Thursday, December 31, 2009

LiveFolders as feeds

LiveFolders exist in Android since version 1.5. The mechanism was advertised as a lead feature of Android 1.5/1.6 but somehow it failed to take hold. There are excellent introductions to LiveFolders, for example this one so I cut short here. Folder is an element of the Android desktop (technically, the Launcher application) that contains "links" to e.g. Android applications. More exactly, these "links" fire Intents and those intents can launch applications, open data sources, etc. A LiveFolder is different from a normal folder in that the content of the folder (folder items and their graphical representations) is not statically stored but is generated dynamically by a ContentProvider. There is a discovery mechanism based on Activities handling the android.intent.action.CREATE_LIVE_FOLDER intent. The Launcher discovers all the Activites handling this intent, invokes them by sending the intent, in response these Activities return the URIs of the LiveFolders' ContentProviders. If the user creates an icon for a LiveFolder and opens this icon, the Launcher will know the URI of the ContentProvider behind the LiveFolder, will list its content (as icon grid or list) and allow the user to activate an item in the LiveFolder which will fire an intent, opening a contact for example.

So far so good but I would like you to think a bit further. So we have these LiveFolders that
  • Allow applications to produce items of interest
  • And these items of interest, when "clicked", activate other actions.
Doesn't is sound familiar? Feeds in web programming are just like that. Android UI already has some elements of web programming (like the Back button) and now it has feeds. Feeds are not only fashionable nowadays but have deep roots in dataflow programming (here is a short introduction if you want to know more) and clever application frameworks like Yahoo Pipes were built around them.

Sadly, exploiting this possibility is not easy now. The only LiveFolder client I am aware of is Launcher itself and aggregating/manipulating feeds is not easy. I am attempting to do just that in this blog post. I will show you how to create a LiveFolder of non-starred contacts of two existing LiveFolders: All contacts and starred contacts.

Click here to download the live folder aggregating application.

Did you know that you can star contacts? I did not but there is a LiveFolder for starred contacts.


Install the application. Now if you select the Add menu on the Launcher main screen, select Folders, you will see the Nonstarred folder. Add that folder and it appears on the home screen. If you open that folder, you will see all non-starred contacts in it. If you click any such contact, the Contact application is opened and the contact is displayed.





We generate the non-starred LiveFolder from to other LiveFolders. The application has two parts, an Activity that is invoked by Launcher to discover the LiveFolder. This is the part of the application that itself discovers other LiveFolders to retrieve the URIs of the two source LiveFolders. These URIs are then passed to the ContentProvider that aggregates the two source LiveFolders into a third one. The interesting part is the fake Cursor we return to the LiveFolder client which really accesses in-memory data and not SQLite database as it is usual with Android applications.

As a bonus track, I share with you a simple LiveFolder client that helps you to discover other LiveFolders.

Click here to download the live folder client application.


So far so good but I am not satisfied. In order to achieve the ease of manipulating RSS feeds in web programming, more automation is necessary. I intend to do it later, after I experimented with another idea.

Monday, November 23, 2009

Droidcon+ODEX file disassembly

First, the advertisement. I will make a longer presentation at Droidcon London 2009 about Dalvik bytecode in general, using Dedexer examples. This will be a longer version of my previous, short presentation (also in podcast). If central London is convenient for you, please, come. Otherwise I will share the presentation after the event.

To celebrate the event, I finished the symbolic ODEX disassembly feature in Dedexer (look for version 1.8). This means that instead of ugly offsets, Dedexer now correctly decompiles the method and field names for execute-inline, iget/iput-quick and nvoke-virtual-quick instruction families if the dependency files are available. So instead of this:

.line 3041
invoke-virtual-quick {v5},vtable #0x2c
move-result-object v2
.line 3042
iget-object-quick v3,v5,[obj+0x28]
invoke-virtual-quick {v3},vtable #0xe
move-result-object v0
.line 3043
execute-inline {v2},inline #0x4
move-result v1

You will get this:

.line 3041
invoke-virtual-quick {v5},android/app/Activity/android/app/Activity/getPackageName ; getPackageName()Ljava/lang/String; , vtable #0x2c
move-result-object v2
.line 3042
iget-object-quick v3,v5,mComponent Landroid/content/ComponentName; ;[obj+0x28]
invoke-virtual-quick {v3},android/content/ComponentName/android/content/ComponentName/getClassName ; getClassName()Ljava/lang/String; , vtable #0xe
move-result-object v0
.line 3043
execute-inline {v2},Ljava/lang/String/length ; length()I , inline #0x4
move-result v1


Much better, isn't it? See you at Droidcon and I will explain how to interpret the code fragment above.

Monday, November 2, 2009

Another book: Android Wireless Application Development

Somebody contacted me by LinkedIn whether I would write a review about this book from Addison-Wesley. Why not, replied I, if I get the book to read and it is understood that I am not a professional reviewer. I got the book, read it and here are my subjective impressions.


Gee, there are SO MANY THINGS in Android - that was the lingering feeling after having read the book. Because the authors' strong intention is not to make compromises. They methodically go through every feature of the Android API, including 1.5 features. Have you heard about AppWidgets before? Or LiveFolders? I admit that I have not but now I know about them because the book mentioned it.

The enormous breadth of the discussion comes with a cost, however. Even though everything (or almost everything) is mentioned, very few topics are discussed in depth. For example I checked the most popular topics of this blog - unit tests, adapters. The Android unit testing framework is discussed as a bulleted list (no code examples) and the ArrayAdapter example uses Strings as backing data which causes so many problems for developers. I even managed to find the topic of hybrid applications (mashup of web technologies and Android applications, like the JavaScript handlers that an Android app can implement) that was not discussed at all (go to the lean Hello, Android book if you are interested, how this very fashionable approach works in Android).

It is best to handle this book as an inventory of Android features and as such, it is very valuable. Such an inventory takes 573 pages, as of version 1.5. I wonder what that number will be in 3 years time.

Wednesday, October 28, 2009

Spinner and its data behind

I got another comment asking about Spinner and the data behind the widget. The author of the comment wanted to know, how to associate data to the item the Spinner displays. Then that associated data would be used to look up some other data source.

Click here to download the example program.

In order to understand the trick, one has to know, how Adapters work in general and ArrayAdapter in particular. Adapters are objects that are able to turn data structures into widgets. The widgets are then displayed in a List or in a Spinner. So the two questions an Adapter answers are:
  • What widget or composite view to associate with a data structure with a certain index.
  • How to extract data from the data structure and how to set field(s) of the widget or composite view according to this data.
ArrayAdapter's answers are:
  • Each widget for any index is the same and is inflated from the resource whose ID the ArrayAdapter receives in its constructor.
  • Each such a widget is expected to be an instance of TextView (or descendant). The widget's setText() method will be used with the string format of the item in the supporting data structure. The string format will be obtained by invoking toString() on the item.
Knowing these facts, the solution is very simple. We back ArrayAdapter with our own data structure. In this simple example MyData structure has just two fields but we can use structures with arbitrary complexity. The only thing we have to care about is that the data object's toString() method will be used to obtain the text which is displayed in the Spinner. Hence we made sure that toString() returns just one field of the object. The other field will be retrieved from MyData when the item is selected. Our application is written in such a way that then the other field is displayed in a separate text field.

Tuesday, October 27, 2009

Lists and focuses

I received another seemingly trivial question in a comment. The situation is simple: we have a ListView and it contains TextViews. The user clicks (touches) a list row and the row gets highlighted until the user removes his or her finger (releases the mouse button in case of the emulator). Then comes the mistery. If you put a Button into the row, this highlight does not happen. How come?

Download the example program from here.

The secret is the quite complicated relationship between the ListView's selection algorithm and the focus. Button is focusable, basic TextView is not (Button is really just a specialized TextView). ViewGroup (whose child is LinearLayout which encapsulates one list row) delegates the focus to its first focusable child if it is not prevented to do so. As list row gives away the focus to the first focusable child (the Button) and the user did not touch the Button's area, neither the list row, nor the Button is selected. All this happens in "touch mode", try to select the row with the down/up key and you will see a completely different selection algorithm in action - the row is highlighted but the Button is not.



In order to achieve the selection effect you see in the screenshot, the ViewGroup must be prevented giving away the focus. The example program implements a quick and dirty solution: the Button is not focusable (ButtonListAdapter, line 47). More elegant solution would be to declare the ViewGroup (inflated from the buttonrow.xml layout) with FOCUS_BLOCK_DESCENDANTS flag. Conveniently, not being focusable does not prevent the Button in receiving events, click on the action button and the row counter increases nicely.

Friday, October 23, 2009

Sunday, October 18, 2009

Help needed

I decided to release a new version of dedexer but I am not satisfied. The Holy Grail I am chasing is the high-quality disassembly of ODEX files and I intended to use the hint received from Nenik. I extended the dedexer tool with data flow analysis so it now has knowledge about the types in Dalvik registers at any point of the execution of Android bytecode. If you ask nicely the new version of the tool (-r switch), it will even share this information with you. Now a decompiled method looks like this if this switch is used:

.method public (Ljava/lang/String;)V
.limit registers 4
; this: v2 (LLineReader;)
; parameter[0] : v3 (Ljava/lang/String;)
.catch java/io/IOException from lbba to lbda using lbdc
.line 18
invoke-direct {v2},java/lang/Object/ ; ()V
; v2 : LLineReader;
lbba:
.line 20
new-instance v0,java/io/FileInputStream
; v0 : Ljava/io/FileInputStream;
invoke-direct {v0,v3},java/io/FileInputStream/ ; (Ljava/lang/String;)V
; v0 : Ljava/io/FileInputStream; , v3 : Ljava/lang/String;
iput-object v0,v2,LineReader.fis Ljava/io/FileInputStream;
; v0 : Ljava/io/FileInputStream; , v2 : LLineReader;
.line 21
new-instance v0,java/io/BufferedInputStream
; v0 : Ljava/io/BufferedInputStream;
iget-object v1,v2,LineReader.fis Ljava/io/FileInputStream;
; v1 : Ljava/io/FileInputStream; , v2 : LLineReader;
invoke-direct {v0,v1},java/io/BufferedInputStream/ ; (Ljava/io/InputStream;)V
; v0 : Ljava/io/BufferedInputStream; , v1 : Ljava/io/FileInputStream;
iput-object v0,v2,LineReader.bis Ljava/io/BufferedInputStream;
; v0 : Ljava/io/BufferedInputStream; , v2 : LLineReader;
lbda:
.line 28
return-void
lbdc:
.line 23
move-exception v0
; v0 : Ljava/io/IOException;
goto lbda
.end method

Great then, but where is the invoke-quick disassembly? Well, erm, I ran into problems. First of all, I could not figure out the data structures that store the names of other ODEX files that this ODEX file depends on. They seem to be in some sort of data structure at the end of the ODEX file that stores the name of these files but its exact layout remains a mistery for me.

Second, in order to decode invoke-quick statements, iget-object-quick statements also need to be decoded because the type values they put into Dalvik registers are needed for the data flow analyser. The source of this instruction is known as an offset and the mapping of these offsets back to Java types.

I will try to progress with these problems, any help is appreciated.

And now some PR after the boring technical details.

I will make a short presentation about dedexer during the coming Android meetup in London. If you are interested about the tool and central London is accessible for you, let's see each other there.

Sunday, August 23, 2009

Dedexer in Softpedia

Wow, I got an e-mail that dedexer 1.5 got included into Softpedia. The funny thing is that it got included into the Mac development tool section. I have already got a number of questions from Android developers working on Mac. Is it so that Mac is a favourite platform for Android developers or is it just my fortune? Any opinions?

Monday, August 17, 2009

Fancy graphs

It seems that a sure sign of the maturity of an application platform when graph libraries start to appear. Android definitely got to this stage with aiCharts.

I didn't discover it myself. I got a mail from the authors. Even though aiCharts is a commercial product, the Android component market is still nascent enough so that they deserve advertising (even if it is only my lame advertising).

aiCharts comes with flashy demonstrations and a number of demo programs.


There was only one limitation I was able to discover: the demo programs require the latest API version and according to the authors, aiChart will not run with lower than Android 1.1. Another limitation is that ArtfulBits obviously wants to make money out of the product so the thing is protected by license key.

I also received this chart from them that I now share with you. If you need a chart library, at least you know what options to choose from.

Feature name aiCharts, Artfulbits v1.0.0 Rchart, java4less, v1.0.0 chart4j, Google, v1.2 jFreeChart, Jfree, v1.0.13 AChartEngine, 4viewsoft, v0.3.0
Chart types




Area + + - + +
Bar + + + + +
Bubble + + + + -
Box and Whiskers - - - + -
Candle stick + + - + +
Column + + + + -
Doughnut - - - + -
Fast line + - - + -
Funnel + - - - -
Gantt - - - + -
HiLo Open Close + + - + -
HiLo + + - + -
Histogram - - - + -
Kagi - - - - -
Line + + + + +
Pie + + + + +
Point + + + + -
Polar + + + + -
Point and Figure - - - - -
Pyramid + - - - -
Renko - - - - -
Spline Area + - - + -
Spline + + + + -
100% Stacked Area + - - + -
Stacked Area + - - + -
Stacked Bar + + - + +
100% Stacked Column + - - + -
Stacked Column + - - + -
Step Line + - - + -
Step Area - - - + -
Three line break - - - - -
Tornado
- - - -
3D Charts - + pseoudo + -
Annotations + + + + -
Multiple series + + + + +
Multiple areas + - - - -
Legend + + + + -
Multiple legends + - - - -
Legend dock + + + + -
Legend alignment + + - - -
Custom legend items + - - + -
Axis




Logarithmic axes - + - + -
Multiple axes - + - + -
Axis label position + - - + -
Axis label alignment + - - + -
Labels mode + - + + -
Date values + + + + -
Axis scale + + + + -
Custom labels format + - + - -
Nice range calculation + + + + -
Zoom/Scroll + + + + -
Striplines + + + + -
Series




SQL data source + - - - -
Series drawables + - - - -
Per point style + - - - -
XML data source + - - - -
Visual customization




Themes - - - + -
Chart background + + - + -
Axes customization




Series customization




Annotations customization + + + + -
Saving chart to image/stream + + + + -
XML inflation + - - - -
Multiple titles + - - - -
Events on chart objects clicks + - - - -
Specially writtern for Android + - - - -
APIs Documentation + + - + -
Intuitive architecture + - - - -
Summary for features 61 38 25 53 9

Friday, August 7, 2009

Dedexer annotation support

Just a short post for those few who do Dalvik bytecode analysis: dedexer has now full annotation support! For example it now decompiles "throws" and inner class annotation, along with custom annotations. Go for 1.5 release to get it.

Thursday, July 30, 2009

It's that simple

Like many, I also thought that this project was a joke. Somebody obviously created something like the Visual Basic and made it work on Android. Then from this blog post, it became clear that Simple is dead serious.

Simple tries to replicate the 20 year old Microsoft idea about high-performance components and a script language binding them into applications. There is one thing, however, that caught my attention. Why not Python or any other "real" script language? Why this Basic afterthought?

The intriguing fact is that Android's virtual machine, Dalvik just got another language beside Java. The Simple compiler takes the Simple code and compiles directly into Dalvik bytecode, without going through Java. For example there is this Simple subroutine (remember the term "subroutine" ages ago? :-)).

Sub PreviewBrick(brick As Brick, orientation As Integer)

The Simple compiler turns it into a proper Dalvik method (Simple compiler's DEX output decompiled by Dedexer):

.method public PreviewBrick(Lcom/google/devtools/simple/samples/tetris/Brick;I)V

There is a runtime for Simple programs but it is not really an interpreter, it is just a glue between the standard Android classes and the Simple event system. That may explain, why the scripting language is not Python; a real scripting language may be too dynamic to compile.

There have been similar attempts for Java proper but the JVM was never designed to run anything other than Java. When .Net appeared, Microsoft claimed that the .Net Common Language Runtime is much more suitable running certain languages than the Java bytecode. This may or may not be true, the fact remains that CLR runs mostly C# and Visual Basic.NET programs.

From this demonstration with Simple, it is clear that Dalvik can also run a script language (Simple) and a component language (Java). Whether developers will find attractive enough to work in a script language that needs time-consuming compilation and deployment before running it (one huge advantage of scripting languages is that the program can be executed immediately after modification) or whether experimenting software experts want to use a rather obsolete language (like this BASIC clone) for binding their components is yet to be seen.

Wednesday, July 1, 2009

New DEX assembler/disassembler pair

Dedexer got competition! Not one but immediately two - smali and baksmali is a DEX assembler/disassembler pair. The programs are brand new and - like Dedexer - they are also based on a Jasmin-like format. I tried them very shortly, the disassembler - baksmali - worked correctly and indeed produced an output similar to dedexer but I could not compile the output of baksmali back to DEX format with the assembler - smali. The disassembler does not handle ODEX files either.

The initiative is indeed valuable, however, and I encourage every reverse engineer out there give the new tools a try.

Tuesday, June 30, 2009

Custom adapter in color

I got a comment on this blog with relation to an old sin of mine, the custom adapter example program. That example was about custom views in a list adapter. The comment was innocent enough: is there a way to change the colors of that list? I thought it was a 5 minute task to answer that question, in the end I had to deal with a topic I never wanted to know about: themes.

Click here to download the example program.

It turned out that the color scheme used by ListView is eventually taken from the active theme. It is possible to change it programmatically but it is quite complicated to do so. Meanwhile, with themes, it is relatively easy. If you know the information source. The Android development guide is almost completely useless regarding themes, for example sample themes don't work. This blog entry from Brainflush is much more informative, at least its examples work. The source that helped me the most was the actual Android XML fileset that defines the themes. If you have access to the Android source tree, the Android system resources can be found under the platform\frameworks\base\core\res\res directory. The relevant files are styles.xml under the values subdirectory and the content of the drawable subdirectory.

If you check the styles.xml in the res/values directory in our example program, you will see that modifying the color scheme of the ListView is a quite complicated, multi-step process. First of all, in res/values/styles.xml, the ListView style is overridden with the android:listViewStyle property. The ListViewStyle (MyListView) in turn references a list selector (android:listSelector) that is stored in the res/drawable directory. That selector defines color schemes for all the possible state combination of the list row. To increase the fun, the resource compiler screwed up the image IDs in the R.java file if the weather icon image files were not at the beginning of the file name list, hence the bizarre names in the drawable subdirectory. Now what we need more is a transition that refers a 9-patch background image (block blue in our case) for the selected row and we are ready.

Don't say that it was not easy.

PS: I apologize for the hideous colors. :-)

Tuesday, June 23, 2009

Assets

Let's have something lighter than the application separation stuff was in the previous entry.

I got a mail from someone who wanted to embed raw files into the APK file so that they are available for the application when it is executing. I have never done such a thing but I remembered faintly something about the res/raw directory where such resources reside. They are still there but now there is a better thing: assets. The difference between a raw resource in res/raw directory and an asset is that assets behave like a file system, they can be listed, iterated over, discovered, just like files while for raw resources, you need the resource ID.

Click here to download the example program.

This simple application iterates over the files in the asset directory, reads their contents and sets three TextFields according to the content of these files. Assets go into the ./assets directory in the project root and can contain any files. The AssetManager class provides access to assets as InputStreams.