Put individual account inboxes in widget rotation
Change-Id: If1fddc107d9934849bbf273a67dd1db9c2063d99
This commit is contained in:
parent
ab1674a2d6
commit
66b6b95646
@ -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
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user