Live folders, introduced in Android 1.5 (API Level 3), let you display any source of data
on the Home screen without forcing the user to launch an application. A live
folder is simply a real-time view of a ContentProvider
.
As such, a live folder can be used to display all of the user's contacts or
bookmarks, email, playlists, an RSS feed, and so on. The possibilities are
endless!
The platform includes several standard folders for displaying contacts. For instance, the screenshot below shows the content of the live folders that displays all contacts with a phone number:
If a contacts sync happens in the background while the user is browsing this live folder, the user will see the change happen in real-time. Live folders are not only useful, but they are also easy to add to to your application and data. This articles shows how to add a live folder to an example application called Shelves. To better understand how live folders work, you can download the source code of the application and modify it by following the instructions below.
To give the user the option to create a new live folder for an application,
you first need to create a new activity with an intent filter whose action is
android.intent.action.CREATE_LIVE_FOLDER
. To do so, simply open
AndroidManifest.xml
and add something similar to this:
<activity android:name=".activity.BookShelfLiveFolder" android:label="BookShelf"> <intent-filter> <action android:name="android.intent.action.CREATE_LIVE_FOLDER" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
The label and icon of this activity are what the user will see on the Home screen when choosing a live folder to create:
Since you just need an intent filter, it is possible, and sometimes advised,
to reuse an existing activity. In the case of Shelves, we will create a new
activity, org.curiouscreature.android.shelves.activity.BookShelfLiveFolder
.
The role of this activity is to send an Intent
result to Home
containing the description of the live folder: its name, icon, display mode and
content URI. The content URI is very important as it describes what
ContentProvider
will be used to populate the live folder. The code
of the activity is very simple as you can see here:
public class BookShelfLiveFolder extends Activity { public static final Uri CONTENT_URI = Uri.parse("content://shelves/live_folders/books"); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Intent intent = getIntent(); final String action = intent.getAction(); if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) { setResult(RESULT_OK, createLiveFolder(this, CONTENT_URI, "Books", R.drawable.ic_live_folder)); } else { setResult(RESULT_CANCELED); } finish(); } private static Intent createLiveFolder(Context context, Uri uri, String name, int icon) { final Intent intent = new Intent(); intent.setData(uri); intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name); intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON, Intent.ShortcutIconResource.fromContext(context, icon)); intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE, LiveFolders.DISPLAY_MODE_LIST); return intent; } }
This activity, when invoked with theACTION_CREATE_LIVE_FOLDER
intent, returns an intent with a URI,
content://shelves/live_folders/books
, and three extras to describe
the live folder. There are other extras and constants you can use and you should
refer to the documentation of android.provider.LiveFolders
for more
details. When Home receives this intent, a new live folder is created on the
user's desktop, with the name and icon you provided. Then, when the user clicks
on the live folder to open it, Home queries the content provider referenced by
the provided URI.
Live folders' content providers must obey specific naming rules. The
Cursor
returned by the query()
method must have at
least two columns named LiveFolders._ID
and
LiveFolders.NAME
. The first one is the unique identifier of each
item in the live folder and the second one is the name of the item. There are
other column names you can use to specify an icon, a description, the intent to
associate with the item (fired when the user clicks that item), etc. Again,
refer to the documentation of android.provider.LiveFolders
for more
details.
In our example, all we need to do is modify the existing provider
in Shelves called
org.curiouscreature.android.shelves.provider.BooksProvider
. First,
we need to modify the URI_MATCHER
to recognize our
content://shelves/live_folders/books
content URI:
private static final int LIVE_FOLDER_BOOKS = 4; // ... URI_MATCHER.addURI(AUTHORITY, "live_folders/books", LIVE_FOLDER_BOOKS);
Then we need to create a new projection map for the cursor. A projection map
can be used to "rename" columns. In our case, we will replace
BooksStore.Book._ID
, BooksStore.Book.TITLE
and
BooksStore.Book.AUTHORS
with LiveFolders._ID
,
LiveFolders.TITLE
and LiveFolders.DESCRIPTION
:
private static final HashMap<string, string=""> LIVE_FOLDER_PROJECTION_MAP; static { LIVE_FOLDER_PROJECTION_MAP = new HashMap<string, string="">(); LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders._ID, BooksStore.Book._ID + " AS " + LiveFolders._ID); LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.NAME, BooksStore.Book.TITLE + " AS " + LiveFolders.NAME); LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.DESCRIPTION, BooksStore.Book.AUTHORS + " AS " + LiveFolders.DESCRIPTION); }
Because we are providing a title and a description for each row, Home will
automatically display each item of the live folder with two lines of text.
Finally, we implement the query()
method by supplying our
projection map to the SQL query builder:
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); switch (URI_MATCHER.match(uri)) { // ... case LIVE_FOLDER_BOOKS: qb.setTables("books"); qb.setProjectionMap(LIVE_FOLDER_PROJECTION_MAP); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } SQLiteDatabase db = mOpenHelper.getReadableDatabase(); Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, BooksStore.Book.DEFAULT_SORT_ORDER); c.setNotificationUri(getContext().getContentResolver(), uri); return c; }
You can now compile and deploy the application, go to the Home screen and try to add a live folder. You can add a books live folder to your Home screen and when you open it, see the list of all of your books, with their titles and authors, and all it took was a few lines of code:
The live folders API is extremely simple and relies only on intents and content URI. If you want to see more examples of live folders implementation, you can read the source code of the Contacts application and of the Contacts provider.
You can also download the result of our exercise, the modified version of Shelves with live folders support.