iTunes DACP pairing hash is broken!

Sunday June 21, 2009 at 2:05 PM

Last year I reverse engineered the iTunes DACP protocol and wrote an Android client that allowed you to remote control your iTunes desktop player from any Android device. (The code is open-sourced here, but I haven’t had the time to update it for quite awhile now.)

You might remember that there was a mysterious MD5 hash floating around the pairing process. Specifically, when you enter a pin code on the desktop iTunes client, it combines that code with the MDNS Pair value and hashes them. It then asks the device “does this match what you expected?” Because I wrote the Android client, I would naïvely always answer “yep, they match.”

Well, yesterday Michael Paul Bailey figured out the mystery behind that MD5 hash. :) I had tried bruteforcing various combinations of the pairing data, but never succeeded. It turns out that it boils down to just concatenating them together with the pin code digits separated by null characters.

He posted the full C++ code over on his blog, and I boiled it down to some spiffy Python here:

import StringIO, md5

pair = "4EA92B4292701F31"
passcode = "8222"
expected = "BEFF520F8280591AC0BBCB83B468FAA5"

merged = StringIO.StringIO()
merged.write(pair)
for c in passcode:
	merged.write(c)
	merged.write("\x00")

found = md5.new(merged.getvalue()).hexdigest()

print "expected =", expected
print "found    =", found.upper()

So what does this mean? Previously, we could write DACP clients easily because they could always return “yep, the MD5 matches” without even checking it. (This is why you could use any 4-digit pin code you wanted.)

Now, with this algorithm, we can do more than just check pin codes–we can write DACP servers that can pair with the original iPhone/iPod Remote app. For example, last year I wrote a DACP server for Amarok, but never got around to releasing it because the pairing process was very ugly. Now I need to find some time to polish and release it. :)

Google I/O Schedule App

Tuesday May 26, 2009 at 8:54 PM

Tomorrow at Google I/O I’ll be presenting some tips on how developers can save battery life when writing Android apps. I’m really stoked about all the stuff going on at I/O this year. :)

Late last week, Virgil Dobjanschi, who you might remember from ADC1, threw out the idea of writing an Android app for Google I/O that would have all the session details. Both of us brainstormed on Friday and came up with a quick design, and hacked through the holiday weekend to get an app working.

We just released the app on Market a few minutes ago, so go check it out! It lets you do all sorts of things, like star sessions you’re interested in, and search across the entire full-text abstracts for all sessions. Plus it includes handy maps to help you find the right rooms, and links directly to Google Moderator for the sessions using it.

The source for the whole app is also available on Google Code, so check that out if you’re looking for a peek behind-the-scenes. Some of the code is still a bit rough, but some good example code. :) So grab the app before you head down to Moscone West tomorrow morning, and have a great couple of days at I/O!

Forecast widget for Android 1.5 (with source!)

Friday April 24, 2009 at 2:07 AM

Over the past few months I’ve been working on the new AppWidget framework that was released as part of the Android 1.5 SDK. I wanted to write a really in-depth widget and share it, so I decided to write a forecast widget.

It offers multiple configurations (both a 2×1 and tiny 1×1), and updates four times daily with the latest forecasts. You can also insert multiple widgets to keep track of the weather in different locations. And tapping the widget brings up a detailed forecast for the next few days. Here are some quick screenshots:

First, here’s the source code under an Apache 2.0 license. And you can grab an APK here.

Now, let’s talk about some of the details. We’re storing widget configuration and cached forecast data in a ContentProvider called ForecastProvider. Pretty simple stuff, and it offers two handy Uri’s to pick all forecasts for a widget using /appwidgets/[id]/forecasts, and only the most-current forecast using /appwidgets/[id]/forecast_at/[time]. These come in handy later when for the update process and details dialog. Also, WebserviceHelper performs most of the backend work of parsing XML returned from the API, and stuffing the forecasts and alerts into the ContentProvider.

As for updates, we maintain our own schedule that wakes us up each day 5:50AM, 11:50AM, 5:50PM, and 11:50PM. These times were mostly chosen to be equally spread out across the day, and to be ready before your 6AM alarm goes off. Notice I said your 6AM alarm, lol. The math also works out if you set your alarm for noon. ;)

Similar to the Wiktionary example, we handle our updates in UpdateService because we’re probably doing API queries that could expose our AppWidgetProvider to the ANR timeout. However, we handle things slightly different because we’re pushing unique updates for each widget. We push updates like this:

UpdateService.requestUpdate(new int[] { mAppWidgetId });
startService(new Intent(this, UpdateService.class));

Which is actually doing a synchronization dance behind the scenes to make sure we only ever have a single thread running updates. Multiple updates are just added to an internal queue. Once the update thread has cleared its work queue, the thread and Service terminate gracefully. This is very similar to how the Calendar widget handles it’s updates. During the update passes, we’re also a good citizen and only update forecasts if the data is more than 3 hours old. (We’re doing our part to keep the boot process spiffy and fast.)

The one final thing to mention is that when we’re building the PendingIntents for when you click on widgets, we’re using the ContentProvider Uri for the data field. This is because PendingIntents don’t keep unique extras bundles, and the details dialog needs a way of telling which widget was selected.

This is a pretty complex example, and it exercises most everything you’ll encounter when writing a widget. Not to mention it actually works and provides useful information! The data comes from the National Weather Service NDFD API, which offers awesome data under a public domain license. And the forecast icons came from the Tango Desktop Project, also under a public domain license.

Modifying the Android logcat stream for full-color debugging

Wednesday April 22, 2009 at 2:01 AM

I’ve been keeping busy writing all sorts of fun stuff lately, but a few weeks ago I was really fighting with Android’s logcat debugging stream.  It dumps out tons of useful information, but it’s easy to get lost in the flood of text.

So I whipped up a quick Python script that reformats the logcat output into a colorful stream that is much easier to visually follow.

One feature I really like is that it allocates unique colors for each “tag” used.  This makes it really easy to visually separate dozens of tags into their source apps, and makes it easy to pick your app out in the crowd.  This was inspired by the irssi nickcolor script, and the best way to explain is using an example:

There, isn’t that better? Just pipe your adb logcat output through the Python script to get started, or you can run the script directly to invoke adb:

$ adb logcat | ~/coloredlogcat.py
$ ~/coloredlogcat.py

To keep things simple, it assumes you’re using an ANSI-compatible terminal (most xterms are fine), and it uses a quick hack to detect your column width for wrapping.

It only took about 30 minutes to write up, but it’s already saved me more than that in lost debugging time.  Feel free to use it yourself, and improve on it–here’s the source code released under an Apache 2.0 license.

OilCan: Greasemonkey on steroids for Android

Monday December 15, 2008 at 12:18 AM

So I’ve been rushing to wrap up some Android side projects, and I’d like to get them out there before I start my new job tomorrow. OilCan is Greasemonkey on steroids for Android. It lets you customize any website by inserting JavaScript to change the website and help it reach into the Android world using intents.

Vimeo is being a bit odd with videos that don’t have sound. Start playing the video, then drag the seek bar slightly to bring it back to normal speed. Or let it play through the video fast and press play again to watch at normal speed.

Using intents to call other Android apps really powerful, and opens the door to all sorts of web-based apps. For example, you can make a JavaScript call to scan a barcode, pick a contact, or launch into Maps or other Android apps. You really have to peek at this video to get an idea of what it does:

There is an OilCan site with more details about the Userscript format and security model. Check out the source dump for OilCan, or grab a ready-to-run OilCan APK.

Greasemonkey scripts are known for customizing websites to your personal tastes, and this can really help when working on a small screen. One of the scripts in the video above trims away extra columns and margins on Wikipedia pages, giving it more screen real estate.

There are thousands of GreaseMonkey scripts, like one that puts favicons into Google Reader, or one that wraps Google search results into two columns.

OilCan is different than the efforts of PhoneGap, which is focusing on providing GPS, vibration, and accelerometer access to webapps.

GroupHome: organize your Android apps into groups

Monday December 15, 2008 at 12:18 AM

So I’ve been rushing to wrap up some Android side projects, and I’d like to get them out there before I start my new job tomorrow.

GroupHome is an app that organizes all the apps you’ve installed on your phone. It automatically groups together apps using the categories shown in Android Market. The “all apps” drawer on my homescreen has become pretty cluttered, and this grouping approach helps you find apps faster.

Oh, and one feature I really like is that you can long-press on an app to uninstall it or view its details.

I wrote GroupHome in about 3 days last week, so it’s still a bit rushed and still rough around the edges. The three remaining things are full-text search, remembering expanded/collapsed groups on close, and moving the static JSON category string to a server.

Check out the source dump for GroupHome, or grab a ready-to-run GroupHome APK.

More CompareEverywhere news coverage

Monday December 15, 2008 at 12:18 AM

I’ve been swamped lately with Android and moving across the country, but was able to give an interview to my hometown ABC affiliate in Duluth, Minnesota over Thanksgiving. It ended up running as the main story for their 10PM news, and was also picked up by the Minneapolis ABC affiliate.

I was lucky enough to have an HDHomeRun networked TV tuner handy to record it in wonderful 720p ATSC:

Seriously, if you’re building a MythTV box, this is the tuner to buy–it has two HDTV/Cable TV tuners and everything runs across normal Ethernet, making it perfect for sticking in the attic right next to your antenna for better SNR margins. And yay, they mentioned that I was homeschooled!

And about a month ago I had the awesome opportunity to be part of an Android Developers interview series while I was visiting Google:

It was a great way to show how CompareEverywhere works, and how it integrates with the Android platform. I was also able to talk about Stateful Drawables and the Hierarchy Viewer, which are both excellent tools for developers.

I’m excited to continue getting the word out there about CompareEverywhere, and more new features are still down the road, like seamless wishlist importing and more.

Leveraging the Android Emulator

Friday October 10, 2008 at 11:05 PM

It sounds like preorders for the T-Mobile G1 have been flying off the shelves even before it’s available in stores. Also, it’s been rumored that the phone will only be sold in 3G areas.

Added together, these facts mean it might be hard for developers to get their hands on devices, especially if the G1 becomes a hot holiday item. Geeks are known for their superhuman ability to stand in line for hours on end, but this might not be enough. :) If you don’t get your hands on a device, it’s important that you leverage the emulator to best reflect an actual G1 experience:

Showing things in actual size on your screen. I’ve seen several apps with touch targets that would be almost impossible to trigger in real life. Bigger targets are always better, and your users will thank you. To give you an idea, the home screen icons are 48px square, and default list items are 64px high. Anything below 48px is going to be pretty hard to for fingers to hit. (Side note: you should be using device independant pixels, or dip, instead of raw pixel values–they will automatically scale to future devices with different DPIs.)

The phone dimensions are 115mm tall by 55mm wide. However, the emulator shows up double that size on my Linux desktop and 24″ monitor. This makes it hard to judge how finger-friendly your interface is. Thankfully the emulator provides a nice switch to solve this:

./emulator -scale 0.5

This makes the emulator 50% of its original size on my desktop, which is about perfect compared to a physical ruler. You might have to play with that value to make it appear right. Remember that the phone screen is much higher DPI (dots-per-inch) than your monitor, so scaling might make things harder to read on the emulator. I find it’s best to develop at the default scale, then launch it scaled down for finger testing.

Getting an actual G1 emulator skin. The default emulator skin is getting very old after almost a year of staring at it. :) About a week ago, T-Mobile released an interesting Flash-based G1 emulator. It’s cute, but you can’t install your apps on it.

So earlier today I created a new emulator skin using the background from that Flash player. Just copy the G1 folder into your tools/lib/images/skins/ folder and launch using the command line below. To flip the keyboard in/out press Numpad 7 or Ctrl+F12. This simple scenery change can really help boost motivation:

./emulator -skin G1

Crossing things off lists in Android 0.9 SDK

Monday September 15, 2008 at 10:18 PM

A few months ago I wrote some code to let you “cross-off” things in a ListView. By wiping your finger left-to-right over an item it will add a strike-through effect to the text, and right-to-left would reverse the effect. Also, we’d like to store the crossed-off status in a backend database.

First, an overview of the problem. The ListView already captures clicks and long-touches for its items, and catches vertical scrolling and flinging to browse through the list. We’re interested in capturing any horizontal events while still letting normal touch events pass through to the ListView. The best way to handle this is by creating a wrapper View that will hold the ListView. Then we can use onInterceptTouchEvent() to watch for our cross-off actions, or otherwise ignore the touch events and let them trickle down to the ListView. (Thanks to Romain Guy for helping me find the correct way to capture these events.) Here’s the core of that capture code:

protected MotionEvent downStart = null;

public boolean onInterceptTouchEvent(MotionEvent event) {

	switch(event.getAction()) {
	case MotionEvent.ACTION_DOWN:
		// keep track of the starting down-event
		downStart = MotionEvent.obtain(event);
		break;
	case MotionEvent.ACTION_MOVE:
		// if moved horizontally more than slop*2, capture the event for ourselves
		float deltaX = event.getX() - downStart.getX();
		if(Math.abs(deltaX) > ViewConfiguration.getTouchSlop() * 2)
			return true;
		break;
	}

	// otherwise let the event slip through to children
	return false;
}

public boolean onTouchEvent(MotionEvent event) {

	// check if we crossed an item
	float targetWidth = this.getWidth() / 4;
	float deltaX = event.getX() - downStart.getX(),
		deltaY = event.getY() - downStart.getY();

	boolean movedAcross = (Math.abs(deltaX) > targetWidth);
	boolean steadyHand = (Math.abs(deltaX / deltaY) > 2);

	if(movedAcross && steadyHand) {
		boolean crossed = (deltaX > 0);

		// figure out which child view we crossed
		ListView list = (ListView)this.findViewById(android.R.id.list);
		int position = list.pointToPosition((int)downStart.getX(), (int)downStart.getY());

		// pass crossed event to any listeners
		for(OnCrossListener listener : listeners) {
			listener.onCross(position, crossed);
		}

		// and return true to consume this event
		return true;
	}

	return false;
}

Using this approach lets us capture these cross-off gestures while still letting the ListView behave normally. I’m using this technique in my CompareEverywhere application, but earlier today I wrote a quick TodoList app to show it in action.

There are two other cool things we’re doing in the process: using a ViewBinder to custom render the created time of each item, and a stateful drawable to handle the checkmarks shown on each item. The ViewBinder correctly sets the strike-through text effect based on the COL_CROSSED database column, and also shows a custom caption with a format similar to “4 hours ago” based on the COL_CREATED column.

public boolean setViewValue(View view, Cursor cursor, int columnIndex) {

	switch(view.getId()) {
	case android.R.id.content:
		// binding to parent container should set the crossed value
		ImageView icon = (ImageView)view.findViewById(android.R.id.icon);
		TextView text1 = (TextView)view.findViewById(android.R.id.text1),
			text2 = (TextView)view.findViewById(android.R.id.text2);

		// read crossed status and set text flags for strikethrough
		boolean crossed = Boolean.valueOf(cursor.getString(columnIndex));
		if(crossed) {
			icon.setImageState(new int[] { android.R.attr.state_checked }, true);
			text1.setPaintFlags(text1.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
			text2.setPaintFlags(text2.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
		} else {
			icon.setImageState(new int[] { }, true);
			text1.setPaintFlags(text1.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
			text2.setPaintFlags(text2.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
		}
		return true;

	case android.R.id.text2:
		// binding to second textview should format time nicely
		long created = cursor.getLong(columnIndex);
		long now = System.currentTimeMillis() / 1000;

		int minutes = (int)((now - created) / 60);
		String nice = view.getContext().getString(R.string.bind_minutes, minutes);
		if(minutes >= 60) {
			int hours = (minutes / 60);
			nice = view.getContext().getString(R.string.bind_hours, hours);
			if(hours >= 24) {
				int days = (hours / 24);
				nice = view.getContext().getString(R.string.bind_days, days);
			}
		}

		((TextView)view).setText(nice);

		return true;
	}

	// otherwise fall through to other binding methods
	return false;

}

And finally the code needed to connect the above ViewBinder to our SimpleCursorAdapter:

this.cross = (CrossView) this.findViewById(R.id.crossview);
this.list = (ListView) this.findViewById(android.R.id.list);

this.cross.addOnCrossListener(this);

// build adapter to show todo cursor
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item_todo, cursor,
	new String[] { db.FIELD_LIST_TITLE, db.FIELD_LIST_CREATED, db.FIELD_LIST_CROSSED },
	new int[] { android.R.id.text1, android.R.id.text2, android.R.id.content });
adapter.setViewBinder(new CrossBinder());

list.setAdapter(adapter);

And it really is that simple. The SimpleCursorAdapter shows our todo list, and the ViewBinder handles showing COL_CREATED correctly, and assigning the overall crossed-off state based on COL_CROSSED.

There is some additional code in our Activity to handle onCross() events and update the database and ListView as needed. Finally I threw in a context menu to handle deleting and crossing-off items on phones without a touchscreen, and a normal menu for adding new items.

The last cool thing is the stateful drawable that I’m using to automatically change the icon based on crossed-off status and also on selection:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
	<item android:state_selected="true" android:state_checked="true"
		android:drawable="@drawable/indicator_check_mark_dark_invert" />
	<item android:state_checked="true"
		android:drawable="@drawable/indicator_check_mark_dark" />

	<item android:state_selected="true" android:drawable="@drawable/ic_text_dot_c_invert" />
	<item android:drawable="@drawable/ic_text_dot_c" />
</selector>

The ImageView automatically works its way down that list until it finds a drawable that matches all the state requirements, which makes it super easy to handle darkening icons when an item is selected. We also used ImageView.setImageState() earlier in our ViewBinder to correctly set the checked state.

If you’re interested, here’s the full Eclipse project source under a GPLv3 license, and also an APK ready to be installed. And here’s some video of the app in action:

Quick database row editor in Android 0.9 SDK

Thursday September 11, 2008 at 3:46 PM

For several Android projects I’ve needed a quick way of editing database rows without building an entire GUI. In the 0.9 SDK, we saw the introduction of the Preferences framework for storing simple application data, along with the PreferenceActivity family of classes for rapidly creating editable GUIs with almost zero effort. Wouldn’t it be awesome if we could edit database rows just as easily?

It is possible if you’re willing to do a little hacking. Essentially we’re providing a fake SharedPreferences up to a PreferenceActivity window. Instead of reading and saving from the application preferences, our SharedPreferences class will be using a specific database row for its storage. To make it all work, we then override the PreferenceActivity.getSharedPreferences() method to return our fake SharedPreferences instance.

Below is some example code of this approach being used in ConnectBot, an Android SSH client that I’ve been working on. First the host_prefs.xml file where we define the “preferences” that will be written to our database. Notice that I’m setting android:key to the database column names, which will make pairing the data up much easier later.

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
	<EditTextPreference
		android:key="nickname"
		android:title="Nickname"
		/>
	<ListPreference
		android:key="color"
		android:title="Color category"
		android:entries="@array/list_colors"
		android:entryValues="@array/list_colors"
		/>
	<CheckBoxPreference
		android:key="usekeys"
		android:title="Use SSH keys"
		/>
	<PreferenceCategory android:title="Connection settings">
		<EditTextPreference
			android:key="username"
			android:title="Username"
			/>
		<EditTextPreference
			android:key="hostname"
			android:title="Host"
			/>
		<EditTextPreference
			android:key="port"
			android:title="Port"
			/>
	</PreferenceCategory>
</PreferenceScreen>

Now let’s look at the code we’ll be using for our PreferenceActivity. Nothing too special except we are overriding the getSharedPreferences(), which is how the PreferenceActivity will get its data source. In this example we’re doing a quick hack by passing the exact _id into the onCreate() as Intent.EXTRA_TITLE. Another way to handle this would be to pass around ContentProvider URIs, which would help clean up this code in several places.

With that approach, the best way to create the SharedPreferences instance would be by passing the URI as the name string to the getSharedPreferences() call. We could easily set the name string our PreferenceActivity requests by calling getPreferenceManager().setSharedPreferencesName(uri.toString()).

public class HostEditor extends PreferenceActivity
	implements OnSharedPreferenceChangeListener {
	protected CursorPreferenceHack pref;

	@Override
	public SharedPreferences getSharedPreferences(String name, int mode) {
		Log.d(this.getClass().toString(), String.format("getSharedPreferences(name=%s)", name));
		return this.pref;
	}

	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);

		HostDatabase db = new HostDatabase(this);
		int id = this.getIntent().getIntExtra(Intent.EXTRA_TITLE, -1);

		// TODO: we could pass through a specific ContentProvider uri here
		//this.getPreferenceManager().setSharedPreferencesName(uri);

		this.pref = new CursorPreferenceHack(db.getWritableDatabase(), db.TABLE_HOSTS, id);
		this.pref.registerOnSharedPreferenceChangeListener(this);

		this.addPreferencesFromResource(R.xml.host_prefs);
		this.updateSummaries();
	}

	public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
		// update values on changed preference
		this.updateSummaries();
	}

	protected void updateSummaries() {
		// for all text preferences, set summary as current database value
		for(String key : this.pref.values.keySet()) {
			Preference pref = this.findPreference(key);
			if(pref == null) continue;
			if(pref instanceof CheckBoxPreference) continue;
			pref.setSummary(this.pref.getString(key, ""));
		}
	}
}

And finally the CursorPreferenceHack source. It’s pretty simple, and just wraps the SharedPreferences calls as needed when converting them over into Cursor calls. The resulting GUI is easy to change, just remember to set your android:key values to database column names so they can be resolved correctly:

So there you have it, this approach allows you to make rapid GUI interfaces to safely update your database-backed information. It’s definitely a hack for now, but it makes these GUI interfaces a snap. I think the Preferences framework itself might use databases for its normal storage, so they might generalize this family of classes in the future.

Next Page »

Archives

Watch my blog using Google Reader: Add to Google

Valid XHTML and CSS