Honeycomb added some neat functionality to Android widgets. However, there's a problem that arises from adding a widget using collections to your app - what if your APK is supposed to work on all versions of Android? How do you prevent the Honeycomb-only widget from appearing in previous versions?
Normally when you want to do something different between versions of Android, you either use resource qualifiers (for XML) or check Build (for code). But in this case, the widget itself is defined in AndroidManifest.xml, which can only be at the root of your project.
There's a way of removing the app widget from the listing in previous versions: use resource qualifiers on the AppWidgetProviderInfo resource.
When you define an app widget in AndroidManifest.xml, you must also define a <meta-data> element which points towards the AppWidgetProviderInfo (that is usually contained inside of a file in /res/xml/). Simply move that provider file to a directory that only Honeycomb can see - /res/xml-v11/. Earlier versions of Android will try to load the widget only to find no AppWidgetProviderInfo and will thus ignore the widget.
UDPATE (Jan 26th, 2012): I've now written about an improved solution to this problem.
I post random things I've learned while coding with the hope that it will save people time and effort.
Thursday, June 30, 2011
Tuesday, May 31, 2011
Passwords: Longer, Not More Complex
I was going through a mandatory security training course for my company when I came across a slide about passwords. Its advice was that the password should be at least 7 characters long and include a good mixture of lower/upper case characters, plus numbers and special symbols. Sony is using the same tactics. I had to change my PSN password and it forced me to use at least one number and one letter in the password.
This is totally bunk advice. What you want is a long password, and it doesn't have to be complex.
Suppose there's a server with your credentials that has the bare essentials of good security (hash + salt). If someone compromises the server, they will have to crack your password by checking every single password against the hash in the database. Therefore, the more possible passwords your scheme contains, the longer it takes to crack.
You can calculate an approximation on number of attempted passwords a cracker will have to attempt with this simple formula: (size of character set)^(password length). Given a rudimentary understanding of exponents, it's pretty evident that increasing the password length will have a lot more impact than expanding the character set size.
Let's look at some numbers. On my keyboard, there are 95 characters I could insert into a password. Let's compare a length eight password using that character set to a slightly longer password using only lower case letters (a 26 size character set):
95^8 ~= 6 quadrillion (or ~10^15)
26^12 ~= 90 quadrillion (or ~10^16)
26^15 ~= 1 sextillion (or ~10^21)
With four extra characters, my simpler password is already harder to crack than the complex eight character password.
The best part about using a limited character set is that you can create a pass phrases instead of pass words. It's much easier to remember "please do not break into my account" than "x82@.Zij", and it's also far more resilient to cracking, too.
Unfortunately, not all sites allow for long passwords. In those cases, it's better to use a more complex character set. But when given the opportunity, a long and simple password is vastly superior to a short but complicated one.
Addendum: A friend pointed out that pass phrases are more vulnerable to dictionary attacks. This is true, but only if your pass phrase contains very few words. The approximate effort for pass phrases is (number of possible words)^(number of words). Given how many possible words there are, it only takes a phrase of a few words to be as secure as 15 simple characters of nonsense. So while "supercalifragilisticexpialidocious" is a crappy password despite how long it is, my example from above ("please do not break into my account") is still very secure.
This is totally bunk advice. What you want is a long password, and it doesn't have to be complex.
Suppose there's a server with your credentials that has the bare essentials of good security (hash + salt). If someone compromises the server, they will have to crack your password by checking every single password against the hash in the database. Therefore, the more possible passwords your scheme contains, the longer it takes to crack.
You can calculate an approximation on number of attempted passwords a cracker will have to attempt with this simple formula: (size of character set)^(password length). Given a rudimentary understanding of exponents, it's pretty evident that increasing the password length will have a lot more impact than expanding the character set size.
Let's look at some numbers. On my keyboard, there are 95 characters I could insert into a password. Let's compare a length eight password using that character set to a slightly longer password using only lower case letters (a 26 size character set):
95^8 ~= 6 quadrillion (or ~10^15)
26^12 ~= 90 quadrillion (or ~10^16)
26^15 ~= 1 sextillion (or ~10^21)
With four extra characters, my simpler password is already harder to crack than the complex eight character password.
The best part about using a limited character set is that you can create a pass phrases instead of pass words. It's much easier to remember "please do not break into my account" than "x82@.Zij", and it's also far more resilient to cracking, too.
Unfortunately, not all sites allow for long passwords. In those cases, it's better to use a more complex character set. But when given the opportunity, a long and simple password is vastly superior to a short but complicated one.
Addendum: A friend pointed out that pass phrases are more vulnerable to dictionary attacks. This is true, but only if your pass phrase contains very few words. The approximate effort for pass phrases is (number of possible words)^(number of words). Given how many possible words there are, it only takes a phrase of a few words to be as secure as 15 simple characters of nonsense. So while "supercalifragilisticexpialidocious" is a crappy password despite how long it is, my example from above ("please do not break into my account") is still very secure.
Tuesday, May 24, 2011
Using Subquery Columns on Android with SQLite
Take a look at this (contrived) query, as might be passed to SQLiteDatabase.rawQuery():
On Android 2.1 and below, this query will cause your app to crash. You'll get an error like this:
It turns out that SQLite throws this error if two conditions are met:
The solution is simple: alias the selected field names. This query will work:
I'm hardly an expert on SQL or SQLite, so I don't know whether this is a bug or just me running into undefined behavior. I ran into this problem when doing JOINs on multiple tables, so as contrived as my example is, it can happen. Regardless, it is easy to work around.
SELECT *
FROM t1 A, (SELECT T2.id FROM t2 T2) B
WHERE A.id = B.id
On Android 2.1 and below, this query will cause your app to crash. You'll get an error like this:
Caused by: android.database.sqlite.SQLiteException: no such column: B.id: , while compiling: SELECT * FROM t1 A, (SELECT T2.id FROM t2 T2) B WHERE A.id = B.id
at android.database.sqlite.SQLiteProgram.native_compile(Native Method)
at android.database.sqlite.SQLiteProgram.compile(SQLiteProgram.java:110)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:59)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:49)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:49)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1220)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1193)
at com.mycompany.myapp.MyActivity.onCreate(QuickTestActivity.java:22)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
... 11 more
It turns out that SQLite throws this error if two conditions are met:
- You use a subquery (in this case, the select subquery from table t2).
- Your subquery has a table alias (in this case, referencing table t2 as "T2").
The solution is simple: alias the selected field names. This query will work:
SELECT *
FROM t1 A, (SELECT T2.id AS id FROM t2 T2) B
WHERE A.id = B.id
I'm hardly an expert on SQL or SQLite, so I don't know whether this is a bug or just me running into undefined behavior. I ran into this problem when doing JOINs on multiple tables, so as contrived as my example is, it can happen. Regardless, it is easy to work around.
Wednesday, April 27, 2011
Detecting the Keystore Signature in Code
Here's a problem I'm sure many of us have faced: you've got code that runs one way when you're developing and another way when you're releasing. A few examples I've run into:
- Logging during development, but disabled for release.
- Targeting development vs. production servers.
- MapView requires an API key tied to the signing key.
Before, I just setup static parameters in code that I'd have to remember to change before making a release build. It's a pain and error prone.
I've just determined a much better (and more automatic) way - detecting the signing keystore in code. Through use of the PackageManager you can actually determine the Signature of the app that's currently running.
First, you need to get the Signature of your release keystore. Put this code into your application temporarily, then sign it with your release keystore and run it:
Take the output from logcat and put it into this method:
Now you can always call isRelease() and check whether your app was signed by your release keystore. No more having to edit files to create a release version of your app - just sign it with the correct keystore and you're ready to go!
- Logging during development, but disabled for release.
- Targeting development vs. production servers.
- MapView requires an API key tied to the signing key.
Before, I just setup static parameters in code that I'd have to remember to change before making a release build. It's a pain and error prone.
I've just determined a much better (and more automatic) way - detecting the signing keystore in code. Through use of the PackageManager you can actually determine the Signature of the app that's currently running.
First, you need to get the Signature of your release keystore. Put this code into your application temporarily, then sign it with your release keystore and run it:
PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
Log.i("test", pi.signatures[0].toCharsString());
Take the output from logcat and put it into this method:
private static final Signature SIG_RELEASE = new Signature("<YOUR SIGNATURE HERE>");
public static boolean isRelease(Context context) {
try {
PackageManager pm = context.getPackageManager();
PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
for (Signature sig : pi.signatures) {
if (sig.equals(SIG_RELEASE)) {
return true;
}
}
}
catch (Exception e) {
Log.w("Exception thrown when detecting if app is signed by a release keystore.", e);
// Return true if we can't figure it out, just to play it safe
return true;
}
return false;
}Now you can always call isRelease() and check whether your app was signed by your release keystore. No more having to edit files to create a release version of your app - just sign it with the correct keystore and you're ready to go!
Wednesday, April 13, 2011
HTML in TextViews
There's a trick I've been increasingly using as I've learned how powerful it is: HTML in TextViews.
I used to think that TextViews were pretty plain; they contained a CharSequence, and that was it. But it can actually contain a Spanned (or its mutable cousin, Spannable) buffer type as well. This means that there are a host of HTML tags that you can use to modify your TextView, which allows for different typefaces/functionality - all in the same TextView. Check out what you can do with just one string resource in a TextView:

Here's the string resource for above:
Android has tips on the basics of Html in TextViews, but it doesn't nearly cover some of the use cases. It also doesn't have a reference on which tags are supported (scroll to bottom for a reference I created).
Here are a few tips:
Links in TextViews
The simplest way to add links to TextView is to use the android:autoLink attribute. However, this only allows you to link visible URIs in the text and can sometimes lead to undesired situations (I had an app that was detecting the copyright dates "2009-2011" as a phone number). By using the <a> tag, you can create links with any text that leads to any URI:
There's only one catch: when you try to use this in a TextView, it won't be clickable unless you set the movement method in code:
Dynamic Html
All of the above examples have been with static text - that is, when the TextView's android:text attribute is set in XML from a string resource. What if you want to set a TextView's string resource in code? This is especially important when you use string formatting (which I'm a big fan of).
Android discusses this already, but for posterity I'll repeat the process here:
1. HTML-escape the string resource:
2. Use Html.fromHtml() to dynamically create a Spanned that a TextView can be styled with:
Handling Custom Tags
So far so good, but I ran into a problem the other day: while the <strike> tag works if it's linked as a static string, it doesn't work when using Html.fromHtml(). I looked through the source code and discovered that Html.fromHtml() handles a different set of tags from static resources. Luckily, there's a way to handle tags that Html.fromHtml() doesn't: the TagHandler interface.
It's a little complex, but here's one possible solution for how to handle the <strike> tag. (My own solution differed a bit, but the essentials are the same.)
Tags Supported in String Resources
Tags in static string resources are parsed by android.content.res.StringBlock, which is a hidden class. I've looked through the class and determined which tags are supported:
Tags Supported by Html.fromHtml()
For some reason, Html.fromHtml() handles a different set of of tags than static text supports. Here's a list of the tags (gleaned from Html.java's source code):
The font "color" attribute supports some color names (along with the normal integer-based color scheme):
I used to think that TextViews were pretty plain; they contained a CharSequence, and that was it. But it can actually contain a Spanned (or its mutable cousin, Spannable) buffer type as well. This means that there are a host of HTML tags that you can use to modify your TextView, which allows for different typefaces/functionality - all in the same TextView. Check out what you can do with just one string resource in a TextView:

Here's the string resource for above:
<string name="html">This <b>is</b> <i>all</i> <sub>in</sub> <u><sup>one</sup></u> <a href="http://google.com">TextView</a>.</string>
Android has tips on the basics of Html in TextViews, but it doesn't nearly cover some of the use cases. It also doesn't have a reference on which tags are supported (scroll to bottom for a reference I created).
Here are a few tips:
Links in TextViews
The simplest way to add links to TextView is to use the android:autoLink attribute. However, this only allows you to link visible URIs in the text and can sometimes lead to undesired situations (I had an app that was detecting the copyright dates "2009-2011" as a phone number). By using the <a> tag, you can create links with any text that leads to any URI:
<string name="my_site"><a href="http://idunnolol.com">My Website</a></string>
There's only one catch: when you try to use this in a TextView, it won't be clickable unless you set the movement method in code:
TextView myTextView = (TextView) findViewById(R.id.my_textview);
myTextView.setMovementMethod(LinkMovementMethod.getInstance());
Dynamic Html
All of the above examples have been with static text - that is, when the TextView's android:text attribute is set in XML from a string resource. What if you want to set a TextView's string resource in code? This is especially important when you use string formatting (which I'm a big fan of).
Android discusses this already, but for posterity I'll repeat the process here:
1. HTML-escape the string resource:
<string name="loud">Loud text here: <b>%s</b></string>
2. Use Html.fromHtml() to dynamically create a Spanned that a TextView can be styled with:
Spanned spanned = Html.fromHtml(context.getString(R.string.loud, "this is loud"));
myTextView.setText(spanned);
Handling Custom Tags
So far so good, but I ran into a problem the other day: while the <strike> tag works if it's linked as a static string, it doesn't work when using Html.fromHtml(). I looked through the source code and discovered that Html.fromHtml() handles a different set of tags from static resources. Luckily, there's a way to handle tags that Html.fromHtml() doesn't: the TagHandler interface.
It's a little complex, but here's one possible solution for how to handle the <strike> tag. (My own solution differed a bit, but the essentials are the same.)
Tags Supported in String Resources
Tags in static string resources are parsed by android.content.res.StringBlock, which is a hidden class. I've looked through the class and determined which tags are supported:
- <a> (supports attributes "href")
- <annotation>
- <b>
- <big>
- <font> (supports attributes "height", "size", "fgcolor" and "bicolor", as integers)
- <i>
- <li>
- <marquee>
- <small>
- <strike>
- <sub>
- <sup>
- <tt>
- <u>
Tags Supported by Html.fromHtml()
For some reason, Html.fromHtml() handles a different set of of tags than static text supports. Here's a list of the tags (gleaned from Html.java's source code):
- <a> (supports attribute "href")
- <b>
- <big>
- <blockquote>
- <br>
- <cite>
- <dfn>
- <div>
- <em>
- <font> (supports attributes "color" and "face")
- <i>
- <img> (supports attribute "src". Note: you have to include an ImageGetter to handle retrieving a Drawable for this tag)
- <p>
- <small>
- <strong>
- <sub>
- <sup>
- <tt>
- <u>
The font "color" attribute supports some color names (along with the normal integer-based color scheme):
- aqua
- black
- blue
- fuchsia
- green
- grey
- lime
- maroon
- navy
- olive
- purple
- red
- silver
- teal
- white
- yellow
Wednesday, April 6, 2011
Image Sharing on Android
One of the sillier projects I've worked on in my spare time is Rage Faces for Android. It has almost no value to anyone, which is why it's free (in every sense of the word). However, it's been quite useful to me, as it's taught me a few things about sharing images on Android. Overall, I think this is a good reason for Android developers (or any developer, really) to have fun side projects to work on - there's almost no app so trivial that you can't learn something from doing it.
Here's three big ones I learned from working on Rage Faces.
Sharing Images
The first thing it taught me is that you need space on the SD card in order to share images. This makes sense, as sending images (typically) uses the ACTION_SEND intent along with a URI to the image. You can't link a URI to a resource inside your application package, so you have to put it somewhere else (I chose the SD card).
It's also possible to put the media into a ContentProvider using MediaStore.Images.Media.insertImage(). The downside is that the image is then inserted into the Gallery, which I didn't want just for sharing images (the whole point of the app is to avoid having to fill up your gallery with images you don't want, instead keeping them in one organized place). You can avoid putting images in the Gallery by putting them into a folder on the SD card and creating a file ".nomedia".
Picture Frame and ACTION_GET_CONTENT
ACTION_SEND can be used to send the images to other applications. The opposite of that is having the intent filter ACTION_GET_CONTENT enabled; that way, other applications can request data from your app. They both work essentially the same way, by passing a URI to the image in an Intent. In the case of ACTION_SEND, you pass the URI in EXTRA_STREAM. For ACTION_GET_CONTENT, it's actually provided in the return Intent's data.
However, there is one exception: the standard Picture Frame widget doesn't play by these rules. It uses ACTION_GET_CONTENT to allow anyone to hook into their system, but they won't read a stream URI. If you try it, the picture frame widget crashes. The relevant part of the crash log is here:
What they expect is for you to pass an extra called "data", as a Bitmap. This means you need to pass back both the URI and the Bitmap as a Parcelable in the return Intent:
This neglect in following the rules of the road is, I assume, due to Cool Iris both writing the standard Picture Frame widget and the standard Gallery application. As a result, the two play together nicely, but you'll have to follow their rules to be part of the gang.
Messaging on HTC
There's another player who doesn't quite follow the rules: HTC Sense's messaging application. Instead of filtering on the ACTION_SEND action like everyone else, HTC Sense's messaging application listens to "android.intent.action.SEND_MSG". This means two things for you as a developer: You have to test for the existence of an app that accepts the action "android.intent.action.SEND_MSG", and then give the user an explicit option to send to HTC Sense's messaging application, in addition to the normal picker.
You can test whether the HTC Sense messaging app is on the phone by querying for the intent filter:
If you do have HTC Sense, you'll have to give your users the option to send messages to it. This means another layer of dialogs, which is a pain to users. At this point, I think the best solution is to stop using the Android chooser altogether. As useful as it is, the Android ecosystem is too abused to keep using it. In an ideal world, you'd only need one Intent to pass your data around, but that's just not been the case. If you roll your own chooser (which is not particularly difficult), you can include multiple possible Intents to pass out.
It's also worth noting that HTC Sense's messaging system doesn't implement ACTION_GET_CONTENT, so you can't have users insert your app's content into a conversation already in progress. This is not an insignificant oversight - people have told me they switched text messaging apps because of this lacking feature!
Here's three big ones I learned from working on Rage Faces.
Sharing Images
The first thing it taught me is that you need space on the SD card in order to share images. This makes sense, as sending images (typically) uses the ACTION_SEND intent along with a URI to the image. You can't link a URI to a resource inside your application package, so you have to put it somewhere else (I chose the SD card).
It's also possible to put the media into a ContentProvider using MediaStore.Images.Media.insertImage(). The downside is that the image is then inserted into the Gallery, which I didn't want just for sharing images (the whole point of the app is to avoid having to fill up your gallery with images you don't want, instead keeping them in one organized place). You can avoid putting images in the Gallery by putting them into a folder on the SD card and creating a file ".nomedia".
Picture Frame and ACTION_GET_CONTENT
ACTION_SEND can be used to send the images to other applications. The opposite of that is having the intent filter ACTION_GET_CONTENT enabled; that way, other applications can request data from your app. They both work essentially the same way, by passing a URI to the image in an Intent. In the case of ACTION_SEND, you pass the URI in EXTRA_STREAM. For ACTION_GET_CONTENT, it's actually provided in the return Intent's data.
However, there is one exception: the standard Picture Frame widget doesn't play by these rules. It uses ACTION_GET_CONTENT to allow anyone to hook into their system, but they won't read a stream URI. If you try it, the picture frame widget crashes. The relevant part of the crash log is here:
Caused by: java.lang.NullPointerException
at com.cooliris.media.PhotoAppWidgetProvider$PhotoDatabaseHelper.setPhoto(PhotoAppWidgetProvider.java:121)
at com.cooliris.media.PhotoAppWidgetConfigure.onActivityResult(PhotoAppWidgetConfigure.java:92)
at android.app.Activity.dispatchActivityResult(Activity.java:3908)
at android.app.ActivityThread.deliverResults(ActivityThread.java:2528)
... 11 more
What they expect is for you to pass an extra called "data", as a Bitmap. This means you need to pass back both the URI and the Bitmap as a Parcelable in the return Intent:
Intent return = new Intent();
return.setData(myImageUri);
return.putExtra("data", myBitmap);
setResult(RESULT_OK, return);
finish();
This neglect in following the rules of the road is, I assume, due to Cool Iris both writing the standard Picture Frame widget and the standard Gallery application. As a result, the two play together nicely, but you'll have to follow their rules to be part of the gang.
Messaging on HTC
There's another player who doesn't quite follow the rules: HTC Sense's messaging application. Instead of filtering on the ACTION_SEND action like everyone else, HTC Sense's messaging application listens to "android.intent.action.SEND_MSG". This means two things for you as a developer: You have to test for the existence of an app that accepts the action "android.intent.action.SEND_MSG", and then give the user an explicit option to send to HTC Sense's messaging application, in addition to the normal picker.
You can test whether the HTC Sense messaging app is on the phone by querying for the intent filter:
Intent dummy = new Intent("android.intent.action.SEND_MSG");
dummy.putExtra(Intent.EXTRA_STREAM, myImageUri);
dummy.setType("image/png");
PackageManager packageManager = getPackageManager();
List list = packageManager.queryIntentActivities(dummy, PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() > 0) { // This means the HTC Sense messaging app is on the phone } If you do have HTC Sense, you'll have to give your users the option to send messages to it. This means another layer of dialogs, which is a pain to users. At this point, I think the best solution is to stop using the Android chooser altogether. As useful as it is, the Android ecosystem is too abused to keep using it. In an ideal world, you'd only need one Intent to pass your data around, but that's just not been the case. If you roll your own chooser (which is not particularly difficult), you can include multiple possible Intents to pass out.
It's also worth noting that HTC Sense's messaging system doesn't implement ACTION_GET_CONTENT, so you can't have users insert your app's content into a conversation already in progress. This is not an insignificant oversight - people have told me they switched text messaging apps because of this lacking feature!
Wednesday, March 9, 2011
Tiled bitmaps in layer drawables
This is a bizarre bug that a coworker came across.
There's a cool feature of XML drawables that allows you to tile bitmaps, using android:tileMode. There is also the ability to layer drawables in XML, via the layer list. Naturally, there are some circumstances where you might want to layer bitmaps that are tiled.
It turns out there is a bug in Android with trying to layer a tiled bitmap. Every once in a while, a tiled bitmap in a layer list won't tile. It's not every time (nor even that common) but anything less than a 100% success rate for graphics is problematic.
The solution is to not define the bitmap drawable tileMode in XML, instead defining it dynamically in code. Inflate the drawable in code somehow (either directly, or by inflating a layout that uses the drawable). Grab the drawable, cast it to a LayerDrawable, then retrieve the BitmapDrawable from the layer list (there are a few methods for it, like LayerDrawable.getDrawable()). Then, set the tileMode in code via BitmapDrawable.setTileModeXY().
I've looked through the code and haven't figured out exactly why this bug occurs. I would appreciate any insight; in the meantime, the fix works well enough.
There's a cool feature of XML drawables that allows you to tile bitmaps, using android:tileMode. There is also the ability to layer drawables in XML, via the layer list. Naturally, there are some circumstances where you might want to layer bitmaps that are tiled.
It turns out there is a bug in Android with trying to layer a tiled bitmap. Every once in a while, a tiled bitmap in a layer list won't tile. It's not every time (nor even that common) but anything less than a 100% success rate for graphics is problematic.
The solution is to not define the bitmap drawable tileMode in XML, instead defining it dynamically in code. Inflate the drawable in code somehow (either directly, or by inflating a layout that uses the drawable). Grab the drawable, cast it to a LayerDrawable, then retrieve the BitmapDrawable from the layer list (there are a few methods for it, like LayerDrawable.getDrawable()). Then, set the tileMode in code via BitmapDrawable.setTileModeXY().
I've looked through the code and haven't figured out exactly why this bug occurs. I would appreciate any insight; in the meantime, the fix works well enough.
Subscribe to:
Posts (Atom)