I’ve just released a new app for Android that adjust the ringtone and notification volume based on ambient noise. The app is available on the Android Market for $0.99. Check it out on the Android Market or the RingDimmer homepage!
Android Protips Talk Slides
I recently gave a talk on Android at CodeMash called Android Protips. I’ll be giving this talk a few more times this year. I’ll be at Code PaLOUsa on March 16th, and AnDevCon III on May 14th-17th.
If you can’t make any of those dates, or you just want the slides, you can grab them here!
Falling back on old SDK methods without reflection
As Android progresses as a platform, there will inevitably be methods added to the SDK. You’ll want to add some of these great new features while still supporting the old SDKs.
We can conditionally use these methods by getting the device’s SDK version and using the appropriate method, but this won’t actually work because although it may compile, the older device will throw an exception when it loads the class that uses that unknown method.
One way to fix this is via reflection, which works great. Reflection, however, can be resource intensive, and hard to maintain. You’ll have to declare the method as a string and pass in a method signature… gross.
Another way to do this builds on the first approach. Since a method isn’t loaded until the class it’s in is loaded, we can hide the method in another class. Here’s how it works:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Check to see if this version of Android supports
// ListView smooth scrolling
if(Integer.parseInt(Build.VERSION.SDK) >= 8) {
// Smooth scroll to position
SmoothScrollMethodHolder.smoothScrollToPosition(getListView(), 5);
}
else {
// Set postion
getListView().setSelection(5);
}
}
private class SmoothScrollMethodHolder {
// Put method in a static method of a private class. This class
// won't be loaded until you call this statically method.
public static void smoothScrollToPosition(ListView listView, int position) {
listView.smoothScrollToPosition(position);
}
}
}
This code is easy to read, easy to maintain, and comes with all the benefits that reflection strips away, like code completion. Of course, you don’t want to litter your code with the above, so you’ll probably want to put it into a utility class.
private static final int SDK_VERSION = Integer.parseInt(Build.VERSION.SDK);
public static void smoothScrollToPosition(ListView listView, int position) {
if(SDK_VERSION >= 8) {
API9.smoothScrollToPosition(listView, position);
}
else {
listView.setPosition(position);
}
}
private static class API6 {
...
}
private static class API8 {
public static void smoothScrollToPosition(ListView listView, int position) {
listView.smoothScrollToPosition(position);
}
}
private static class API9 {
...
}
private static class API10 {
...
}
private static class API14 {
...
}
}
You can add all your compatibility methods to this class. The original code is now just:
Inset TextView shadows
If you’re used to using Apple products, you’re probably familiar with the heavy use of inset shadows. It adds a bit of depth to the UI and can really make the screen look beautiful. Notice the white drop shadow in the title of the window.

I tend to do the same thing a lot for my Android apps. It’s incredibly simple to do. Here’s an example of a TextView with the same inset shadow.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
...
android:shadowColor="#88FFFFFF"
android:shadowRadius="0.1"
android:shadowDx="0"
android:shadowDy="1" />
<!-- Semi-opaque black inset shadow above the text -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
...
android:shadowColor="#88000000"
android:shadowRadius="0.1"
android:shadowDx="0"
android:shadowDy="-1" />
And here’s how it looks:

It should look great on all screen sizes. Don’t use the above code strictly, however. Mess around with the color values and shadowRadius value to get the exact effect you’re looking for.
Repeating Bitmaps inside LayerLists
I’ve run into this particular issue several times now. It’s a bug in the Android SDK, which apparently has been fixed as of ICS (Ice Cream Sandwich). When you place a <bitmap> inside a <layer-list>, it tends to do whatever it feels like doing in regards to repeating the bitmap. Sometimes it will follow your instructions, and sometimes it won’t.
To fix this, just set the repeat mode in code. Here’s a snippet that will set all your Bitmaps repeating in a LayerDrawable.
final int size = layerDrawable.getNumberOfLayers();
for(int i = 0; i < size; i++) {
Drawable drawable = layerDrawable.getDrawable(i);
if(drawable instanceof BitmapDrawable) {
((BitmapDrawable) drawable).setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
}
}
}
Getting visible bounds from a MapView
MapView doesn’t have a getBounds() method, but using a couple of MapView’s other methods, it’s actually very easy to find the visible bounds. MapView has the methods getCenter(), getLongitudeSpan(), and getLatitudeSpan(). By combining these methods we can get the visible bounds.
final GeoPoint mapCenter = mapView.getMapCenter();
final int lngHalfSpan = mapView.getLongitudeSpan() / 2;
final int latHalfSpan = mapView.getLatitudeSpan() / 2;
return new Rect(mapCenter.getLongitudeE6() - lngHalfSpan, mapCenter.getLatitudeE6() - latHalfSpan,
mapCenter.getLongitudeE6() + lngHalfSpan, mapCenter.getLatitudeE6() + latHalfSpan);
}