Listening to music when working to drown out everything but what I’m concentrating on has long been the way I’ve done things, and sound quality is important to me.
When I’ve had housemates, I always used my Sennheiser HD 650 Open Back headphones along with an RME Babyface Pro for custom wave tuning. To perfectly tune the waveforms so it sounded the best to me, I spent many hours listening to the same sound clips over and over, ones that I’d already heard thousands of times before and knew impeccably.
Now that I’ve had my house to myself for a while, I always listen to everything through surround sound (I have my house wired for 7.1 in my office, living room, and bedroom). While the sound quality is a pretty big step down, I really enjoy being immersed in the music, coming in from all directions. Any headphones I’ve tried just can’t simulate that experience.
I generally just listen to stereo tracks that are upmixed (upmuxed?) to 7.1, which gives me what I want. Actual surround sound music tracks are rare, and it’s even more rare that they are actually good.
In 1996 there were 5 Eva (Neon Genesis Evangelion) OST CDs released, and in December of 2004 they were rereleased with 5.1 surround editions. I have acquired copies of the first 3 of these CDs and the surround mixes are phenomenal. I’ve been saddened by the fact I don’t have the 5th CD (I’ve found a physical copy online I intend to grab soon) as it contains one of my favorite Eva songs, “Komm, süsser Tod”.
It recently came to my attention that there was a “Neon Genesis Evangelion 5.1ch Surround Edition Soundtrack” released in 2015 that has that song and I finally acquired it today. Unfortunately, the surround remix on this CD is horrible and I deleted it after listening all the way through. Very disappointing.
Another fun tidbit. I’ve lost a good deal of my hearing ranges from playing percussion in instrumental band in high school. I recently went to an audiologist and tried out hearing aids and HOLY CRAP, everything in life suddenly sounds so much better and crisper. The Oticon Intent hearing aids are absolutely amazing. The best versions (#1) definitely give the best quality. The lowest tier version (#3) didn’t cut it for me. I’m probably going to settle with the mid-tier version (#2) due to price vs quality loss.
Using these hearing aids is a huge step for me in bridging the gap to listening to music out loud and through my Sennheisers. And what really surprised me was that using the hearing aids actually enhanced the sound quality when listening through my Sennheisers.
To adjust the hearing aids to my needs I went through a 10-ish minute test in a sound booth in which all the ranges of my hearing were testing, so the hearing aids could boost the different ranges to match my hearing loss. What really made me smile was when I compared the hearing range loss chart with the waveform I came up with for my Babyface. They were almost exactly matched. Which tells me I haven’t lost much more hearing in the last decade. |
I wanted to make a script to check if updated flatpak app permissions have changed before updating them. I decided to use ChatGPTs newest model, 01-preview for this task and holy crap am I impressed. I had to give it 14 commands to get to the final product and it seems to work great. That number could have been reduced quite a bit had I done things a bit differently.
I still had to find the problems, look up reference docs to correct it, and even debug in an IDE a little. But just telling it where the problems were, it got there in the end, and its user interaction output is way better than what I was planning on doing.
Sections:
My final updated copy of the script
<?php
// -- This script checks for Flatpak updates and reports permission changes. --
// Function to parse permissions from Flatpak metadata
function parsePermissions($content) {
$permissions = [];
$lines = is_array($content) ? $content : explode("\n", $content);
$currentSection = '';
$skipSections = ['Application']; // Sections to skip
foreach ($lines as $line) {
$line = trim($line);
if (empty($line)) {
continue;
}
// Check for section headers
if (preg_match('/^\[(.*)\]$/', $line, $matches)) {
$currentSection = $matches[1];
// Skip the [Application] section
if (in_array($currentSection, $skipSections)) {
$currentSection = '';
continue;
}
$permissions[$currentSection] = [];
} elseif ($currentSection !== '') {
// Only process lines within non-skipped sections
$parts = explode('=', $line, 2);
if (count($parts) == 2) {
$key = $parts[0];
$values = explode(';', trim($parts[1], ';'));
$permissions[$currentSection][$key] = $values;
} else {
// Handle keys without '=' (e.g., single permissions)
$permissions[$currentSection][$line] = [];
}
}
}
return $permissions;
}
// Function to compare permissions
function comparePermissions($current, $new) {
$differences = [];
// Get all sections
$sections = array_unique(array_merge(array_keys($current), array_keys($new)));
foreach ($sections as $section) {
$currentSection = isset($current[$section]) ? $current[$section] : [];
$newSection = isset($new[$section]) ? $new[$section] : [];
// Get all keys in this section
$keys = array_unique(array_merge(array_keys($currentSection), array_keys($newSection)));
foreach ($keys as $key) {
$currentValues = isset($currentSection[$key]) ? $currentSection[$key] : [];
$newValues = isset($newSection[$key]) ? $newSection[$key] : [];
// Compare values
$added = array_diff($newValues, $currentValues);
$removed = array_diff($currentValues, $newValues);
if (!empty($added) || !empty($removed)) {
$differences[$section][$key] = [
'added' => $added,
'removed' => $removed,
];
}
}
}
return $differences;
}
// Function to output a line with appId (if given), colored red (IsError=true) or green (IsError=false)
function outputColor($appId, $str, $isError=true, $NoNewline=false)
{
// Determine if coloring should be used
static $hasColors=null;
if(!isset($hasColors)) {
$hasColors=stream_isatty(STDOUT) && (!trim(`command -v tput`) || intval(`tput colors`)>=16);
}
echo
(!$hasColors ? '' : ($isError ? "\e[31m" : "\e[32m")).
($appId ? "$appId: " : '').
$str.
(!$hasColors ? '' : "\e[0m").
($NoNewline ? '' : "\n");
}
// Function to display permission differences
function displayDifferences($appId, $differences) {
outputColor($appId, 'Permission changes:');
foreach ($differences as $section => $keys) {
outputColor(null, " [$section]");
foreach ($keys as $key => $changes) {
if (!empty($changes['added'])) {
outputColor(null, " + $key = " . implode(';', $changes['added']));
}
if (!empty($changes['removed'])) {
outputColor(null, " - $key = " . implode(';', $changes['removed']));
}
}
}
echo "\n";
}
// Function to ask the user a question
function askQuestion($Question) {
outputColor('', "$Question (y/N): ", true, true);
$handle = fopen('php://stdin', 'r');
$line = fgets($handle);
$answer = trim(strtolower($line));
fclose($handle);
return ($answer == 'y' || $answer == 'yes');
}
// Get architecture (moved above the loop)
$archCommand = 'flatpak --default-arch';
exec($archCommand, $archOutput);
$arch = trim(implode('', $archOutput));
// Step 1: Get the list of installed Flatpaks
$installedCommand = 'flatpak list -a --columns=application,branch,origin,options';
exec($installedCommand, $installedOutput);
// Remove header line if present
if (!empty($installedOutput) && strpos($installedOutput[0], 'Application ID') !== false) {
array_shift($installedOutput);
}
// Build an associative array of installed applications
$installedApps = [];
foreach ($installedOutput as $line) {
// The output is tab-delimited
$columns = explode("\t", trim($line));
if (count($columns) >= 4) {
$appId = $columns[0];
$branch = $columns[1];
$origin = $columns[2];
$options = $columns[3];
$installedApps[$appId] = [
'appId' => $appId,
'branch' => $branch,
'origin' => $origin,
'options' => $options,
];
}
}
// Get the list of updates
exec('echo n | flatpak update', $updatesOutput);
foreach ($updatesOutput as $Line) {
if (preg_match('/^ *\d+\.\s+([\w\.-]+)/', $Line, $matches)) {
$updatesAvailable[]=$matches[1];
}
}
// Let the user confirm the updates
echo str_repeat('-', 80)."\n";
echo implode("\n", $updatesOutput)."\n";
echo str_repeat('-', 80)."\n";
if (empty($updatesAvailable)) {
outputColor('', 'No updates available for installed Flatpaks.');
exit(0);
}
if (!askQuestion('Found '.count($updatesAvailable).' updates. Continue?')) {
echo "Updates canceled.\n";
exit(0);
}
$permissionChanges = [];
foreach ($updatesAvailable as $appId) {
if (!isset($installedApps[$appId])) {
outputColor($appId, 'Installed app not found. Skipping.');
continue;
}
$app = $installedApps[$appId];
$branch = $app['branch'];
$origin = $app['origin'];
$options = $app['options'];
// Determine if it's an app or runtime
$isRuntime = strpos($options, 'runtime') !== false;
// Paths to the metadata files
if ($isRuntime) {
$metadataPath = "/var/lib/flatpak/runtime/$appId/$arch/$branch/active/metadata";
} else {
$metadataPath = "/var/lib/flatpak/app/$appId/$arch/$branch/active/metadata";
}
// Check if the metadata file exists
if (!file_exists($metadataPath)) {
outputColor($appId, 'Metadata file not found. Skipping.');
continue;
}
// Read current permissions from the metadata file
$metadataContent = file_get_contents($metadataPath);
$currentPermissions = parsePermissions($metadataContent);
// Get new metadata from remote
$ref = $appId . '/' . $arch . '/' . $branch;
$remoteInfoCommand = 'flatpak remote-info --show-metadata ' . escapeshellarg($origin) . ' ' . escapeshellarg($ref);
// Clear $remoteOutput before exec()
$remoteOutput = [];
exec($remoteInfoCommand, $remoteOutput);
if (empty($remoteOutput)) {
outputColor($appId, 'Failed to retrieve remote metadata. Skipping.');
continue;
}
// Parse new permissions from the remote metadata
$newPermissions = parsePermissions($remoteOutput);
// Compare permissions
$differences = comparePermissions($currentPermissions, $newPermissions);
if (!empty($differences)) {
$permissionChanges[$appId] = $differences;
displayDifferences($appId, $differences);
} else {
outputColor($appId, 'No permission changes found.', false);
}
}
// If there are no permission changes, inform the user
if (empty($permissionChanges)) {
echo "No permission changes detected in the available updates.\n";
}
// Ask user if they want to proceed
if (askQuestion('Do you want to proceed with the updates?')) {
// Proceed with updates
echo "Updating Flatpaks...\n";
passthru('flatpak update -y');
} else {
echo "Updates canceled.\n";
}
?>
List of the changes I made from the AI produced script
- Added “outputColor” function and wrapped appropriate echo statements into it
- Added “-a” to “flatpak list”
- Added output line “Installed app not found. Skipping”
- Added output line “No permission changes found.”
- Added “askQuestion” function since there are now multiple places in the script that ask questions
- Changed get-updates command from “flatpak remote-ls --updates” to “echo n | flatpak update” (with a regex extraction). Also now confirms the update list with the user.
The commands I gave the AI
For demonstration purposes, I have left all of my original typos uncorrected below.
Write me a program in php that checks if there are any updates for my installed flatpaks. and then for each flatpak check and see if the permissions have changed between my current version and the new version. report to me the changes. then ask me if i want to continue with the updates.
your code doesnt work.
first $command = 'flatpak list --app --updates --columns=application,app,branch,origin,installation'; should be flatpak remote-ls --updates --columns=application,app,branch,origin (installation is an invalid column)
and then flatpak info --show-permissions doesnt give the original permissions. you have to get the original non-user-modified permissions from /var/lib/flatpak
the line if (empty($output)) { is incorrect, it should be if (count($output)) { as $output is an array, not a string
$columns = preg_split('/\s{2,}/', trim($line)); is incorrect. its tab delimited, so it just needs to be explode("\t", trim($line));
you also have a problem with the $metadataPath. its not always in /var/lib/flatpak/app/ . It may be in /var/lib/flatpak/runtime/. You can confirm which directory it should be in with the options column having "runtime" as an option.
in the --columns for your first command, "application" should be "name"
actually, you cant get the options from flatpak remote-ls --updates . you have to get the options from flatpak list
flatpak remote-info does not have an option --show-permissions
in your flatpak remote-info command, there is no --branch option.
there is no --assumeno option
there is no --dry-run permission. perhaps use --no-deploy?
you are incorrect. flatpak remote-info does not have an option --show-permissions . we already went over that. perhaps flatpak remote-info --show-metadata to get the permissions
flatpak remote-info does not have --branch
when checking the metadata, do not compare the info under [Application]
also, move the "Get architecture" line above its for loop
you have a problem with exec($remoteInfoCommand, $remoteOutput); you need to always empty $remoteOutput before running the exec. Otherwise, it appends the data to what is already there.
The final script the AI produced
<?php
/**
* This script checks for Flatpak updates and reports permission changes.
*/
// Function to parse permissions from Flatpak metadata
function parsePermissions($content) {
$permissions = [];
$lines = is_array($content) ? $content : explode("\n", $content);
$currentSection = '';
$skipSections = ['Application']; // Sections to skip
foreach ($lines as $line) {
$line = trim($line);
if (empty($line)) {
continue;
}
// Check for section headers
if (preg_match('/^\[(.*)\]$/', $line, $matches)) {
$currentSection = $matches[1];
// Skip the [Application] section
if (in_array($currentSection, $skipSections)) {
$currentSection = '';
continue;
}
$permissions[$currentSection] = [];
} elseif ($currentSection !== '') {
// Only process lines within non-skipped sections
$parts = explode('=', $line, 2);
if (count($parts) == 2) {
$key = $parts[0];
$values = explode(';', trim($parts[1], ';'));
$permissions[$currentSection][$key] = $values;
} else {
// Handle keys without '=' (e.g., single permissions)
$permissions[$currentSection][$line] = [];
}
}
}
return $permissions;
}
// Function to compare permissions
function comparePermissions($current, $new) {
$differences = [];
// Get all sections
$sections = array_unique(array_merge(array_keys($current), array_keys($new)));
foreach ($sections as $section) {
$currentSection = isset($current[$section]) ? $current[$section] : [];
$newSection = isset($new[$section]) ? $new[$section] : [];
// Get all keys in this section
$keys = array_unique(array_merge(array_keys($currentSection), array_keys($newSection)));
foreach ($keys as $key) {
$currentValues = isset($currentSection[$key]) ? $currentSection[$key] : [];
$newValues = isset($newSection[$key]) ? $newSection[$key] : [];
// Compare values
$added = array_diff($newValues, $currentValues);
$removed = array_diff($currentValues, $newValues);
if (!empty($added) || !empty($removed)) {
$differences[$section][$key] = [
'added' => $added,
'removed' => $removed,
];
}
}
}
return $differences;
}
// Function to display permission differences
function displayDifferences($appId, $differences) {
echo "Permission changes for $appId:\n";
foreach ($differences as $section => $keys) {
echo " [$section]\n";
foreach ($keys as $key => $changes) {
if (!empty($changes['added'])) {
echo " + $key = " . implode(';', $changes['added']) . "\n";
}
if (!empty($changes['removed'])) {
echo " - $key = " . implode(';', $changes['removed']) . "\n";
}
}
}
echo "\n";
}
// Get architecture (moved above the loop)
$archCommand = 'flatpak --default-arch';
exec($archCommand, $archOutput);
$arch = trim(implode('', $archOutput));
// Step 1: Get the list of installed Flatpaks
$installedCommand = 'flatpak list --columns=application,branch,origin,options';
exec($installedCommand, $installedOutput);
// Remove header line if present
if (!empty($installedOutput) && strpos($installedOutput[0], 'Application ID') !== false) {
array_shift($installedOutput);
}
// Build an associative array of installed applications
$installedApps = [];
foreach ($installedOutput as $line) {
// The output is tab-delimited
$columns = explode("\t", trim($line));
if (count($columns) >= 4) {
$appId = $columns[0];
$branch = $columns[1];
$origin = $columns[2];
$options = $columns[3];
$installedApps[$appId] = [
'appId' => $appId,
'branch' => $branch,
'origin' => $origin,
'options' => $options,
];
}
}
// Get the list of available updates
$updatesCommand = 'flatpak remote-ls --updates --columns=application';
exec($updatesCommand, $updatesOutput);
// Remove header line if present
if (!empty($updatesOutput) && strpos($updatesOutput[0], 'Application ID') !== false) {
array_shift($updatesOutput);
}
// Build a list of applications that have updates
$updatesAvailable = array_map('trim', $updatesOutput);
if (empty($updatesAvailable)) {
echo "No updates available for installed Flatpaks.\n";
exit(0);
}
$permissionChanges = [];
foreach ($updatesAvailable as $appId) {
if (!isset($installedApps[$appId])) {
// The updated app is not in the installed apps list, skip it
continue;
}
$app = $installedApps[$appId];
$branch = $app['branch'];
$origin = $app['origin'];
$options = $app['options'];
// Determine if it's an app or runtime
$isRuntime = strpos($options, 'runtime') !== false;
// Paths to the metadata files
if ($isRuntime) {
$metadataPath = "/var/lib/flatpak/runtime/$appId/$arch/$branch/active/metadata";
} else {
$metadataPath = "/var/lib/flatpak/app/$appId/$arch/$branch/active/metadata";
}
// Check if the metadata file exists
if (!file_exists($metadataPath)) {
echo "Metadata file not found for $appId. Skipping.\n";
continue;
}
// Read current permissions from the metadata file
$metadataContent = file_get_contents($metadataPath);
$currentPermissions = parsePermissions($metadataContent);
// Get new metadata from remote
$ref = $appId . '/' . $arch . '/' . $branch;
$remoteInfoCommand = 'flatpak remote-info --show-metadata ' . escapeshellarg($origin) . ' ' . escapeshellarg($ref);
// Clear $remoteOutput before exec()
$remoteOutput = [];
exec($remoteInfoCommand, $remoteOutput);
if (empty($remoteOutput)) {
echo "Failed to retrieve remote metadata for $appId. Skipping.\n";
continue;
}
// Parse new permissions from the remote metadata
$newPermissions = parsePermissions($remoteOutput);
// Compare permissions
$differences = comparePermissions($currentPermissions, $newPermissions);
if (!empty($differences)) {
$permissionChanges[$appId] = $differences;
displayDifferences($appId, $differences);
}
}
// If there are no permission changes, inform the user
if (empty($permissionChanges)) {
echo "No permission changes detected in the available updates.\n";
}
// Ask user if they want to proceed
echo "Do you want to proceed with the updates? (y/N): ";
$handle = fopen("php://stdin", "r");
$line = fgets($handle);
$answer = trim(strtolower($line));
if ($answer == 'y' || $answer == 'yes') {
// Proceed with updates
echo "Updating Flatpaks...\n";
passthru('flatpak update -y');
} else {
echo "Updates canceled.\n";
}
fclose($handle);
?>
| One of the main selling points for me for the Android platform was that, as I understood it, the system was supposed to be very “open” in nature. It would allow a programmer to create virtually any application imaginable that they wanted to for users, as long as the user’s security is maintained. This is, of course, the antithesis of Apple’s philosophy with the iPhone/iPod Touch. However, I find this much spouted openness to not be the case at all. Security permissions are way too tight across the board, especially regarding interfacing with the hardware, making many things next to impossible to accomplish. This is especially true when interfacing with the phone functionality. While a programmer is free to do what they want within the scope of their own application(s) and their GUIs, working with the rest of the system can be a major PITA, or even impossible.
Some of this functionality can be gained back with rooted (jail broken) phones, but it is not always easy (or completely safe) to get one’s phone to such a state. It was simple with the Android 2.0 platform, which I originally had on my Motorola Droid, but not so much with the v2.1 software. Version 2.1 is (currently) a major PITA to root, as it entails having to restore the phone to its original state first, losing everything on it (which can, of course, be restored manually). I also, at this point, do not consider it worth it putting in the time to build things for rooted-only phones as the market is much smaller, and I myself haven’t even bothered rooting my phone on the current Android version.
Anyone can also compile their own version of the Android platform as it is open source. This would be worth it, for example, if an organization wanted to distribute their own compilation with modifications internally. However, it doesn’t much help application programmers like myself that want to reach a wide audience. I am also under the impression that putting your own flavor of the Android platform on your phone would lose certain functionalities/things included by the image provided by the provider of the phone (usually cell phone network carriers).
I really like how they did one section of the security system, which is, allowing an application to request special permissions from the operating system. A user is informed of the requested permissions before they install an application from the market place. The main problem is, though, that so many permissions are unavailable that should be possible. Another major downside is that way too many applications request permissions that they shouldn’t be requesting. This leaves users high and dry with applications they consider critical only available if they accept things they don’t want to. For example, many programs request full internet access with no need for it. It would be great to be able to selectively turn off these permissions, but I doubt the option for this is going to happen. I’m going to do more research myself on if an application can be written to do this, but I am not going to get even the slightest hope up on this possibility.
There are even examples of listed permissions that cannot be accessed by user submitted applications! For example, the INJECT_EVENTS permission can only be used by applications signed with the same signature as the system. I was unable to find this tidbit of information anywhere in the Android documentation and references (or the Internet). This all goes back to the problem of the documentation being less than optimal, as it leaves out a lot of important information.
There are at least 3 applications ATM I wanted to create but could not due to permissions:
- Call recording: I have written on this previously, but this functionality is unavailable, and Google is not commenting as to why. There are also countless other applications that could use the ability to access a call’s audio. This functionality was available on some older versions of the Android platform (and there are applications out there that take advantage of this), but it seems unavailable on newer versions for 1 of 3 reasons:
- Legal reasons: It’s illegal to record calls in some areas (which would be dumb to revoke accessing call audio because of this because it’s legal in so many other places, including where I live in Texas).
- Technological reasons: Some phone manufacturers might have it so the audio never even makes it to the operating system (it’s kept on the phone’s radio stack).
- Google reasons: They decided it was a feature they no longer wanted to support. The fact of the matter is the interface is provided by the platform to do this, but bugs have been introduced into it and it no longer seems to work.
- Automated call menu: I would love to make an application that created an automated call menu on the phone, which could include leaving messages. I would personally use this so I could keep my phone on when sleeping, allowing the phone to direct the caller to either my [local or remote] voice mail or to wake me up if it’s an emergency. This is not possible due to the inability to access a call’s audio, as is explained in the above unimplementable application, but I am betting that there would be many more permissions that would make this not possible.
- Global Key interception: I have somewhat solved this problem, as I will be explaining in a post most likely coming tomorrow.
| I finally gave in and got myself a Motorola Droid phone, as I’ve been meaning to do for quite some time, but was reluctant to do so due to some known problems with it. I have been incredibly happy with it, and find it leaps and bounds better than the iPhone platform (and many other smart phones).
Pros (when compared to other phones/platforms on the market):
- It’s on the Verizon network, which, from my experience, has by far the best coverage and quality
- The Android platform keeps things running in the background so you can go in and out of applications freely, as opposed to only being able to run 1 application at a time on the iPhone. This multitasking approach is much better because...
- This means that applications can continue to run/process in the background for necessary tasks, like periodically talking and receiving data from servers (without push notifications, which aren’t as powerful)
- Applications, since they remain open, take no extra time to start back up every time you want to go to them
- Keeping applications open has (as I understand it) next to zero, if not zero, drain on system resources if they are not doing anything in the background
- If the phone is running out of memory, it will kill an application that is not in use
- I find the touchscreen much more responsive and accurate than the iPhone
- The voice recognition is spectacular (especially useful when combined with GPS/mapping programs)
- It’s not Apple :-) (and it’s Google!)
- It has a physical qwerty keyboard (see Cons)
- The lock screen protection is pretty neat and quick (gesture-like unlocking)
- The platform is open source, which has many powerful advantages for programmers
- Music/books/etc are directly loaded from an SD Card with no need to go through something like iTunes. This can, however, be slow when indexing from the SD card after changes
- Music sorts first by folder and then by album. While this would have been great for me a year or so ago when I got my iTouch, it no longer is as useful as I have already gone through my whole music folder and properly re-tagged everything (and it has actually caused a few bugs in my music organization)
- Free tethering to a computer through PDANet (1 month trial that blocks HTTPS sites afterwards, but I SSL tunnel my connections anyways :-) ). [Edit on 5/25/2010]: Google has just announced Android 2.2 has a new added feature “a portable Wi-Fi hotspot that can be shared with up to 8 devices.”
- Great [5.0 megapixel] camera/video recorder
- Applications can use self signed certificates for distribution. Signed applications prevent tampering (which has both advantages and disadvantages :-) ), and self signing means you can develop for the platform for free
Cons:
- It cannot be on the Internet and a phone call at the same time (Verizon [CDMA] problem). This is especially problematic when tethering
- Even though the system is Linux based, working with the terminal emulator leaves a lot to be desired
- Most of my standard bash commands [coreutils] are not there
- Permissions are so tight you can barely do anything without rooting
- The shell itself is missing a lot of functionality (problems with finding files even though they are in the “path”, bash-type arrow shortcuts [autofill, history], etc)
- Motorola has seemingly [possibly?] even removed some of the utilities that should have come with the Android platform (they are on the Android emulator at least) like the command line SQLite program
- The physical keyboard is a lot harder to use than my last phone (VX9800, I’ve been using one since 2004), and also leaves a lot to be desired. It’s better than having no keyboard though!
- Since there is no spacing between the keys, it is very easy to make a mistake
- The number of keys is very small and not always in typical qwerty layout (for numbers and symbols), so it’s hard to find some characters
- Some characters (like the pipe | ) are not even listed, and you just have to know how to get to them (alt+shift+comma for the pipe)
- The phone does not let you record call conversations. This seems to be a hardware issue specific to the Droid (and possibly the Nexus One) and not necessarily because of the Android platform. I cannot find any official or confirmable information on the reason. [Edited this bullet on 3/1/2010]
- It’s made to interface with Java when programming, and you don’t have much of a choice with this :-( . However, C/C++ modules can be made that directly interface easily with the Java base.
Anywho, the original intent of this post was not to talk about the Droid itself, but I figured I might as well get that out of the way while I was on the topic :-). The real point was to talk about a problem I ran into and the solution.
I had a lot of trouble finding a way to quickly set a ringtone to many people. As I have many hundreds of contacts in my phone, and I need groups of people set to different ringtones (and sometimes just one individual), it would have taken many hours to accomplish the task of assigning ringtones to these contacts. I found the perfect solution though in an application, not on the market, called JUSTones (also called “Just Tones”). Not only does it allow you to set ringtones for many people at once, but it also lets you set SMS tones for contacts (Yay!), which is not native to the platform.
Unfortunately, it was made for a depreciated version of the Android platform, and did not work on my phone. I have been in communication with the author, and after sending him the solution to my main problem, he has sent me a new working version (with many more fixes for bugs I mentioned too) ^_^. He even refunded my original purchase and told me to not worry about paying for it, which was pretty cool of him. It’s nice to find other software authors as nice and willing to work with you as this :-).
The problem was that the ringtones being set through the program were not actually being set to the contacts. The reason was that ringtone values are now set in 2 separate places in the OS, and only 1 of them was actually being used. I presume the old location of the value was still being set so legacy applications could still read the ringtone for the contact, but not necessarily set it.
The following is the code I sent to him that copies over the values from the old value location to the new one.
//Prepare to read from the old contacts database
Cursor cur=managedQuery(People.CONTENT_URI, new String[] { People.NAME, People.CUSTOM_RINGTONE }, null, null, People.NAME + " ASC"); //Query the old contacts database
cur.moveToFirst(); //Move to the first record of the old contacts database
//Prepare queries to run on new contacts database
ArrayList<ContentProviderOperation> ops = new ArrayList(); //This holds the queries to run
do //Loop over each [old] record of the database
{
String TheName=String.valueOf(cur.getString(cur.getColumnIndex(People.NAME))); //Get the name from the old record
String TheRingtone=cur.getString(cur.getColumnIndex(People.CUSTOM_RINGTONE)); //Get the ringtone from the old record
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Contacts.CONTENT_URI) //Prepare a query on the new contacts database
.withSelection(ContactsContract.Contacts.DISPLAY_NAME + "=?", new String[]{TheName}) //On any record where the Name = OLD_NAME
.withValue(ContactsContract.Contacts.CUSTOM_RINGTONE, TheRingtone) //Set Ringtone = OLD_RINGTONE
.build());
} while (cur.moveToNext());
//Execute the queries on the new contacts database
try
{
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch(Exception e) { }
| To start off, Merry XMas ya’ll! (And Happy Holidays, of course! [I’m actually Jewish by heritage for those who don’t know me personally ^_^; ] )
I decided to get an eBook reader as a present for someone for the holidays, so I tried out both the Sony PRS-505 and Sony PRS-700. I decided on the Sony readers for now as they can handle most, if not all, of the main eBook formats. Here are the important things I discovered out about both.
Sony PRS-505
This is a minor upgrade to the first eBook reader that Sony released in September of 2006 (the PRS-500), and costs $300. It works as it should and is advertised, and does everything I’d really want from a basic eBook reader.
Sony PRS-700
This is a major update to Sony’s eBook line, released in September of 2008, and costs $400. The most important new feature to this is the touch screen, which has some major pros and cons.
The main comparison points that I found between the 505 and 700 are as follows.
- I immediately noticed upon comparing the two how much lighter and more reflective the screen is on the 700, making it much harder to read. After some quick research, I found the following here:
Sony added a touch layer on top of the e-ink display and embedded LED side-lights into the frame that surrounds the display. Clever. But this comes at the expense of contrast and glare, and the Sony Reader PRS-700 looks more like a grayscale notebook screen than an eBook reader. The glare isn’t nearly as bad as the average PDA or gloss notebook display-- it’s on par with matte finish notebook displays.
As far as I’m concerned, very unfortunately, this makes the product completely worthless as far as an eBook reader. You might as well just use an LCD display instead of an eInk display for the quality and price!
- The touch screen (that comes with a pointer pen too) itself is a spectacular design, and would make the device far better than the 505 if it didn’t ruin the readability of the device. The ability to navigate the device is much easier, quicker, and more intuitive due to the touch screen interface, which also allows for a lot of additional functionality including a virtual keyboard and selecting text.
- The 700 “turns pages” about twice as fast, due to the processor being about twice as powerful.
- The 700 also has many more zoom levels by default, which is a big plus for people who need the eBook devices specifically for bad eyesight. The “Large” zoom level on the 500 just doesn’t always satisfy what is needed in some eBooks, but the XL and XXL on the 700 definitely go that extra step. I was told by a rep at the Sony Style store that there is a way to download larger fonts to the system (possibly through the eBook files themselves), but I have not fully researched into this yet.
- The 700 allows for searching for text now because of the virtual keyboard. I find this to be an incredibly useful feature for a book reader.
- The 700 also allows you to takes notes and make annotations on pages due to the virtual keyboard.
- The 700 has side lights that can be turned on, which is kind of neat, but this is really just an extra luxury.
One unfortunate annoyance of both devices is that you cannot use them while they are plugged into the computer (for charging via the USB interface or uploading new books).
After playing with both, I’d definitely recommend the 505 for now. If they could fix the contrast problem with the 700, it would be perfect and well worth the price.
I’d like to try the Amazon Kindle too, but their stock of it is so far backordered, I don’t feel like dealing with it for the time being. When I checked around the 23rd of this month, they had a 13 week wait to have the product shipped to you! The Kindle is also, unfortunately, more DRM laden with proprietary formats. This can be bypassed though. | So I decided to go over to the evil side recently and get an IPod Touch. I originally wanted to just try it out in The Apple Store, but I just couldn’t find out all I wanted to about it there, and was getting highly annoyed by the completely ignorant sale reps, who couldn’t answer any of my questions anyways, hovering over my shoulder. And, yes, I asked them a few questions and neither they nor their managers had a clue. >:-(
However, all the sales reps I’ve been talking to lately at different stores about the IPod Touch and other electronic products I’ve been interested in buying have been pushing me to just buy them, and return them if I’m not satisfied. This sales tactic is a bit new to me, and I don’t like buying something and returning it needlessly, but they suggest it, so I decided what the heck! I guess it’s assumed most people will buy it and either decide they like it, forget to return it, or are too lazy to return it! So I decided to go to Fry’s to grab one (IPod Touch 2G v2.2) for testing and possibly keeping if I liked it because The Apple Store were really uncool about a lot of things, and also charged a hefty restocking fee on return... jerks. The jury is still out on if I’ll be keeping it or not, but I decided to share some of my findings.
When I talk about the IPod Touch here, I am also talking about the IPhone, because they are basically the exact same product. The IPhone just has the camera and the phone features, but the rest of the software is all the same (they run on the same OS). I also have a few IPhone specific comments below, as a good friend of mine got one for XMas and I helped him out with setting it up and found out a few things about it at the same time. Whenever I refer to the IPod Touch from here on out, I am referring to both IPod Touches and IPhones.
First of all, as is advertised and highly touted, The IPod Touch has style. The design is wonderful, it has a lot of nifty features, and has lots of useful applications in the App Store, many of them free. The product itself is by far better than anything else I’ve tried on the market for music playing and general PDA (personal digital assistant) purposes.
The Blackberrys I’ve tried out at a Verizon store (the Storm and Curve IIRC) weren’t even in the same league as the IPod Touch. I also tried out a G1 (Google phone) at a TMobile store, and initial impressions were not spectacular. However, I can’t make a solid judgment on the G1 because I didn’t spend as much time with it as I could have, as I knew I couldn’t use it anyways. This is because I refuse to switch from the Verizon network because the signal quality and customer support I have received from them are worlds better than what I had ever received from Cingular (now AT&T), AT&T, and Sprint.
Now that I’ve gotten the initial information out of the way including why the IPod Touch is nice; on to all of the problems I’ve found with it.
- Apple has horrible draconian policies regarding what can be put on an IPod Touch. Applications can only (legally) be put on the IPod Touch from the App Store, and Apple specifically regulates what is in the store, only allowing in it what is “best for their interests”. This, of course, includes denying any application in the App Store that “duplicates functionality” of an Apple product. This is bad for many reasons.
- First and foremost, it’s not Apple’s place (though they argue that it is) to say who can develop and what can be developed for the IPod Touch, as long as it is not malicious in any way.
- Apply very specifically blocks, quite often, products that would be excellent with great functionality because it “competes” with their generally inferior applications. Of course, one can unlock older IPod Touches, and I’m sure newer ones will be unlockable soon enough, so this problem can be bypassed. When a phone is unlocked, it can be theoretically used on a compatible network (not AT&T), and you can install any application you want to on it for free (as long as you can find it). The legality of this is questionable, but it’s not really risky.
- This can force developers who have spent their time and effort to build a good product to not be accessible to the market, thereby completely screwing them after the fact. Apple is not specific on what can be put on the store, and is very subjective about the whole matter. Unfortunately, many developers have found themselves in this position after submitting their application to Apple for inclusion in the store.
- Apple can decide to block a product after it has been released and people have bought it, deleting it from their phones without refund. I believe (but have no proof) that this has already happened when a product “duplicated the functionality” of a new application or feature in an application of theirs that was added after the fact.
- The SMS (texting) interface on the IPhone is horrible. It only allows you to see part of the message that you are typing at any time (40 characters as a hazy guess). This could easily be fixed through a third party application, but Apple blocks any application that has SMS as it is “duplicating” the functionality of something they built. See the above bullet for more information.
- The keyboard correction on the IPod touches leaves much to be desired, and there is no text prediction (suggesting words you are typing).
- The virtual keyboard itself, while far ahead of any other virtual keyboard on a cell phone I have tried as far as usability goes, also leaves a lot to be desired, and can be quite annoying. I did get used to it pretty fast, but mistakes were very often and easily made, and I do not believe one could ever type as fast on a virtual keyboard, like the IPod Touch’s, as a physical keyboard, though I haven’t spent near enough time practicing on it to confirm this. The Google phones (at least the G1) solves this problem with its flip-out keyboard interface.
- No multitasking. Period. The IPod Touch can do a few things at the same time (mainly play music), but 2 applications cannot run at the same time, and trying is against their developer agreement. Apple did this to control the user experience, so that a user doesn’t try running too many things at once, creating a bad user experience on the product from lag, which they would blame on Apple. Granted, the IPod Touch isn’t that powerful and it would be easy to bog down the system if too many things were running, but some things need to continue running in the background, with minimal processor time, to create a good experience.
One of many examples of this is AIM (AOL Instant Messenger). When you start the application, it signs you on, and it keeps you online AIM until you specifically sign off (or perhaps if you turn off the phone, but I doubt it). This means that if you exit the AIM application after signing on, it shows other people that you are still online and receiving messages, even if you aren’t getting them. When you open the application back up, it retrieves all of the queued messages that were sent to you while the application was not opened. How hard and taxing would it be on the system to pop up a message informing the user a new message has come in while they are in other applications? Apparently too much, as Apple has to be black and white about the multitasking issue instead of allowing developers to petition for the right. Further, this queued AIM message system also tips one off to the fact that ALL AIM messages are sent through their servers to get to your IPod Touch, instead of your system directly connecting to the AIM servers, which is essentially an invasion on your private conversations.
- Crashing. The IPod Touch itself has crashed on me twice within the first 2 hours I used it. When this occurred, I could not even start most all of the applications, even after turning the IPod Touch on and off (all the way, not standby mode). The only way I found to fix this was installing a new application from the App Store, or updating an application that had a new version ready. Go figure.
- The IPhone can only take pictures, and not video. While there are products that allow taking video on the IPhone, they can only be installed by unlocking the phone, as Apple will not allow them on the App Store (see the top bullet for more information).
- No searching for text on the current page in the web browser (Safari). This really bugs me as it is an essential feature I need in my web browser :-(.
- I don’t trust installing Apple applications on my computers. I actually ended up using VMWare to use ITunes for this reason >:-(. ITunes likes embedding itself in your system in lots of places it shouldn’t, much like AOL since version 5.0. I do not believe it uninstalls itself completely either if you try. Also, when I tried uninstalling bonjour (an Apple communication protocol, which the program that runs it is also named, It used to be called Rendezvous) it didn’t even TRY to uninstall itself from my system. It just took the program off of a few lists and left all the files there. Even worse, I noticed that Bonjour was hooking a bunch of other processes it shouldn’t have been *sighs*.
- I’ve saved my biggest complaint for last. All music on the IPod Touches (all IPods actually, and Zunes and Zens too) organize music by the MP3’s ID3 tags into genre/album/artist/etc, and do not allow organizing the music in folder based structures. While for most people this is not a problem, it is a big one for me. This is not a problem for people “new” to the MP3 player scene that buy their music straight from the ITunes Store, as that music is already organized for them with proper tags how they want it. My, and many other peoples collections, that have been being built for well over a decade (from CDs myself or friends have ripped ourselves for the most part), are not all tagged very well, as it never mattered. While I could go through my whole directory and tag everything properly, this would take upwards of hundreds of hours to do, and would be a waste of my time. Even so, I feel being able to organize by directory can be easier to navigate and organize then straight up genre/album/artist listings. This is a very basic functionality of all MP3 players I have had up until this point.
- The above problem is actually solvable by playlist folder structures. Unfortunately, these are only available on some of the IPod types (for example, the Classic and Nano, IIRC) but not on IPod Touches or IPhones :-(. Further, building these nested folder playlist structures is also a minor pain. I started writing a script to do it for my music collection until I realized it didn’t work on my IPod Touch. ITunes transfers each folder to the IPod Touch as a flat playlist of all the songs in the playlists under it, but again, this is not a problem on some of the other IPod Systems. Unfortunately, if I was to spend the money on an IPod, I would like it to be a PDA too with much more functionality, which the IPod Touch satisfies, and the others do not.
As previously mentioned, I might not be keeping the IPod Touch, as I cannot justify the cost of it mainly as an MP3 player while I’ve already had other solutions that are almost as good for a number of years. I was one of the first adopters of MP3 players (of the MP3s on CD variety) back in 1998, I believe, and they still work great. However, I would probably get an IPhone were I able to use it on the Verizon network because it combines all the features I like on the IPod Touch with a phone. I would love to be able to use its excellent web browser (as far as cell phone browsers go) anywhere, not just when an accessible WiFi network was handy. The cost of an IPhone is more proportionate to what I’d like to spend since I’d be getting a phone and a music player out of it. Unfortunately, when unlocked, IPhones (and G1s) cannot work on Verizon, like it can the other networks, because Verizon uses a different kind of technology for its carrier signals (CDMA instead of GSM). Alas :-\.
Oh, yes, one more thing I wanted to mention. Apple was originally turning a blind eye to the unlocking IPhone market because most of them were going oversees to markets untapped by Apple, which is good for business for them. However, when Apple started expanding into other countries and this practice no longer served their needs, they added on a section to the AT&T contract you are forced to sign up for when buying the phone. It basically stipulates that if you cancel the AT&T contract (which incurs a fee after the first 30 days anyways) that you have to return the IPhone too. This way Apple is guaranteeing people can’t use the phone outside of AT&T. | I really love my GPS (Magellan Maestro 3100) system that I received last Christmas as a present from my mother. I use it whenever navigating to new places I have never been before and it is always pretty darn accurate.
So it worked as usual without a hitch, calculating the best route flawlessly, on my way to Angel Sword last Saturday. On the way back, however, it sent me back on a different route which ended up making the 50 minutes trip take 10-20 minutes longer due to sticking me on backwater highway roads with only 1 lane, and getting stuck behind old geezers going below the speed limit. This had made me really mad at the time, and rather confused as to why it chose a different "fastest" route back; that is until I got to my destination and found out there was heavy construction on the highway going northbound (my way back) that had delayed one of my friends for 4 hours on his trip into Austin :-O. Glad I ended up following its directions after all and not going with my gut and taking the same route I took down there!
My fatal mistake was assuming the GPS calculated the routes itself instead of asking a central server elsewhere with traffic information. Now I know better! |
|