/******************************************************************************* * Copyright (C) 2012 Google Inc. * Licensed to 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.mail.ui; import android.app.ActionBar; import android.app.ActionBar.LayoutParams; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.LoaderManager; import android.content.ContentResolver; import android.content.Context; import android.content.CursorLoader; import android.content.DialogInterface; import android.content.Intent; import android.content.Loader; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.text.TextUtils; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import com.android.mail.ConversationListContext; import com.android.mail.R; import com.android.mail.browse.ConversationCursor; import com.android.mail.browse.SelectedConversationsActionMenu; import com.android.mail.browse.ConversationCursor.ConversationListener; import com.android.mail.compose.ComposeActivity; import com.android.mail.providers.Account; import com.android.mail.providers.Conversation; import com.android.mail.providers.Folder; import com.android.mail.providers.MailAppProvider; import com.android.mail.providers.Settings; import com.android.mail.providers.UIProvider; import com.android.mail.providers.UIProvider.AutoAdvance; import com.android.mail.providers.UIProvider.ConversationColumns; import com.android.mail.providers.UIProvider.FolderCapabilities; import com.android.mail.utils.LogUtils; import com.android.mail.utils.Utils; import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Set; /** * This is an abstract implementation of the Activity Controller. This class * knows how to respond to menu items, state changes, layout changes, etc. It * weaves together the views and listeners, dispatching actions to the * respective underlying classes. *
* Even though this class is abstract, it should provide default implementations * for most, if not all the methods in the ActivityController interface. This * makes the task of the subclasses easier: OnePaneActivityController and * TwoPaneActivityController can be concise when the common functionality is in * AbstractActivityController. *
** In the Gmail codebase, this was called BaseActivityController *
*/ public abstract class AbstractActivityController implements ActivityController, ConversationListener { // Keys for serialization of various information in Bundles. private static final String SAVED_ACCOUNT = "saved-account"; private static final String SAVED_FOLDER = "saved-folder"; private static final String SAVED_CONVERSATION = "saved-conversation"; // Batch conversations stored in the Bundle using this key. private static final String SAVED_CONVERSATIONS = "saved-conversations"; /** Are we on a tablet device or not. */ public final boolean IS_TABLET_DEVICE; protected Account mAccount; protected Folder mFolder; protected ActionBarView mActionBarView; protected final RestrictedActivity mActivity; protected final Context mContext; protected final RecentFolderList mRecentFolderList; protected ConversationListContext mConvListContext; protected Conversation mCurrentConversation; /** A {@link android.content.BroadcastReceiver} that suppresses new e-mail notifications. */ private SuppressNotificationReceiver mNewEmailReceiver = null; protected Handler mHandler = new Handler(); protected ConversationListFragment mConversationListFragment; private SelectedConversationsActionMenu mSelectedConversationsActionMenu; /** * The current mode of the application. All changes in mode are initiated by * the activity controller. View mode changes are propagated to classes that * attach themselves as listeners of view mode changes. */ protected final ViewMode mViewMode; protected ContentResolver mResolver; protected FolderListFragment mFolderListFragment; protected ConversationViewFragment mConversationViewFragment; protected boolean isLoaderInitialized = false; private AsyncRefreshTask mAsyncRefreshTask; private final Set
* A simple null check before restarting a loader will not work, because that would not
* give the controller a chance to invalidate UI corresponding the prior loader result.
*
* @param id loader ID to safely restart
* @param args arguments to pass to the restarted loader
*/
private void restartOptionalLoader(int id, Bundle args) {
final LoaderManager lm = mActivity.getLoaderManager();
lm.destroyLoader(id);
lm.restartLoader(id, args, this);
}
private boolean accountsUpdated(Cursor accountCursor) {
// Check to see if the current account hasn't been set, or the account cursor is empty
if (mAccount == null || !accountCursor.moveToFirst()) {
return true;
}
// Check to see if the number of accounts are different, from the number we saw on the last
// updated
if (mCurrentAccountUris.size() != accountCursor.getCount()) {
return true;
}
// Check to see if the account list is different or if the current account is not found in
// the cursor.
boolean foundCurrentAccount = false;
do {
final Uri accountUri =
Uri.parse(accountCursor.getString(UIProvider.ACCOUNT_URI_COLUMN));
if (!foundCurrentAccount && mAccount.uri.equals(accountUri)) {
foundCurrentAccount = true;
}
if (!mCurrentAccountUris.contains(accountUri)) {
return true;
}
} while (accountCursor.moveToNext());
// As long as we found the current account, the list hasn't been updated
return !foundCurrentAccount;
}
/**
* Update the accounts on the device. This currently loads the first account
* in the list.
*
* @param loader
* @param accounts cursor into the AccountCache
* @return true if the update was successful, false otherwise
*/
private boolean updateAccounts(Loader