Put individual account inboxes in widget rotation

Change-Id: If1fddc107d9934849bbf273a67dd1db9c2063d99
This commit is contained in:
Marc Blank 2010-12-20 16:15:23 -08:00
parent ab1674a2d6
commit 66b6b95646
3 changed files with 110 additions and 45 deletions

View File

@ -32,7 +32,7 @@
android:layout_marginRight="5dip" android:layout_marginRight="5dip"
android:orientation="horizontal" android:orientation="horizontal"
android:paddingTop="4dip" android:paddingTop="4dip"
android:paddingLeft="16dip" android:paddingLeft="8dip"
android:paddingRight="8dip" android:paddingRight="8dip"
android:background="@drawable/header_bg_email_widget_holo"> android:background="@drawable/header_bg_email_widget_holo">
<ImageView <ImageView

View File

@ -996,14 +996,14 @@ save attachment.</string>
example="12">%2$s</xliff:g></string> example="12">%2$s</xliff:g></string>
<!-- Widget --> <!-- Widget -->
<!-- Instruction for how to move to different widget views [CHAR LIMIT=50] --> <!-- Instruction for how to move to different widget views [CHAR LIMIT=20] -->
<string name="widget_other_views">Tap icon to configure</string> <string name="widget_other_views">Tap icon to change</string>
<!-- Header for the "All Mail" widget view (showing all of the user's mail) [CHAR LIMIT=20] --> <!-- Header for the "All Mail" widget view (showing all of the user's mail) [CHAR LIMIT=20] -->
<string name="widget_all_mail">All Mail</string> <string name="widget_all_mail">Combined Inbox</string>
<!-- Header for the "Unread" widget view (showing all unread mail) [CHAR LIMIT=20] --> <!-- Header for the "Unread" widget view (showing all unread mail) [CHAR LIMIT=20] -->
<string name="widget_unread">All Unread</string> <string name="widget_unread">Unread</string>
<!-- Header for the "Starred" widget view (showing all starred mail) [CHAR LIMIT=20] --> <!-- Header for the "Starred" widget view (showing all starred mail) [CHAR LIMIT=20] -->
<string name="widget_starred">All Starred</string> <string name="widget_starred">Starred</string>
<!-- Shown when waiting for mail data to be loaded into the widget list view [CHAR LIMIT=20] --> <!-- Shown when waiting for mail data to be loaded into the widget list view [CHAR LIMIT=20] -->
<string name="widget_loading">Loading\u2026</string> <string name="widget_loading">Loading\u2026</string>

View File

@ -22,6 +22,8 @@ import com.android.email.Utility;
import com.android.email.activity.MessageCompose; import com.android.email.activity.MessageCompose;
import com.android.email.activity.Welcome; import com.android.email.activity.Welcome;
import com.android.email.data.ThrottlingCursorLoader; import com.android.email.data.ThrottlingCursorLoader;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.AccountColumns;
import com.android.email.provider.EmailContent.Mailbox; import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.Message; import com.android.email.provider.EmailContent.Message;
import com.android.email.provider.EmailContent.MessageColumns; import com.android.email.provider.EmailContent.MessageColumns;
@ -41,6 +43,7 @@ import android.database.Cursor;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.net.Uri; import android.net.Uri;
import android.net.Uri.Builder; import android.net.Uri.Builder;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
@ -93,7 +96,13 @@ public class WidgetProvider extends AppWidgetProvider {
private static final int TOTAL_COUNT_UNKNOWN = -1; private static final int TOTAL_COUNT_UNKNOWN = -1;
private static final int MAX_MESSAGE_LIST_COUNT = 25; private static final int MAX_MESSAGE_LIST_COUNT = 25;
private static final String SORT_DESCENDING = MessageColumns.TIMESTAMP + " DESC"; private static final String[] NO_ARGUMENTS = new String[0];
private static final String SORT_TIMESTAMP_DESCENDING = MessageColumns.TIMESTAMP + " DESC";
private static final String SORT_ID_ASCENDING = AccountColumns.ID + " ASC";
private static final String[] ID_NAME_PROJECTION = {Account.RECORD_ID, Account.DISPLAY_NAME};
private static final int ID_NAME_COLUMN_ID = 0;
private static final int ID_NAME_COLUMN_NAME = 1;
// Map holding our instantiated widgets, accessed by widget id // Map holding our instantiated widgets, accessed by widget id
private static HashMap<Integer, EmailWidget> sWidgetMap = new HashMap<Integer, EmailWidget>(); private static HashMap<Integer, EmailWidget> sWidgetMap = new HashMap<Integer, EmailWidget>();
@ -114,21 +123,24 @@ public class WidgetProvider extends AppWidgetProvider {
* mail; we rotate between them. Each ViewType is composed of a selection string and a title. * mail; we rotate between them. Each ViewType is composed of a selection string and a title.
*/ */
public enum ViewType { public enum ViewType {
ALL_MAIL(null, R.string.widget_all_mail), ALL_MAIL(null, NO_ARGUMENTS, R.string.widget_all_mail),
UNREAD(MessageColumns.FLAG_READ + "=0", R.string.widget_unread), UNREAD(MessageColumns.FLAG_READ + "=0", NO_ARGUMENTS, R.string.widget_unread),
STARRED(MessageColumns.FLAG_FAVORITE + "=1", R.string.widget_starred); STARRED(MessageColumns.FLAG_FAVORITE + "=1", NO_ARGUMENTS, R.string.widget_starred),
ACCOUNT(MessageColumns.ACCOUNT_KEY + "=?", new String[1], 0);
private final String selection; private final String selection;
private final String[] selectionArgs;
private final int titleResource; private final int titleResource;
private String title; private String title;
ViewType(String _selection, int _titleResource) { ViewType(String _selection, String[] _selectionArgs, int _titleResource) {
selection = _selection; selection = _selection;
selectionArgs = _selectionArgs;
titleResource = _titleResource; titleResource = _titleResource;
} }
public String getTitle(Context context) { public String getTitle(Context context) {
if (title == null) { if (title == null && titleResource != 0) {
title = context.getString(titleResource); title = context.getString(titleResource);
} }
return title; return title;
@ -151,7 +163,7 @@ public class WidgetProvider extends AppWidgetProvider {
private WidgetLoader mLoader; private WidgetLoader mLoader;
// The current view type (all mail, unread, or starred for now) // The current view type (all mail, unread, or starred for now)
private ViewType mViewType = ViewType.ALL_MAIL; private ViewType mViewType = ViewType.STARRED;
// The projection to be used by the WidgetLoader // The projection to be used by the WidgetLoader
public static final String[] WIDGET_PROJECTION = new String[] { public static final String[] WIDGET_PROJECTION = new String[] {
@ -190,7 +202,6 @@ public class WidgetProvider extends AppWidgetProvider {
sDefaultTextColor = res.getColor(R.color.widget_default_text_color); sDefaultTextColor = res.getColor(R.color.widget_default_text_color);
sLightTextColor = res.getColor(R.color.widget_light_text_color); sLightTextColor = res.getColor(R.color.widget_light_text_color);
sConfigureText = res.getString(R.string.widget_other_views); sConfigureText = res.getString(R.string.widget_other_views);
} }
} }
@ -201,8 +212,8 @@ public class WidgetProvider extends AppWidgetProvider {
*/ */
final class WidgetLoader extends ThrottlingCursorLoader { final class WidgetLoader extends ThrottlingCursorLoader {
protected WidgetLoader() { protected WidgetLoader() {
super(sContext, Message.CONTENT_URI, WIDGET_PROJECTION, mViewType.selection, null, super(sContext, Message.CONTENT_URI, WIDGET_PROJECTION, mViewType.selection,
SORT_DESCENDING); mViewType.selectionArgs, SORT_TIMESTAMP_DESCENDING);
registerListener(0, new OnLoadCompleteListener<Cursor>() { registerListener(0, new OnLoadCompleteListener<Cursor>() {
@Override @Override
public void onLoadComplete(Loader<Cursor> loader, Cursor cursor) { public void onLoadComplete(Loader<Cursor> loader, Cursor cursor) {
@ -224,51 +235,74 @@ public class WidgetProvider extends AppWidgetProvider {
sWidgetManager.notifyAppWidgetViewDataChanged(mWidgetId, R.id.message_list); sWidgetManager.notifyAppWidgetViewDataChanged(mWidgetId, R.id.message_list);
} }
}); });
startLoading();
new WidgetViewSwitcher(EmailWidget.this).execute();
} }
/** /**
* Convenience method that stops existing loading (if any), sets a (possibly new) * Stop any pending load, reset selection parameters, and start loading
* selection criterion, and starts loading * Must be called from the UI thread
* * @param viewType the current ViewType
* @param selection a valid query selection argument
*/ */
void startLoadingWithSelection(String selection) { private void load(ViewType viewType) {
reset(); reset();
setSelection(selection); setSelection(viewType.selection);
setSelectionArgs(viewType.selectionArgs);
startLoading(); startLoading();
} }
} }
/** /**
* Switch to the next widget view (cycles all -> unread -> starred) * Reset cursor and cursor count, notify widget that list data is invalid, and start loading
* with our current ViewType
*/ */
public void switchToNextView() { private void loadView() {
synchronized(mCursorLock) {
mCursorCount = TOTAL_COUNT_UNKNOWN;
mCursor = null;
sWidgetManager.notifyAppWidgetViewDataChanged(mWidgetId, R.id.message_list);
mLoader.load(mViewType);
}
}
/**
* Switch to the next widget view (all -> account1 -> ... -> account n -> unread -> starred)
* This must be called on a background thread
*/
public synchronized void switchToNextView() {
switch(mViewType) { switch(mViewType) {
// If we're in starred and there is more than one account, go to "all mail"
// Otherwise, fall through to the accounts themselves
case STARRED:
if (EmailContent.count(sContext, Account.CONTENT_URI) > 1) {
mViewType = ViewType.ALL_MAIL;
break;
}
//$FALL-THROUGH$
case ALL_MAIL: case ALL_MAIL:
mViewType = ViewType.UNREAD; ViewType.ACCOUNT.selectionArgs[0] = "0";
//$FALL-THROUGH$
case ACCOUNT:
// Find the next account (or, if none, default to UNREAD)
String idString = ViewType.ACCOUNT.selectionArgs[0];
Cursor c = sResolver.query(Account.CONTENT_URI, ID_NAME_PROJECTION, "_id>?",
new String[] {idString}, SORT_ID_ASCENDING);
try {
if (c.moveToFirst()) {
mViewType = ViewType.ACCOUNT;
mViewType.selectionArgs[0] = c.getString(ID_NAME_COLUMN_ID);
mViewType.title = c.getString(ID_NAME_COLUMN_NAME);
} else {
mViewType = ViewType.UNREAD;
}
} finally {
c.close();
}
break; break;
case UNREAD: case UNREAD:
mViewType = ViewType.STARRED; mViewType = ViewType.STARRED;
break; break;
case STARRED:
mViewType = ViewType.ALL_MAIL;
break;
} }
synchronized(mCursorLock) {
mCursorCount = TOTAL_COUNT_UNKNOWN;
invalidateCursorLocked();
mLoader.startLoadingWithSelection(mViewType.selection);
}
}
/**
* Invalidates the current cursor and tells the UI that the underlying data has changed.
* This method must be called while holding mCursorLock
*/
private void invalidateCursorLocked() {
mCursor = null;
sWidgetManager.notifyAppWidgetViewDataChanged(mWidgetId, R.id.message_list);
} }
/** /**
@ -599,6 +633,36 @@ public class WidgetProvider extends AppWidgetProvider {
} }
} }
/**
* Utility class to handle switching widget views; in the background, we access the database
* to determine account status, etc. In the foreground, we start up the Loader with new
* parameters
*/
public static class WidgetViewSwitcher extends AsyncTask<Void, Void, Void> {
private final EmailWidget mWidget;
public WidgetViewSwitcher(EmailWidget widget) {
mWidget = widget;
}
@Override
protected Void doInBackground(Void... params) {
// Don't use the "all mail" view if we've got 0 or 1 account
if (EmailContent.count(sContext, Account.CONTENT_URI) < 2) {
mWidget.switchToNextView();
}
return null;
}
@Override
protected void onPostExecute(Void param) {
if (isCancelled()) {
return;
}
mWidget.loadView();
}
}
/** /**
* We use the WidgetService for two purposes: * We use the WidgetService for two purposes:
* 1) To provide a widget factory for RemoteViews, and * 1) To provide a widget factory for RemoteViews, and
@ -634,7 +698,7 @@ public class WidgetProvider extends AppWidgetProvider {
String command = pathSegments.get(0); String command = pathSegments.get(0);
// Ignore unknown action names // Ignore unknown action names
try { try {
long arg1 = Long.parseLong(pathSegments.get(1)); final long arg1 = Long.parseLong(pathSegments.get(1));
if (COMMAND_NAME_VIEW_MESSAGE.equals(command)) { if (COMMAND_NAME_VIEW_MESSAGE.equals(command)) {
// "view", <message id>, <mailbox id> // "view", <message id>, <mailbox id>
final long mailboxId = Long.parseLong(pathSegments.get(2)); final long mailboxId = Long.parseLong(pathSegments.get(2));
@ -649,7 +713,8 @@ public class WidgetProvider extends AppWidgetProvider {
// "next_view", <widget id> // "next_view", <widget id>
EmailWidget widget = sWidgetMap.get((int)arg1); EmailWidget widget = sWidgetMap.get((int)arg1);
if (widget != null) { if (widget != null) {
widget.switchToNextView(); WidgetViewSwitcher switcher = new WidgetViewSwitcher(widget);
switcher.execute();
} }
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {