I have been busy updating the next version of my File Browser app to work with Android 3.0 and display correctly on tablet devices. Almost everything worked as it had in prior versions of Android, however, not everything worked as intended.
ImageButtons with Reduced Scale Images
ImageButton behaves differently from prior versions in that if you have constraints set for the height and width of the button and set the Scale Type attribute to “fitXY”, the image used to scale downward correctly to match the height and width of the ImageButton. On a 3.0 device, however, the result is that the image scales incorrectly and appears significantly skinnier than it should. In order to display the image correctly on 3.0 and also on all prior versions, you need to also define the Padding attribute to some non-blank value. If you know the size of the image that will be assigned to the ImageButton, the difference in size between what it is and what you are trying to reduce it to is a good start. i.e. a 48×48 icon being scaled down to 40×40 by the ImageButton would mean an 8dip Padding attribute. Alternatively, you can just start with 4dip and play with the values until you find one that makes you happy.
Indeterminate Progress Bars
The indeterminate progress bar feature that is available to all Activities has a slightly different default behavior in 3.0. When you call requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS) for an Activity in prior versions of Android, the default visibility for the feature was FALSE. In 3.0, the default value is TRUE. If your code did not bother to initialize the visibility of the feature, then it will be stuck on visible for 3.0 devices until your app actually uses the feature for the first time. I highly recommend calling setProgressBarIndeterminateVisibility(false) in your Activity, right after your setContentView() call in order to keep all Android versions acting the same way.
Dynamic TabHosts
Unfortunately, I had to contend with a crash bug in Android 3.0 when dealing with adding tabs to a dynamically created TabHost. If you use a TabHost that is created with the default tabs = new TabHost(context) constructor, then you need to be aware of this exception issue with tabs.addTabs(…) (link). Basically, it seems that the default constructor for the TabHost class causes an exception down the line in addTabs() because it tries to load an XML resource for the tab content view even though none has been defined (see Tab Host Example 2 on using dynamically created content views).
An excerpt of an exception log:
Thrown: android.content.res.Resources$<wbr>NotFoundException: Resource ID #0x0 --------------- Instruction Stack Trace ------------------- android.content.res.Resources.getValue(Resources.java:1014) android.content.res.Resources.loadXmlResourceParser(Resources.java:2039) android.content.res.Resources.getLayout(Resources.java:853) android.view.LayoutInflater.inflate(LayoutInflater.java:389) android.widget.TabHost$LabelAndIconIndicatorStrategy.createIndicatorView(TabHost.java:568) android.widget.TabHost.addTab(TabHost.java:226) ... (your code calling addTab() here)
As stated in the comments of the official defect report, the workaround for this issue is to use a different constructor, namely the same one used when loading a TabHost from an XML layout file. Using
1 | tabs = new TabHost(context,null) |
will avoid the problem altogether and works in all Android versions as well.
Once I finish updating all my apps to work with 3.0, I look forward to learning about all the new features 3.0 brings to the Android framework.