2010-06-09

AppWidget design - Can I use my own custom widget?

The answer to the question is probably no. But, not impossible. If you take a look at the design of AppWidget class family. You should know that a class that doesn't meet all requirements below can't be inflated in the layout of an AppWidget.
  1. Annotated by RemoteViews
  2. Can't be found by PathClassLoader with default class path - "."
The first one is simple because RemoteViews is not private interface. You can annotate your custom class by RemoteViews as Android widgets do.

The second one is not easy to attack. You need to know where this dot refers to. It is actually defined as an environment variable BOOTCLASSPATH in a file init.rc wrapped in your boot.img or ramdisk.img.

export BOOTCLASSPATH /system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/org.startsmall.widget.jar
So, you need to,
  1. Wrap your widget class in a jar library.
    • Archive classes.dex only.
  2. Put your jar library into system.img.
    • The system.img can be decompressed by unyaffs. Decompress it and put jar library into system/framework.
    • Compress whole system/ directory back to system.img by mkyaffs2image.
  3. Modify init.rc to add custom widget jar into BOOTCLASSPATH.
    • The boot.img/ramdisk.img is just a cpio archive. Decompress  ramdisk.img, do modification to init.rc and archive it back as cpio file.
  4. Put the system.img and ramdisk.img to your avd directory (~/.android/avd/avd-XXX). Start emulator and use logcat to see whether your custom jar library is loaded by Android.
Although you can use your custom widget class now, but you may soon find you can't actually use non-RemotableViews annotated method through RemoteViews set methods. Defeated? Not really, if you are willing to hack Android, I guess you still can modify Android source code to make RemotableMethod visible to your custom widget class.

If you don't want to do it, you need to make your custom widget self-handled. You can't update custom widgets by set methods of RemoteViews, but you can send broadcasts to update it because AppWidgetHostView instantiates custom widgets in your context.

You can see from above that it is possible to write custom widget class to be used in AppWidget design only when you have permissions to access image files. This means either you work for a phone company or you make custom ROMs.