diff --git a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java index 867c12dbc..bc5d44b41 100644 --- a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java +++ b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java @@ -631,6 +631,10 @@ public abstract class EmailContent { public static final String ALL_UNREAD_SELECTION = MessageColumns.FLAG_READ + "=0 AND " + ALL_INBOX_SELECTION; + /** Selection to retrieve unread messages in "inbox" for one account */ + public static final String PER_ACCOUNT_UNREAD_SELECTION = + ACCOUNT_KEY_SELECTION + " AND " + ALL_UNREAD_SELECTION; + /** Selection to retrieve all messages in "inbox" for one account */ public static final String PER_ACCOUNT_INBOX_SELECTION = ACCOUNT_KEY_SELECTION + " AND " + ALL_INBOX_SELECTION; diff --git a/emailcommon/src/com/android/emailcommon/provider/Mailbox.java b/emailcommon/src/com/android/emailcommon/provider/Mailbox.java index 97f8195dc..3e007014a 100644 --- a/emailcommon/src/com/android/emailcommon/provider/Mailbox.java +++ b/emailcommon/src/com/android/emailcommon/provider/Mailbox.java @@ -531,4 +531,4 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns return new Mailbox[size]; } }; -} \ No newline at end of file +} diff --git a/src/com/android/email/provider/WidgetProvider.java b/src/com/android/email/provider/WidgetProvider.java index 0e20a76a1..12f7b3ce3 100644 --- a/src/com/android/email/provider/WidgetProvider.java +++ b/src/com/android/email/provider/WidgetProvider.java @@ -55,7 +55,7 @@ public class WidgetProvider extends AppWidgetProvider { Log.d(EmailWidget.TAG, "onUpdate"); } super.onUpdate(context, appWidgetManager, appWidgetIds); - WidgetManager.getInstance().getOrCreateWidgets(context, appWidgetIds); + WidgetManager.getInstance().createWidgets(context, appWidgetIds); } @Override diff --git a/src/com/android/email/service/EmailBroadcastProcessorService.java b/src/com/android/email/service/EmailBroadcastProcessorService.java index 24963fb55..07e10d89e 100644 --- a/src/com/android/email/service/EmailBroadcastProcessorService.java +++ b/src/com/android/email/service/EmailBroadcastProcessorService.java @@ -225,8 +225,5 @@ public class EmailBroadcastProcessorService extends IntentService { // If the exchange service wasn't already running, starting it will cause exchange account // reconciliation to be performed. The service stops itself it there are no EAS accounts. ExchangeUtils.startExchangeService(this); - - // Let all of the widgets update - WidgetManager.getInstance().updateAllWidgets(); } } diff --git a/src/com/android/email/widget/EmailWidget.java b/src/com/android/email/widget/EmailWidget.java index 18f028e1a..47045c19c 100644 --- a/src/com/android/email/widget/EmailWidget.java +++ b/src/com/android/email/widget/EmailWidget.java @@ -23,15 +23,16 @@ import com.android.email.activity.MessageCompose; import com.android.email.activity.UiUtilities; import com.android.email.activity.Welcome; import com.android.email.provider.WidgetProvider.WidgetService; +import com.android.emailcommon.provider.EmailContent.Account; +import com.android.emailcommon.provider.EmailContent.AccountColumns; import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.utility.EmailAsyncTask; -import com.android.emailcommon.utility.Utility; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; -import android.content.ContentUris; import android.content.Context; +import android.content.CursorLoader; import android.content.Intent; import android.content.Loader; import android.content.Loader.OnLoadCompleteListener; @@ -57,11 +58,8 @@ import java.util.List; /** * The email widget. - * - * Threading notes: - * - All methods must be called on the UI thread, except for {@link WidgetUpdater#doInBackground}. - * - {@link WidgetUpdater#doInBackground} must not read/write any members of {@link EmailWidget}. - * - (So no synchronizations are required in this class) + *

NOTE: All methods must be called on the UI thread so synchronization is NOT required + * in this class) */ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, OnLoadCompleteListener { @@ -90,16 +88,22 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, private static final Uri COMMAND_URI = Uri.parse("widget://command"); // Command names and Uri's built upon COMMAND_URI - private static final String COMMAND_NAME_SWITCH_LIST_VIEW = "switch_list_view"; - private static final Uri COMMAND_URI_SWITCH_LIST_VIEW = - COMMAND_URI.buildUpon().appendPath(COMMAND_NAME_SWITCH_LIST_VIEW).build(); private static final String COMMAND_NAME_VIEW_MESSAGE = "view_message"; private static final Uri COMMAND_URI_VIEW_MESSAGE = COMMAND_URI.buildUpon().appendPath(COMMAND_NAME_VIEW_MESSAGE).build(); private static final int MAX_MESSAGE_LIST_COUNT = 25; + // TODO Temporary selection / projection to pick the first account defined. Remove once the + // account / mailbox picker activity is added + private static final String SORT_ID_ASCENDING = AccountColumns.ID + " ASC"; + private static final String[] ID_NAME_PROJECTION = + { AccountColumns.ID, AccountColumns.DISPLAY_NAME }; + private static final int ID_NAME_COLUMN_ID = 0; + private static final int ID_NAME_COLUMN_NAME = 1; + private static String sSubjectSnippetDivider; + @SuppressWarnings("unused") private static String sConfigureText; private static int sSenderFontSize; private static int sSubjectFontSize; @@ -117,6 +121,10 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, private final EmailWidgetLoader mLoader; private final ResourceHelper mResourceHelper; + private long mAccountId = Account.NO_ACCOUNT; + private long mMailboxId = Mailbox.NO_MAILBOX; + private String mAccountName; + /** * The cursor for the messages, with some extra info such as the number of accounts. * @@ -125,9 +133,6 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, */ private EmailWidgetLoader.CursorWithCounts mCursor; - /** The current view type */ - /* package */ WidgetView mWidgetView = WidgetView.UNINITIALIZED_VIEW; - private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker(); public EmailWidget(Context context, int _widgetId) { @@ -158,9 +163,23 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, } public void start() { - // The default view is UNINITIALIZED_VIEW, and we switch to the next one, which should - // be the initial view. (the first view shown to the user.) - switchView(); + // TODO By default, pick an account to display the widget for. This should all be removed + // once the widget configuration activity is hooked up. + CursorLoader accountLoader = new CursorLoader( + mContext, Account.CONTENT_URI, ID_NAME_PROJECTION, null, null, SORT_ID_ASCENDING); + accountLoader.registerListener(1, new OnLoadCompleteListener() { + @Override + public void onLoadComplete(android.content.Loader loader, Cursor data) { + long accountId = Account.NO_ACCOUNT; + String accountName = null; + if (data != null && data.moveToFirst()) { + accountId = data.getLong(ID_NAME_COLUMN_ID); + accountName = data.getString(ID_NAME_COLUMN_NAME); + } + loadView(accountId, accountName); + } + }); + accountLoader.startLoading(); } private boolean isCursorValid() { @@ -174,7 +193,6 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, public void onLoadComplete(Loader loader, Cursor cursor) { // Save away the cursor mCursor = (EmailWidgetLoader.CursorWithCounts) cursor; - mWidgetView = mLoader.getLoadingWidgetView(); RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.widget); updateHeader(); @@ -187,25 +205,10 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, * Start loading the data. At this point nothing on the widget changes -- the current view * will remain valid until the loader loads the latest data. */ - private void loadView(WidgetView view) { - mLoader.load(view); - } - - /** - * Convenience method for creating an onClickPendingIntent that executes a command via - * our command Uri. Used for the "next view" command; appends the widget id to the command - * Uri. - * - * @param views The RemoteViews we're inflating - * @param buttonId the id of the button view - * @param data the command Uri - */ - private void setCommandIntent(RemoteViews views, int buttonId, Uri data) { - Intent intent = new Intent(mContext, WidgetService.class); - intent.setDataAndType(ContentUris.withAppendedId(data, mWidgetId), WIDGET_DATA_MIME_TYPE); - PendingIntent pendingIntent = PendingIntent.getService(mContext, 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT); - views.setOnClickPendingIntent(buttonId, pendingIntent); + private void loadView(long accountId, String accountName) { + mAccountId = accountId; + mAccountName = accountName; + mLoader.load(mAccountId, mMailboxId); } /** @@ -263,12 +266,6 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, if (EmailWidget.COMMAND_NAME_VIEW_MESSAGE.equals(command)) { // "view", , openMessage(context, Long.parseLong(pathSegments.get(2)), arg1); - } else if (EmailWidget.COMMAND_NAME_SWITCH_LIST_VIEW.equals(command)) { - // "next_view", - EmailWidget widget = WidgetManager.getInstance().get((int)arg1); - if (widget != null) { - widget.switchView(); - } } } catch (NumberFormatException e) { // Shouldn't happen as we construct all of the Uri's @@ -279,7 +276,7 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, private static void openMessage(final Context context, final long mailboxId, final long messageId) { - Utility.runAsync(new Runnable() { + EmailAsyncTask.runAsyncParallel(new Runnable() { @Override public void run() { Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId); @@ -292,8 +289,10 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, private void setupTitleAndCount(RemoteViews views) { // Set up the title (view type + count of messages) - views.setTextViewText(R.id.widget_title, mWidgetView.getTitle(mContext)); - views.setTextViewText(R.id.widget_tap, sConfigureText); + views.setTextViewText(R.id.widget_title, mAccountName); + // TODO Temporary UX; need to make this visible and create the correct UX + //views.setTextViewText(R.id.widget_tap, sConfigureText); + views.setViewVisibility(R.id.widget_tap, View.INVISIBLE); String count = ""; if (isCursorValid()) { count = UiUtilities.getMessageCountForUi(mContext, mCursor.getMessageCount(), false); @@ -317,11 +316,11 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, Intent intent = new Intent(mContext, WidgetService.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mWidgetId); intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); - views.setRemoteAdapter(mWidgetId, R.id.message_list, intent); + views.setRemoteAdapter(R.id.message_list, intent); setupTitleAndCount(views); - if (!isCursorValid() || mCursor.getAccountCount() == 0) { + if (!isCursorValid() || mAccountId == Account.NO_ACCOUNT) { // Hide compose icon & show "touch to configure" text views.setViewVisibility(R.id.widget_compose, View.INVISIBLE); views.setViewVisibility(R.id.message_list, View.GONE); @@ -338,8 +337,6 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, intent = MessageCompose.getMessageComposeIntent(mContext, -1); setActivityIntent(views, R.id.widget_compose, intent); } - // Create click intent for "view rotation" target - setCommandIntent(views, R.id.widget_logo, COMMAND_URI_SWITCH_LIST_VIEW); // Use a bare intent for our template; we need to fill everything in intent = new Intent(mContext, WidgetService.class); @@ -452,7 +449,7 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, views.setViewVisibility(R.id.widget_attachment, hasAttachment ? View.VISIBLE : View.GONE); - if (mCursor.getAccountCount() <= 1 || mWidgetView.isPerAccount()) { + if (mAccountId != Account.ACCOUNT_ID_COMBINED_VIEW) { views.setViewVisibility(R.id.color_chip, View.INVISIBLE); } else { long accountId = mCursor.getLong(EmailWidgetLoader.WIDGET_COLUMN_ACCOUNT_KEY); @@ -513,7 +510,6 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, if (mLoader != null) { mLoader.reset(); } - WidgetManager.getInstance().remove(mWidgetId); } @Override @@ -522,57 +518,14 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, mLoader.reset(); } mTaskTracker.cancellAllInterrupt(); - WidgetManager.getInstance().remove(mWidgetId); } @Override public void onCreate() { } - /** - * Update the widget. If the current view is invalid, switch to the next view, then update. - */ - /* package */ void validateAndUpdate() { - new WidgetUpdater(this, false).cancelPreviousAndExecuteParallel(); - } - - /** - * Switch to the next view. - */ - /* package */ void switchView() { - new WidgetUpdater(this, true).cancelPreviousAndExecuteParallel(); - } - - /** - * Update the widget. If {@code switchToNextView} is set true, or the current view is invalid, - * switch to the next view. - */ - private static class WidgetUpdater extends EmailAsyncTask { - private final EmailWidget mParent; - private final WidgetView mCurrentView; - private final boolean mSwitchToNextView; - - public WidgetUpdater(EmailWidget parent, boolean switchToNextView) { - super(parent.mTaskTracker); - mParent = parent; - mCurrentView = mParent.mWidgetView; - mSwitchToNextView = switchToNextView; - } - - @Override - protected WidgetView doInBackground(Void... params) { - if (mSwitchToNextView || !mCurrentView.isValid(mParent.mContext)) { - return mCurrentView.getNext(mParent.mContext); - } else { - return mCurrentView; // Reload the same view. - } - } - - @Override - protected void onPostExecute(WidgetView nextView) { - if (nextView != null) { - mParent.loadView(nextView); - } - } + @Override + public String toString() { + return "View=" + mAccountName; } } diff --git a/src/com/android/email/widget/EmailWidgetLoader.java b/src/com/android/email/widget/EmailWidgetLoader.java index b145f910b..ca818496f 100644 --- a/src/com/android/email/widget/EmailWidgetLoader.java +++ b/src/com/android/email/widget/EmailWidgetLoader.java @@ -18,9 +18,9 @@ package com.android.email.widget; import com.android.email.data.ThrottlingCursorLoader; import com.android.emailcommon.provider.EmailContent; -import com.android.emailcommon.provider.EmailContent.Account; import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.provider.EmailContent.MessageColumns; +import com.android.emailcommon.provider.Mailbox; import android.content.Context; import android.database.Cursor; @@ -35,7 +35,7 @@ import android.database.CursorWrapper; * It's currently just the same as the message count, but this will be updated to the unread * counts for inboxes. */ -/* package */ class EmailWidgetLoader extends ThrottlingCursorLoader { +class EmailWidgetLoader extends ThrottlingCursorLoader { private static final String SORT_TIMESTAMP_DESCENDING = MessageColumns.TIMESTAMP + " DESC"; // The projection to be used by the WidgetLoader @@ -57,23 +57,20 @@ import android.database.CursorWrapper; public static final int WIDGET_COLUMN_ACCOUNT_KEY = 9; public static final int WIDGET_COLUMN_FLAGS = 10; + private long mAccountId; + private long mMailboxId; + /** * The actual data returned by this loader. */ - public static class CursorWithCounts extends CursorWrapper { - private final int mAccountCount; + static class CursorWithCounts extends CursorWrapper { private final int mMessageCount; - public CursorWithCounts(Cursor cursor, int accountCount, int messageCount) { + public CursorWithCounts(Cursor cursor, int messageCount) { super(cursor); - mAccountCount = accountCount; mMessageCount = messageCount; } - public int getAccountCount() { - return mAccountCount; - } - /** * @return The count that should be shown on the widget header. * Note depending on the view, it may be the unread count, which is different from @@ -86,9 +83,7 @@ import android.database.CursorWrapper; private final Context mContext; - private WidgetView mLoadingWidgetView; - - public EmailWidgetLoader(Context context) { + EmailWidgetLoader(Context context) { super(context, Message.CONTENT_URI, WIDGET_PROJECTION, null, null, SORT_TIMESTAMP_DESCENDING); mContext = context; @@ -101,17 +96,17 @@ import android.database.CursorWrapper; // Reset the notification Uri to our Message table notifier URI messagesCursor.setNotificationUri(mContext.getContentResolver(), Message.NOTIFIER_URI); - final int accountCount = EmailContent.count(mContext, Account.CONTENT_URI); - final int messageCount; - if (mLoadingWidgetView.useUnreadCount()) { - messageCount = mLoadingWidgetView.getUnreadCount(mContext); + if (mMailboxId != Mailbox.QUERY_ALL_FAVORITES) { + String selection = "(" + getSelection() + " ) AND " + MessageColumns.FLAG_READ + " = 0"; + messageCount = EmailContent.count(mContext, Message.CONTENT_URI, selection, + getSelectionArgs()); } else { // Just use the number of all messages shown. messageCount = messagesCursor.getCount(); } - return new CursorWithCounts(messagesCursor, accountCount, messageCount); + return new CursorWithCounts(messagesCursor, messageCount); } /** @@ -119,22 +114,15 @@ import android.database.CursorWrapper; * * Must be called from the UI thread * - * @param view the current ViewType + * @param accountId + * @param mailboxId */ - public void load(WidgetView view) { + void load(long accountId, long mailboxId) { reset(); - mLoadingWidgetView = view; - setSelection(view.getSelection()); - setSelectionArgs(view.getSelectionArgs()); + mAccountId = accountId; + mMailboxId = mailboxId; + setSelection(Message.PER_ACCOUNT_UNREAD_SELECTION); + setSelectionArgs(new String[]{ Long.toString(mAccountId) }); startLoading(); } - - /** - * @return the {@link WidgetView} that is (being) loaded. - * - * Must be called from the UI thread - */ - public WidgetView getLoadingWidgetView() { - return mLoadingWidgetView; - } } diff --git a/src/com/android/email/widget/WidgetManager.java b/src/com/android/email/widget/WidgetManager.java index 20a890db6..fefa89394 100644 --- a/src/com/android/email/widget/WidgetManager.java +++ b/src/com/android/email/widget/WidgetManager.java @@ -43,19 +43,9 @@ public class WidgetManager { return sInstance; } - /** - * Updates all active widgets. If no widgets are active, does nothing. - */ - public synchronized void updateAllWidgets() { - for (EmailWidget widget: mWidgets.values()) { - // Anything could have changed; update widget & validate the current view - widget.validateAndUpdate(); - } - } - - public synchronized void getOrCreateWidgets(Context context, int[] widgetIds) { + public synchronized void createWidgets(Context context, int[] widgetIds) { for (int widgetId : widgetIds) { - getOrCreateWidget(context, widgetId).validateAndUpdate(); + getOrCreateWidget(context, widgetId); } } @@ -67,10 +57,11 @@ public class WidgetManager { // Stop loading and remove the widget from the map widget.onDeleted(); } + remove(widgetId); } } - public EmailWidget getOrCreateWidget(Context context, int widgetId) { + public synchronized EmailWidget getOrCreateWidget(Context context, int widgetId) { EmailWidget widget = WidgetManager.getInstance().get(widgetId); if (widget == null) { if (Email.DEBUG) { @@ -83,15 +74,15 @@ public class WidgetManager { return widget; } - public EmailWidget get(int widgetId) { + private EmailWidget get(int widgetId) { return mWidgets.get(widgetId); } - /* package */ void put(int widgetId, EmailWidget widget) { + private void put(int widgetId, EmailWidget widget) { mWidgets.put(widgetId, widget); } - /* package */ void remove(int widgetId) { + private void remove(int widgetId) { mWidgets.remove(widgetId); } @@ -99,7 +90,7 @@ public class WidgetManager { int n = 0; for (EmailWidget widget : mWidgets.values()) { writer.println("Widget #" + (++n)); - writer.println(" View=" + widget.mWidgetView); + writer.println(" " + widget.toString()); } } } diff --git a/src/com/android/email/widget/WidgetView.java b/src/com/android/email/widget/WidgetView.java deleted file mode 100644 index b913680da..000000000 --- a/src/com/android/email/widget/WidgetView.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.email.widget; - -import com.android.email.R; -import com.android.emailcommon.provider.EmailContent; -import com.android.emailcommon.provider.EmailContent.Account; -import com.android.emailcommon.provider.EmailContent.AccountColumns; -import com.android.emailcommon.provider.EmailContent.Message; -import com.android.emailcommon.provider.EmailContent.MessageColumns; -import com.android.emailcommon.utility.Utility; - -import android.content.ContentUris; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; - -/** - * Represents the "view" of the widget. - * - * It's a {@link ViewType} + mutable fields. (e.g. account id/name) - */ -/* package */ class WidgetView { - 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; - - private static enum ViewType { - TYPE_ALL_UNREAD(false, Message.ALL_UNREAD_SELECTION, R.string.widget_unread, false), - TYPE_ALL_STARRED(false, Message.ALL_FAVORITE_SELECTION, R.string.widget_starred, false), - TYPE_ALL_INBOX(false, Message.ALL_INBOX_SELECTION, R.string.widget_all_mail, true), - TYPE_ACCOUNT_INBOX(true, Message.PER_ACCOUNT_INBOX_SELECTION, 0, true) { - @Override public String getTitle(Context context, String accountName) { - return accountName; - } - - @Override public String[] getSelectionArgs(long accountId) { - return new String[]{Long.toString(accountId)}; - } - }; - - private final boolean mIsPerAccount; - private final String mSelection; - private final int mTitleResource; - private final boolean mUseUnreadCount; - - ViewType(boolean isPerAccount, String selection, int titleResource, - boolean useUnreadCount) { - mIsPerAccount = isPerAccount; - mSelection = selection; - mTitleResource = titleResource; - mUseUnreadCount = useUnreadCount; - } - - public String getTitle(Context context, String accountName) { - return context.getString(mTitleResource); - } - - public String getSelection() { - return mSelection; - } - - public String[] getSelectionArgs(long accountId) { - return null; - } - } - - /* package */ static final WidgetView ALL_UNREAD = new WidgetView(ViewType.TYPE_ALL_UNREAD); - /* package */ static final WidgetView ALL_STARRED = new WidgetView(ViewType.TYPE_ALL_STARRED); - /* package */ static final WidgetView ALL_INBOX = new WidgetView(ViewType.TYPE_ALL_INBOX); - - /** - * The initial view will be the *next* of ALL_STARRED -- see {@link #getNext}. - */ - public static final WidgetView UNINITIALIZED_VIEW = ALL_STARRED; - - private final ViewType mViewType; - /** Account ID -- set only when isPerAccount */ - private final long mAccountId; - /** Account name -- set only when isPerAccount */ - private final String mAccountName; - - private WidgetView(ViewType viewType) { - this(viewType, 0, null); - } - - private WidgetView(ViewType viewType, long accountId, String accountName) { - mViewType = viewType; - mAccountId = accountId; - mAccountName = accountName; - } - - public boolean isPerAccount() { - return mViewType.mIsPerAccount; - } - - public String getTitle(Context context) { - return mViewType.getTitle(context, mAccountName); - } - - public boolean useUnreadCount() { - return mViewType.mUseUnreadCount; - } - - public String getSelection() { - return mViewType.getSelection(); - } - - public String[] getSelectionArgs() { - return mViewType.getSelectionArgs(mAccountId); - } - - /** - * Switch to the "next" view. - * - * Views rotate in this order: - * - {@link #ALL_STARRED} - * - {@link #ALL_INBOX} -- this will be skipped if # of accounts <= 1 - * - Inbox for account 1 - * - Inbox for account 2 - * - : - * - {@link #ALL_UNREAD} - * - Go back to {@link #ALL_STARRED}. - * - * Note the initial view is always the next of {@link #ALL_STARRED}. - */ - public WidgetView getNext(Context context) { - if (mViewType == ViewType.TYPE_ALL_UNREAD) { - return ALL_STARRED; - } - if (mViewType == ViewType.TYPE_ALL_STARRED) { - // If we're in starred and there is more than one account, go to "all mail" - // Otherwise, fall through to the accounts themselves - if (EmailContent.count(context, Account.CONTENT_URI) > 1) { - return ALL_INBOX; - } - } - final long nextAccountIdStart; - if (mViewType == ViewType.TYPE_ALL_INBOX) { - nextAccountIdStart = -1; - } else { // TYPE_ACCOUNT_INBOX - nextAccountIdStart = mAccountId + 1; - } - Cursor c = context.getContentResolver().query(Account.CONTENT_URI, ID_NAME_PROJECTION, - "_id>=?", new String[] {Long.toString(nextAccountIdStart)}, SORT_ID_ASCENDING); - - final long nextAccountId; - final String nextAccountName; - try { - if (c.moveToFirst()) { - return new WidgetView(ViewType.TYPE_ACCOUNT_INBOX, c.getLong(ID_NAME_COLUMN_ID), - c.getString(ID_NAME_COLUMN_NAME)); - } else { - return ALL_UNREAD; - } - } finally { - c.close(); - } - } - - /** - * Returns whether the current view is valid. The following rules determine if a view is - * considered valid: - * 1. {@link ViewType#TYPE_ALL_STARRED} and {@link ViewType#TYPE_ALL_UNREAD} are always - * valid. - * 2. If the view is {@link ViewType#TYPE_ALL_INBOX}, returns true if more than - * one account is defined. Otherwise, returns false. - * 3. If the view is {@link ViewType#TYPE_ACCOUNT_INBOX}, returns true if the - * account is defined. Otherwise, returns false. - */ - public boolean isValid(Context context) { - switch(mViewType) { - case TYPE_ALL_INBOX: - // "all inbox" is valid only if there is more than one account - return (EmailContent.count(context, Account.CONTENT_URI) > 1); - case TYPE_ACCOUNT_INBOX: - // Ensure current account still exists - Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, mAccountId); - return Utility.getFirstRowLong(context, uri, - EmailContent.ID_PROJECTION, null, null, null, - EmailContent.ID_PROJECTION_COLUMN, null) != null; - } - return true; - } - - /** - * @return unread message count using the selection. - */ - public int getUnreadCount(Context context) { - String selection = "(" + getSelection() + " ) AND " + MessageColumns.FLAG_READ + " = 0"; - return EmailContent.count(context, Message.CONTENT_URI, selection, - getSelectionArgs()); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("WidgetView:type="); - sb.append(mViewType); - sb.append(" account="); - sb.append(mAccountId); - - return sb.toString(); - } -} diff --git a/tests/src/com/android/email/widget/WidgetViewTests.java b/tests/src/com/android/email/widget/WidgetViewTests.java deleted file mode 100644 index 6caec9042..000000000 --- a/tests/src/com/android/email/widget/WidgetViewTests.java +++ /dev/null @@ -1,227 +0,0 @@ -/* Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.email.widget; - -import com.android.email.provider.EmailProvider; -import com.android.email.provider.ProviderTestUtils; -import com.android.emailcommon.provider.EmailContent; -import com.android.emailcommon.provider.EmailContent.Account; -import com.android.emailcommon.provider.EmailContent.Message; -import com.android.emailcommon.provider.Mailbox; - -import android.content.Context; -import android.test.ProviderTestCase2; - -/** - * Tests of EmailWidget - * - * You can run this entire test case with: - * runtest -c com.android.email.widget.WidgetView email - */ -public class WidgetViewTests extends ProviderTestCase2 { - private Context mMockContext; - - public WidgetViewTests() { - super(EmailProvider.class, EmailContent.AUTHORITY); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - mMockContext = getMockContext(); - } - - @Override - public void tearDown() throws Exception { - super.tearDown(); - } - - private int getMessageCount(WidgetView view) { - return EmailContent.count(mMockContext, Message.CONTENT_URI, - view.getSelection(), view.getSelectionArgs()); - } - - private int getUnreadCount(WidgetView view) { - return view.getUnreadCount(mMockContext); - } - - private static Message createMessage(Context c, Mailbox b, boolean starred, boolean read, - int flagLoaded) { - Message message = ProviderTestUtils.setupMessage( - "1", b.mAccountKey, b.mId, true, false, c, starred, read); - message.mFlagLoaded = flagLoaded; - message.save(c); - return message; - } - - public void testGetNext() { - // Test with 1 account. - final Account a1 = ProviderTestUtils.setupAccount("account1", true, mMockContext); - - WidgetView view = WidgetView.ALL_UNREAD; - - // all unread -> all starred - view = view.getNext(mMockContext); - assertEquals(WidgetView.ALL_STARRED, view); - - // all starred -> account 1 inbox - view = view.getNext(mMockContext); - assertTrue(view.isPerAccount()); - assertEquals(Long.toString(a1.mId), view.getSelectionArgs()[0]); - - // account 1 inbox -> all unread - view = view.getNext(mMockContext); - assertEquals(WidgetView.ALL_UNREAD, view); - - // Next, test with 2 accounts. - final Account a2 = ProviderTestUtils.setupAccount("account2", true, mMockContext); - - // Still all unread - assertEquals(WidgetView.ALL_UNREAD, view); - - // all unread -> all starred - view = view.getNext(mMockContext); - assertEquals(WidgetView.ALL_STARRED, view); - - // all starred -> all inboxes, as there are more than 1 account. - view = view.getNext(mMockContext); - assertEquals(WidgetView.ALL_INBOX, view); - - // all inbox -> account 1 inbox - view = view.getNext(mMockContext); - assertTrue(view.isPerAccount()); - assertEquals(Long.toString(a1.mId), view.getSelectionArgs()[0]); - - // account 1 inbox -> account 2 inbox - view = view.getNext(mMockContext); - assertTrue(view.isPerAccount()); - assertEquals(Long.toString(a2.mId), view.getSelectionArgs()[0]); - - // account 2 inbox -> all unread - view = view.getNext(mMockContext); - assertEquals(WidgetView.ALL_UNREAD, view); - } - - public void testIsValid() { - // with 0 accounts - assertTrue(WidgetView.ALL_UNREAD.isValid(mMockContext)); - assertTrue(WidgetView.ALL_STARRED.isValid(mMockContext)); - assertFalse(WidgetView.ALL_INBOX.isValid(mMockContext)); - - // Test with 1 account. - final Account a1 = ProviderTestUtils.setupAccount("account1", true, mMockContext); - assertTrue(WidgetView.ALL_UNREAD.isValid(mMockContext)); - assertTrue(WidgetView.ALL_STARRED.isValid(mMockContext)); - assertFalse(WidgetView.ALL_INBOX.isValid(mMockContext)); // only 1 account -- still invalid - - final WidgetView account1View = WidgetView.ALL_INBOX.getNext(mMockContext); - assertEquals(Long.toString(a1.mId), account1View.getSelectionArgs()[0]); - assertTrue(account1View.isValid(mMockContext)); - - // Test with 2 accounts. - final Account a2 = ProviderTestUtils.setupAccount("account2", true, mMockContext); - assertTrue(WidgetView.ALL_UNREAD.isValid(mMockContext)); - assertTrue(WidgetView.ALL_STARRED.isValid(mMockContext)); - assertTrue(WidgetView.ALL_INBOX.isValid(mMockContext)); // now it's valid - - final WidgetView account2View = account1View.getNext(mMockContext); - assertEquals(Long.toString(a2.mId), account2View.getSelectionArgs()[0]); - assertTrue(account2View.isValid(mMockContext)); - - // Remove account 1 - ProviderTestUtils.deleteAccount(mMockContext, a1.mId); - - assertTrue(WidgetView.ALL_UNREAD.isValid(mMockContext)); - assertTrue(WidgetView.ALL_STARRED.isValid(mMockContext)); - assertFalse(WidgetView.ALL_INBOX.isValid(mMockContext)); // only 1 account -- now invalid - - assertFalse(account1View.isValid(mMockContext)); - assertTrue(account2View.isValid(mMockContext)); - - // Remove account 2 - ProviderTestUtils.deleteAccount(mMockContext, a2.mId); - - assertTrue(WidgetView.ALL_UNREAD.isValid(mMockContext)); - assertTrue(WidgetView.ALL_STARRED.isValid(mMockContext)); - assertFalse(WidgetView.ALL_INBOX.isValid(mMockContext)); // still invalid - - assertFalse(account1View.isValid(mMockContext)); - assertFalse(account2View.isValid(mMockContext)); - } - - /** - * Test the message counts returned by the ViewType selectors. - */ - public void testCursorCount() { - // Create 2 accounts - Account a1 = ProviderTestUtils.setupAccount("account1", true, mMockContext); - Account a2 = ProviderTestUtils.setupAccount("account2", true, mMockContext); - - // Create 2 mailboxes for each account - Mailbox b11 = ProviderTestUtils.setupMailbox( - "box11", a1.mId, true, mMockContext, Mailbox.TYPE_INBOX); - Mailbox b12 = ProviderTestUtils.setupMailbox( - "box12", a1.mId, true, mMockContext, Mailbox.TYPE_OUTBOX); - Mailbox b21 = ProviderTestUtils.setupMailbox( - "box21", a2.mId, true, mMockContext, Mailbox.TYPE_INBOX); - Mailbox b22 = ProviderTestUtils.setupMailbox( - "box22", a2.mId, true, mMockContext, Mailbox.TYPE_OUTBOX); - Mailbox b2t = ProviderTestUtils.setupMailbox( - "box2T", a2.mId, true, mMockContext, Mailbox.TYPE_TRASH); - - // Create some messages - // b11 (account 1, inbox): 2 messages - // star read - Message m11a = createMessage(mMockContext, b11, true, false, Message.FLAG_LOADED_COMPLETE); - Message m11b = createMessage(mMockContext, b11, false, false, Message.FLAG_LOADED_UNLOADED); - - // b12 (account 1, outbox): 2 messages - Message m12a = createMessage(mMockContext, b12, false, false, Message.FLAG_LOADED_COMPLETE); - Message m12b = createMessage(mMockContext, b12, true, true, Message.FLAG_LOADED_COMPLETE); - - // b21 (account 2, inbox): 4 messages - Message m21a = createMessage(mMockContext, b21, false, false, Message.FLAG_LOADED_COMPLETE); - Message m21b = createMessage(mMockContext, b21, false, true, Message.FLAG_LOADED_COMPLETE); - Message m21c = createMessage(mMockContext, b21, true, true, Message.FLAG_LOADED_COMPLETE); - Message m21d = createMessage(mMockContext, b21, true, true, Message.FLAG_LOADED_UNLOADED); - - // b22 (account 2, outbox) has no messages. - - // bt (account 2, trash): 3 messages - Message mt1 = createMessage(mMockContext, b2t, true, false, Message.FLAG_LOADED_COMPLETE); - Message mt2 = createMessage(mMockContext, b2t, true, true, Message.FLAG_LOADED_COMPLETE); - Message mt3 = createMessage(mMockContext, b2t, false, false, Message.FLAG_LOADED_COMPLETE); - - assertEquals(4, getMessageCount(WidgetView.ALL_INBOX)); - assertEquals(2, getUnreadCount(WidgetView.ALL_INBOX)); - - assertEquals(3, getMessageCount(WidgetView.ALL_STARRED)); - assertEquals(1, getUnreadCount(WidgetView.ALL_STARRED)); - - assertEquals(2, getMessageCount(WidgetView.ALL_UNREAD)); - assertEquals(2, getUnreadCount(WidgetView.ALL_UNREAD)); - - final WidgetView account1View = WidgetView.ALL_INBOX.getNext(mMockContext); - assertEquals(Long.toString(a1.mId), account1View.getSelectionArgs()[0]); - assertEquals(1, getMessageCount(account1View)); - assertEquals(1, getUnreadCount(account1View)); - - final WidgetView account2View = account1View.getNext(mMockContext); - assertEquals(Long.toString(a2.mId), account2View.getSelectionArgs()[0]); - assertEquals(3, getMessageCount(account2View)); - assertEquals(1, getUnreadCount(account2View)); - } -}