14a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal/******************************************************************************* 24a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * Copyright (C) 2012 Google Inc. 34a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * Licensed to The Android Open Source Project. 44a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * 54a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * Licensed under the Apache License, Version 2.0 (the "License"); 64a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * you may not use this file except in compliance with the License. 74a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * You may obtain a copy of the License at 84a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * 94a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * http://www.apache.org/licenses/LICENSE-2.0 104a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * 114a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * Unless required by applicable law or agreed to in writing, software 124a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * distributed under the License is distributed on an "AS IS" BASIS, 134a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 144a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * See the License for the specific language governing permissions and 154a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal * limitations under the License. 164a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal *******************************************************************************/ 174a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal 184a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwalpackage com.android.mail.ui; 194a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal 2012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huangimport android.animation.ValueAnimator; 21a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.app.Activity; 2254452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwalimport android.app.AlertDialog; 23a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.app.Dialog; 2400179f19e413461498599ab7e6eb6914cc5c3671Andrew Sappersteinimport android.app.DialogFragment; 256902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwalimport android.app.Fragment; 262d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrookimport android.app.FragmentManager; 27f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huangimport android.app.LoaderManager; 28e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.app.SearchManager; 29839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huangimport android.content.ContentProviderOperation; 3080aeac5356b5a14a5ef2aff8f0f72a464c9a3cb4Vikram Aggarwalimport android.content.ContentResolver; 316c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereiraimport android.content.ContentValues; 32a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.content.Context; 3354452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwalimport android.content.DialogInterface; 346cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwalimport android.content.DialogInterface.OnClickListener; 35a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.content.Intent; 367dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwalimport android.content.Loader; 3757246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrookimport android.content.res.Configuration; 38bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwalimport android.content.res.Resources; 39ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yangimport android.database.Cursor; 40632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.database.DataSetObservable; 41632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.database.DataSetObserver; 4261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huangimport android.database.Observable; 4323b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrookimport android.net.Uri; 4427d89ada3e8d1b17357a7064e1f47f3c15686412Vikram Aggarwalimport android.os.AsyncTask; 45a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.os.Bundle; 4621ab490d4919985d611bc36ae2d8aea86a911499Mindy Pereiraimport android.os.Handler; 47f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedyimport android.os.Parcelable; 481a864cce6321f46031d6cd43e205278d0f219f92Jin Caoimport android.os.SystemClock; 49c6801eb828627c37b8992584767c095dfe11df62Jin Caoimport android.speech.RecognizerIntent; 5012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huangimport android.support.v4.widget.DrawerLayout; 5152882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sappersteinimport android.support.v7.app.ActionBar; 52355dd90d120bc105f5ad37aa5a5c7449e665a566Andrew Sappersteinimport android.support.v7.app.ActionBarDrawerToggle; 5312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huangimport android.view.Gravity; 54a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.view.KeyEvent; 55a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.view.Menu; 5628d5f72e0ad0db75b6243ee8125bfe3aadbdcb85Mindy Pereiraimport android.view.MenuInflater; 57a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.view.MenuItem; 58a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.view.MotionEvent; 59d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereiraimport android.view.View; 6012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huangimport android.widget.ListView; 61fd0c2974af56ad244006faab2651e054974a4b7bMindy Pereiraimport android.widget.Toast; 62a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 63b9e1a353c6a173a2885642dbcc1939f3281f29f7Vikram Aggarwalimport com.android.mail.ConversationListContext; 6459f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwalimport com.android.mail.MailLogService; 65f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huangimport com.android.mail.R; 66761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huangimport com.android.mail.analytics.Analytics; 67779dd6012a6c5b4d71255085059e57d94eab1a3fJin Caoimport com.android.mail.analytics.AnalyticsTimer; 686cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwalimport com.android.mail.browse.ConfirmDialogFragment; 69967ede63e059810d9d4d425c50111d606014c893Mindy Pereiraimport com.android.mail.browse.ConversationCursor; 707c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Huimport com.android.mail.browse.ConversationCursor.ConversationOperation; 71ca87de41285bde382a894b6cb2d13c112c5d7a2fmindypimport com.android.mail.browse.ConversationItemViewModel; 728812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport com.android.mail.browse.ConversationMessage; 7387a8982af83168453b6dc219fe984bff68047bebAndy Huangimport com.android.mail.browse.ConversationPagerAdapter; 74bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrookimport com.android.mail.browse.ConversationPagerController; 757c9f6acdf2b992fecaf0b3ad0afe9ec30ec86f33Marc Blankimport com.android.mail.browse.SelectedConversationsActionMenu; 76991f453c8905ec683458f8b4ea0e2737832425d9Andy Huangimport com.android.mail.browse.SyncErrorDialogFragment; 7730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Caoimport com.android.mail.browse.UndoCallback; 789b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereiraimport com.android.mail.compose.ComposeActivity; 79177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwalimport com.android.mail.content.CursorCreator; 80177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwalimport com.android.mail.content.ObjectCursor; 81177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwalimport com.android.mail.content.ObjectCursorLoader; 821ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwalimport com.android.mail.providers.Account; 839b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereiraimport com.android.mail.providers.Conversation; 84839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huangimport com.android.mail.providers.ConversationInfo; 854a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwalimport com.android.mail.providers.Folder; 867a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwalimport com.android.mail.providers.FolderWatcher; 87c2074c4442eacf5604dd3cecd06b363e8fc574dePaul Westbrookimport com.android.mail.providers.MailAppProvider; 88dac00547ce8d44a964e4510315168ee413e55a75Mindy Pereiraimport com.android.mail.providers.Settings; 8980aeac5356b5a14a5ef2aff8f0f72a464c9a3cb4Vikram Aggarwalimport com.android.mail.providers.UIProvider; 903cb28b5e1598f74dedbdb87b187d9bd7e132ff0fMindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities; 912388c5d208acd4e4e658aaacbbc5f080ee8e9f7cPaul Westbrookimport com.android.mail.providers.UIProvider.AccountCursorExtraKeys; 920d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedyimport com.android.mail.providers.UIProvider.AutoAdvance; 93c9d59184da271d5a6974edb709e3b39a5a970fa7Mindy Pereiraimport com.android.mail.providers.UIProvider.ConversationColumns; 945109c516b5cac279b4f99271953a27dd9a4828d8Paul Westbrookimport com.android.mail.providers.UIProvider.ConversationOperations; 9554452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwalimport com.android.mail.providers.UIProvider.FolderCapabilities; 96a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedyimport com.android.mail.providers.UIProvider.FolderType; 97c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sappersteinimport com.android.mail.ui.ActionableToastBar.ActionClickedListener; 98839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huangimport com.android.mail.utils.ContentProviderTask; 99144bfe739b93afdee0a1700a34806b0b287e5887Andy Huangimport com.android.mail.utils.DrawIdler; 100b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag; 1015cb0c3e684150d6d8ed4d9df4fb73a7606086aaaMindy Pereiraimport com.android.mail.utils.LogUtils; 10261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huangimport com.android.mail.utils.MailObservable; 103cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedyimport com.android.mail.utils.NotificationActionUtils; 104fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwalimport com.android.mail.utils.Utils; 10569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwalimport com.android.mail.utils.VeiledAddressMatcher; 106ca08fc170ca3f04572af8999645d5fd9e0bdb725Paul Westbrookimport com.google.common.base.Objects; 10777eee625cd8c317c605acfd06cd3a7e22120a0fdPaul Westbrookimport com.google.common.collect.ImmutableList; 108acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereiraimport com.google.common.collect.Lists; 109167faa8584750e37781f22ad7e6d61003029f954Marc Blankimport com.google.common.collect.Sets; 1104a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal 111167faa8584750e37781f22ad7e6d61003029f954Marc Blankimport java.util.ArrayList; 1129e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huangimport java.util.Arrays; 113fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereiraimport java.util.Collection; 114839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huangimport java.util.Collections; 1158db7e407109532557718c6b8064792f2df7a073dMindy Pereiraimport java.util.HashMap; 116cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwalimport java.util.List; 11723b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrookimport java.util.Set; 118bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blankimport java.util.TimerTask; 11923b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 12023b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 1214a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal/** 122161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * This is an abstract implementation of the Activity Controller. This class 123161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * knows how to respond to menu items, state changes, layout changes, etc. It 124161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * weaves together the views and listeners, dispatching actions to the 125161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * respective underlying classes. 126161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * <p> 127161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * Even though this class is abstract, it should provide default implementations 128161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * for most, if not all the methods in the ActivityController interface. This 129161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * makes the task of the subclasses easier: OnePaneActivityController and 130161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * TwoPaneActivityController can be concise when the common functionality is in 131161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * AbstractActivityController. 132161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * </p> 133a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * <p> 134161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * In the Gmail codebase, this was called BaseActivityController 135161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * </p> 1364a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal */ 137ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sappersteinpublic abstract class AbstractActivityController implements ActivityController, 1385d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux EmptyFolderDialogFragment.EmptyFolderDialogFragmentListener, View.OnClickListener { 1391ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal // Keys for serialization of various information in Bundles. 140cabd3f227bf97159774e246ad278bb49d4aa2badVikram Aggarwal /** Tag for {@link #mAccount} */ 1416c51158ad3269f157424e6c7bd488425c98da08fVikram Aggarwal private static final String SAVED_ACCOUNT = "saved-account"; 142cabd3f227bf97159774e246ad278bb49d4aa2badVikram Aggarwal /** Tag for {@link #mFolder} */ 1435e478d2c4087b50764756b0edc95941cb6094f68Mindy Pereira private static final String SAVED_FOLDER = "saved-folder"; 144cabd3f227bf97159774e246ad278bb49d4aa2badVikram Aggarwal /** Tag for {@link #mCurrentConversation} */ 14526f23fc8cc0d49bc0bea1eeec4c0c4742928f693Mindy Pereira private static final String SAVED_CONVERSATION = "saved-conversation"; 146ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao /** Tag for {@link #mCheckedSet} */ 147cabd3f227bf97159774e246ad278bb49d4aa2badVikram Aggarwal private static final String SAVED_SELECTED_SET = "saved-selected-set"; 148649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal /** Tag for {@link ActionableToastBar#getOperation()} */ 149d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira private static final String SAVED_TOAST_BAR_OP = "saved-toast-bar-op"; 150649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal /** Tag for {@link #mFolderListFolder} */ 151649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal private static final String SAVED_HIERARCHICAL_FOLDER = "saved-hierarchical-folder"; 152f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal /** Tag for {@link ConversationListContext#searchQuery} */ 153f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal private static final String SAVED_QUERY = "saved-query"; 1546cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal /** Tag for {@link #mDialogAction} */ 1556cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal private static final String SAVED_ACTION = "saved-action"; 156b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal /** Tag for {@link #mDialogFromSelectedSet} */ 157b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal private static final String SAVED_ACTION_FROM_SELECTED = "saved-action-from-selected"; 158a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal /** Tag for {@link #mDetachedConvUri} */ 159a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal private static final String SAVED_DETACHED_CONV_URI = "saved-detached-conv-uri"; 160ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang /** Key to store {@link #mInbox}. */ 161f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy private static final String SAVED_INBOX_KEY = "m-inbox"; 162f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy /** Key to store {@link #mConversationListScrollPositions} */ 163f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy private static final String SAVED_CONVERSATION_LIST_SCROLL_POSITIONS = 164f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy "saved-conversation-list-scroll-positions"; 1655cb0c3e684150d6d8ed4d9df4fb73a7606086aaaMindy Pereira 166ede2e52e725abc625ae963f979639ff8ecc40cf5Greg Bullock /** Tag used when loading a wait fragment */ 1676902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal protected static final String TAG_WAIT = "wait-fragment"; 1686902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal /** Tag used when loading a conversation list fragment. */ 169bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook public static final String TAG_CONVERSATION_LIST = "tag-conversation-list"; 170103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy /** Tag used when loading a custom fragment. */ 171103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy protected static final String TAG_CUSTOM_FRAGMENT = "tag-custom-fragment"; 1726902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal 173a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal /** Key to store an account in a bundle */ 174a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal private final String BUNDLE_ACCOUNT_KEY = "account"; 175a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal /** Key to store a folder in a bundle */ 176a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal private final String BUNDLE_FOLDER_KEY = "folder"; 1775bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein /** 1785bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein * Key to set a flag for the ConversationCursorLoader to ignore any 1795bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein * initial load limit that may be set by the Account. Instead, 1805bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein * perform a full load instead of the full-stage load. 1815bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein */ 1825bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein private final String BUNDLE_IGNORE_INITIAL_CONVERSATION_LIMIT_KEY = 1835bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein "ignore-initial-conversation-limit"; 184a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal 185d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal protected Account mAccount; 18612a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira protected Folder mFolder; 187ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang protected Folder mInbox; 18869b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal /** True when {@link #mFolder} is first shown to the user. */ 18969b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal private boolean mFolderChanged = false; 1902d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein protected ActionBarController mActionBarController; 19110fcd645f703799326da326630b663df69f91508James Lemieux protected final MailActivity mActivity; 192a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal protected final Context mContext; 1936902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal private final FragmentManager mFragmentManager; 194ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal protected final RecentFolderList mRecentFolderList; 19580aeac5356b5a14a5ef2aff8f0f72a464c9a3cb4Vikram Aggarwal protected ConversationListContext mConvListContext; 1969b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira protected Conversation mCurrentConversation; 197c6801eb828627c37b8992584767c095dfe11df62Jin Cao protected MaterialSearchViewController mSearchViewController; 198a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal /** 199a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal * The hash of {@link #mCurrentConversation} in detached mode. 0 if we are not in detached mode. 200a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal */ 201a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal private Uri mDetachedConvUri; 202d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal 203f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy /** A map of {@link Folder} {@link Uri} to scroll position in the conversation list. */ 204f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy private final Bundle mConversationListScrollPositions = new Bundle(); 205f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy 2066ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook /** A {@link android.content.BroadcastReceiver} that suppresses new e-mail notifications. */ 2076ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook private SuppressNotificationReceiver mNewEmailReceiver = null; 2086ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook 20959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal /** Handler for all our local runnables. */ 210fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira protected Handler mHandler = new Handler(); 211fa995b4bbccd0e650ef48878107ede5e53dd8309Mindy Pereira 212fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal /** 213161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * The current mode of the application. All changes in mode are initiated by 214161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * the activity controller. View mode changes are propagated to classes that 215161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * attach themselves as listeners of view mode changes. 216fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal */ 2171ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal protected final ViewMode mViewMode; 21880aeac5356b5a14a5ef2aff8f0f72a464c9a3cb4Vikram Aggarwal protected ContentResolver mResolver; 219c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal protected boolean mHaveAccountList = false; 220b7b33e07325fc6664d8ab803b141b87adaa2d013Mindy Pereira private AsyncRefreshTask mAsyncRefreshTask; 2215cb0c3e684150d6d8ed4d9df4fb73a7606086aaaMindy Pereira 2224e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang private boolean mDestroyed; 2234e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang 224bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal /** True if running on tablet */ 225bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal private final boolean mIsTablet; 226bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal 2271ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang /** 2281ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * Are we in a point in the Activity/Fragment lifecycle where it's safe to execute fragment 2291ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * transactions? (including back stack manipulation) 2301ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * <p> 2311ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * Per docs in {@link FragmentManager#beginTransaction()}, this flag starts out true, switches 2321ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * to false after {@link Activity#onSaveInstanceState}, and becomes true again in both onStart 2331ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * and onResume. 2341ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang */ 2351ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang private boolean mSafeToModifyFragments = true; 2361ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 23723b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook private final Set<Uri> mCurrentAccountUris = Sets.newHashSet(); 238967ede63e059810d9d4d425c50111d606014c893Mindy Pereira protected ConversationCursor mConversationListCursor; 23961f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private final DataSetObservable mConversationListObservable = new MailObservable("List"); 240bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 24159f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal /** Runnable that checks the logging level to enable/disable the logging service. */ 24259f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal private Runnable mLogServiceChecker = null; 243de60c9d0ad164a5daf358181a05bbd43edd5d5edVikram Aggarwal /** List of all accounts currently known to the controller. This is never null. */ 244de60c9d0ad164a5daf358181a05bbd43edd5d5edVikram Aggarwal private Account[] mAllAccounts = new Account[0]; 24559f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal 24677ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal private FolderWatcher mFolderWatcher; 24777ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal 2485bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein private boolean mIgnoreInitialConversationLimit; 2495bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein 2507c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu /** 2517c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu * Interface for actions that are deferred until after a load completes. This is for handling 2527c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu * user actions which affect cursors (e.g. marking messages read or unread) that happen before 2537c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu * that cursor is loaded. 2547c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu */ 2557c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu private interface LoadFinishedCallback { 2567c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu void onLoadFinished(); 2577c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } 2587c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu 2597c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu /** The deferred actions to execute when mConversationListCursor load completes. */ 2607c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu private final ArrayList<LoadFinishedCallback> mConversationListLoadFinishedCallbacks = 2617c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu new ArrayList<LoadFinishedCallback>(); 2627c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu 263bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank private RefreshTimerTask mConversationListRefreshTask; 264e1d1b07cdb0026097eb80f6c2912a16353aacec1Marc Blank 2657c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal /** Listeners that are interested in changes to the current account. */ 26661f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private final DataSetObservable mAccountObservers = new MailObservable("Account"); 26758cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal /** Listeners that are interested in changes to the recent folders. */ 26861f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private final DataSetObservable mRecentFolderObservers = new MailObservable("RecentFolder"); 26907dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal /** Listeners that are interested in changes to the list of all accounts. */ 27061f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private final DataSetObservable mAllAccountObservers = new MailObservable("AllAccounts"); 27150ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal /** Listeners that are interested in changes to the current folder. */ 27261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private final DataSetObservable mFolderObservable = new MailObservable("CurrentFolder"); 27354022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler /** Listeners that are interested in changes to the Folder or Account selection */ 27454022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler private final DataSetObservable mFolderOrAccountObservers = 27554022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler new MailObservable("FolderOrAccount"); 27658cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal 277967ede63e059810d9d4d425c50111d606014c893Mindy Pereira /** 278967ede63e059810d9d4d425c50111d606014c893Mindy Pereira * Selected conversations, if any. 279967ede63e059810d9d4d425c50111d606014c893Mindy Pereira */ 280ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao private final ConversationCheckedSet mCheckedSet = new ConversationCheckedSet(); 281dac00547ce8d44a964e4510315168ee413e55a75Mindy Pereira 282c7a070f90a47ea658c36185c65ba8dcc7f2b09b9Paul Westbrook private final int mFolderItemUpdateDelayMs; 283c7a070f90a47ea658c36185c65ba8dcc7f2b09b9Paul Westbrook 284135fd02e74ea8449b36c3dc44cd796e06a7e714dVikram Aggarwal /** Keeps track of selected and unselected conversations */ 285937c94f025ed55c19bd46c7c077fa3575ab6be52Paul Westbrook final protected ConversationPositionTracker mTracker; 286af1ee0c4b6258530d8da30bcdb2a9cb403f70d5eVikram Aggarwal 287e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal /** 288e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal * Action menu associated with the selected set. 289e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal */ 290e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal SelectedConversationsActionMenu mCabActionMenu; 2911a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux 2921a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux /** The compose button floating over the conversation/search lists */ 2931a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux protected View mFloatingComposeButton; 294c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein protected ActionableToastBar mToastBar; 295632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang protected ConversationPagerController mPagerController; 296ab4863650794e81f35a0fd9abc16a5564d7b102bMindy Pereira 297d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal // This is split out from the general loader dispatcher because its loader doesn't return a 298b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang // basic Cursor 299d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal /** Handles loader callbacks to create a convesation cursor. */ 300b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang private final ConversationListLoaderCallbacks mListCursorCallbacks = 301b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang new ConversationListLoaderCallbacks(); 302b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang 303177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal /** Object that listens to all LoaderCallbacks that result in {@link Folder} creation. */ 304177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private final FolderLoads mFolderCallbacks = new FolderLoads(); 305177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal /** Object that listens to all LoaderCallbacks that result in {@link Account} creation. */ 306177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private final AccountLoads mAccountCallbacks = new AccountLoads(); 307177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 30869a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal /** 30969a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * Matched addresses that must be shielded from users because they are temporary. Even though 31069a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * this is instantiated from settings, this matcher is valid for all accounts, and is expected 31169a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * to live past the life of an account. 31269a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal */ 31369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal private final VeiledAddressMatcher mVeiledMatcher; 31469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 315b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook protected static final String LOG_TAG = LogTag.getLogTag(); 316d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal 317aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal // Loader constants: Accounts 318aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 319aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The list of accounts. This loader is started early in the application life-cycle since 320aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * the list of accounts is central to all other data the application needs: unread counts for 321aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * folders, critical UI settings like show/hide checkboxes, ... 322aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The loader is started when the application is created: both in 323aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * {@link #onCreate(Bundle)} and in {@link #onActivityResult(int, int, Intent)}. It is never 324aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * destroyed since the cursor is needed through the life of the application. When the list of 325aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * accounts changes, we notify {@link #mAllAccountObservers}. 326aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 327fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal private static final int LOADER_ACCOUNT_CURSOR = 0; 328aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal 329aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 330aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The current account. This loader is started when we have an account. The mail application 331aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * <b>needs</b> a valid account to function. As soon as we set {@link #mAccount}, 332aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * we start a loader to observe for changes on the current account. 333aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The loader is always restarted when an account is set in {@link #setAccount(Account)}. 334aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * When the current account object changes, we notify {@link #mAccountObservers}. 335aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * A possible performance improvement would be to listen purely on 336aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * {@link #LOADER_ACCOUNT_CURSOR}. The current account is guaranteed to be in the list, 337aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * and would avoid two updates when a single setting on the current account changes. 338aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 339004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps private static final int LOADER_ACCOUNT_UPDATE_CURSOR = 1; 340004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 341004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps // Loader constants: Conversations 342004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 343004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps /** The conversation cursor over the current conversation list. This loader provides 344004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * a cursor over conversation entries from a folder to display a conversation 345004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * list. 346004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * This loader is started when the user switches folders (in {@link #updateFolder(Folder)}, 347004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * or when the controller is told that a folder/account change is imminent 348004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * (in {@link #preloadConvList(Account, Folder)}. The loader is maintained for the life of 349004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * the current folder. When the user switches folders, the old loader is destroyed and a new 350004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * one is created. 351004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * 352004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * When the conversation list changes, we notify {@link #mConversationListObservable}. 353004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps */ 354004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps private static final int LOADER_CONVERSATION_LIST = 10; 355004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 356004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps // Loader constants: misc 357004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps /** 358004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * The loader that determines whether the Warm welcome tour should be displayed for the user. 359004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps */ 360004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps public static final int LOADER_WELCOME_TOUR = 20; 361d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal 362944ef3b09d15d28f13cf63e3410850e246b1d54fGreg Bullock /** 363944ef3b09d15d28f13cf63e3410850e246b1d54fGreg Bullock * The load which loads accounts for the welcome tour. 364944ef3b09d15d28f13cf63e3410850e246b1d54fGreg Bullock */ 365944ef3b09d15d28f13cf63e3410850e246b1d54fGreg Bullock public static final int LOADER_WELCOME_TOUR_ACCOUNTS = 21; 366944ef3b09d15d28f13cf63e3410850e246b1d54fGreg Bullock 367aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal // Loader constants: Folders 368004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 369aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** The current folder. This loader watches for updates to the current folder in a manner 370aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * analogous to the {@link #LOADER_ACCOUNT_UPDATE_CURSOR}. Updates to the current folder 371aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * might be due to server-side changes (unread count), or local changes (sync window or sync 372aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * status change). 373aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The change of current folder calls {@link #updateFolder(Folder)}. 374aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * This is responsible for restarting a loader using the URI of the provided folder. When the 375aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * loader returns, the current folder is updated and consumers, if any, are notified. 376aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * When the current folder changes, we notify {@link #mFolderObservable} 377aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 378004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps private static final int LOADER_FOLDER_CURSOR = 30; 379004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 380aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 381aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The list of recent folders. Recent folders are shown in the DrawerFragment. The recent 382aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * folders are tied to the current account being viewed. When the account is changed, 383aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * we restart this loader to retrieve the recent accounts. Recents are pre-populated for 384aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * phones historically, when they were displayed in the spinner. On the tablet, 385aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * they showed in the {@link FolderListFragment} and were not-populated. The code to 386aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * pre-populate the recents is somewhat convoluted: when the loader returns a short list of 387aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * recent folders, it issues an update on the Recent Folder URI. The underlying provider then 388aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * does the appropriate thing to populate recent folders, and notify of a change on the cursor. 389aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * Recent folders are needed for the life of the current account. 390aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * When the recent folders change, we notify {@link #mRecentFolderObservers}. 391aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 392004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps private static final int LOADER_RECENT_FOLDERS = 31; 393aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 394aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The primary inbox for the current account. The mechanism to load the default inbox for the 395aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * current account is (sadly) different from loading other folders. The method 396aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * {@link #loadAccountInbox()} is called, and it restarts this loader. When the loader returns 397aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * a valid cursor, we create a folder, call {@link #onFolderChanged{Folder)} eventually 398aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * calling {@link #updateFolder(Folder)} which starts a loader {@link #LOADER_FOLDER_CURSOR} 399aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * over the current folder. 400aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * When we have a valid cursor, we destroy this loader, This convoluted flow is historical. 401aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 402004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps private static final int LOADER_ACCOUNT_INBOX = 32; 403004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 404aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 405aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The fake folder of search results for a term. When we search for a term, 406aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * a new activity is created with {@link Intent#ACTION_SEARCH}. For this new activity, 407aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * we start a loader which returns conversations that match the user-provided query. 408aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * We destroy the loader when we obtain a valid cursor since subsequent searches will create 409aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * a new activity. 410aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 411004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps private static final int LOADER_SEARCH = 33; 412aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 413aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The initial folder at app start. When the application is launched from an intent that 414aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * specifies the initial folder (notifications/widgets/shortcuts), 415aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * then we extract the folder URI from the intent, but we cannot trust the folder object. Since 416aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * shortcuts and widgets persist past application update, they might have incorrect 417aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * information encoded in them. So, to obtain a {@link Folder} object from a {@link Uri}, 418aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * we need to start another loader. Upon obtaining a valid cursor, the loader is destroyed. 419aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * An additional complication arises if we have to view a specific conversation within this 420aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * folder. This is the case when launching the app from a single conversation notification 421aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * or tapping on a specific conversation in the widget. In these cases, the conversation is 422aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * saved in {@link #mConversationToShow} and is retrieved when the loader returns. 423aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 424004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps public static final int LOADER_FIRST_FOLDER = 34; 425de21e898901a86acdcf62ea46d358184bfd063b3Régis Décamps 426de21e898901a86acdcf62ea46d358184bfd063b3Régis Décamps /** 4277a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * Guaranteed to be the last loader ID used by the activity. Loaders are owned by Activity or 4287a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * fragments, and within an activity, loader IDs need to be unique. A hack to ensure that the 4297a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * {@link FolderWatcher} can create its folder loaders without clashing with the IDs of those 4307a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * of the {@link AbstractActivityController}. Currently, the {@link FolderWatcher} is the only 4317a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * other class that uses this activity's LoaderManager. If another class needs activity-level 4327a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * loaders, consider consolidating the loaders in a central location: a UI-less fragment 4337a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * perhaps. 4347a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal */ 435004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps public static final int LAST_LOADER_ID = 35; 436004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 4377c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy /** 4387c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy * Guaranteed to be the last loader ID used by the Fragment. Loaders are owned by Activity or 4397c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy * fragments, and within an activity, loader IDs need to be unique. Currently, 4402d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein * SectionedInboxTeaserView is the only class that uses the 4417c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy * {@link ConversationListFragment}'s LoaderManager. 4427c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy */ 4437c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy public static final int LAST_FRAGMENT_LOADER_ID = 1000; 4444a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal 4456aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal /** Code returned after an account has been added. */ 4462388c5d208acd4e4e658aaacbbc5f080ee8e9f7cPaul Westbrook private static final int ADD_ACCOUNT_REQUEST_CODE = 1; 4476aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal /** Code returned when the user has to enter the new password on an existing account. */ 448122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook private static final int REAUTHENTICATE_REQUEST_CODE = 2; 449371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon /** Code returned when the previous activity needs to navigate to a different folder 450371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon * or account */ 451371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon private static final int CHANGE_NAVIGATION_REQUEST_CODE = 3; 452371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon 453406ae08b92f78f26fe83830897570c9db1ab23aaGreg Bullock /** Code returned from voice search intent */ 454406ae08b92f78f26fe83830897570c9db1ab23aaGreg Bullock public static final int VOICE_SEARCH_REQUEST_CODE = 4; 455406ae08b92f78f26fe83830897570c9db1ab23aaGreg Bullock 456371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon public static final String EXTRA_FOLDER = "extra-folder"; 457371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon public static final String EXTRA_ACCOUNT = "extra-account"; 4582388c5d208acd4e4e658aaacbbc5f080ee8e9f7cPaul Westbrook 459e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal /** The pending destructive action to be carried out before swapping the conversation cursor.*/ 460e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal private DestructiveAction mPendingDestruction; 461c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein protected AsyncRefreshTask mFolderSyncTask; 462c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira private Folder mFolderListFolder; 463e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon private final int mShowUndoBarDelay; 4646f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp private boolean mRecentsDataUpdated; 465a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal /** A wait fragment we added, if any. */ 466a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal private WaitFragment mWaitFragment; 467f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal /** True if we have results from a search query */ 46887a8982af83168453b6dc219fe984bff68047bebAndy Huang protected boolean mHaveSearchResults = false; 4696cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal /** If a confirmation dialog is being show, the listener for the positive action. */ 4706cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal private OnClickListener mDialogListener; 4716cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal /** 4726cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal * If a confirmation dialog is being show, the resource of the action: R.id.delete, etc. This 4736cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal * is used to create a new {@link #mDialogListener} on orientation changes. 4746cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal */ 4756cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal private int mDialogAction = -1; 476b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal /** 477b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal * If a confirmation dialog is being shown, this is true if the dialog acts on the selected set 478b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal * and false if it acts on the currently selected conversation 479b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal */ 480b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal private boolean mDialogFromSelectedSet; 4816cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal 482177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal /** Which conversation to show, if started from widget/notification. */ 483177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private Conversation mConversationToShow = null; 484177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 485c94d07f4460d00db898237603de311d226707a96Andy Huang /** 486c94d07f4460d00db898237603de311d226707a96Andy Huang * A temporary reference to the pending destructive action that was deferred due to an 487c94d07f4460d00db898237603de311d226707a96Andy Huang * auto-advance transition in progress. 488c94d07f4460d00db898237603de311d226707a96Andy Huang * <p> 489c94d07f4460d00db898237603de311d226707a96Andy Huang * In detail: when auto-advance triggers a mode change, we must wait until the transition 490c94d07f4460d00db898237603de311d226707a96Andy Huang * completes before executing the destructive action to ensure a smooth mode change transition. 491c94d07f4460d00db898237603de311d226707a96Andy Huang * This member variable houses the pending destructive action work to be run upon completion. 492c94d07f4460d00db898237603de311d226707a96Andy Huang */ 493c94d07f4460d00db898237603de311d226707a96Andy Huang private Runnable mAutoAdvanceOp = null; 494c94d07f4460d00db898237603de311d226707a96Andy Huang 49512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang protected DrawerLayout mDrawerContainer; 49612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang protected View mDrawerPullout; 49712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang protected ActionBarDrawerToggle mDrawerToggle; 498f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang 49912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang protected ListView mListViewForAnimating; 50012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang protected boolean mHasNewAccountOrFolder; 501a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein private boolean mConversationListLoadFinishedIgnored; 50261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private final MailDrawerListener mDrawerListener = new MailDrawerListener(); 5035747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein private boolean mHideMenuItems; 50412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 505144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang private final DrawIdler mDrawIdler = new DrawIdler(); 506144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang 50700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein public static final String SYNC_ERROR_DIALOG_FRAGMENT_TAG = "SyncErrorDialogFragment"; 508e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal 509cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy private final DataSetObserver mUndoNotificationObserver = new DataSetObserver() { 510cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy @Override 511cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy public void onChanged() { 512cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy super.onChanged(); 513cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy 514cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy if (mConversationListCursor != null) { 515cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy mConversationListCursor.handleNotificationActions(); 516cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy } 517cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy } 518cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy }; 519cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy 52053de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein private final HomeButtonListener mHomeButtonListener = new HomeButtonListener(); 52153de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein 522a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal public AbstractActivityController(MailActivity activity, ViewMode viewMode) { 523a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal mActivity = activity; 5246902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal mFragmentManager = mActivity.getFragmentManager(); 525a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal mViewMode = viewMode; 526a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal mContext = activity.getApplicationContext(); 527025eba8bfd4d0b5e248b6de0bda6f1129170fb41Vikram Aggarwal mRecentFolderList = new RecentFolderList(mContext); 528937c94f025ed55c19bd46c7c077fa3575ab6be52Paul Westbrook mTracker = new ConversationPositionTracker(this); 529967ede63e059810d9d4d425c50111d606014c893Mindy Pereira // Allow the fragment to observe changes to its own selection set. No other object is 530967ede63e059810d9d4d425c50111d606014c893Mindy Pereira // aware of the selected set. 531ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao mCheckedSet.addObserver(this); 532c7a070f90a47ea658c36185c65ba8dcc7f2b09b9Paul Westbrook 533bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal final Resources r = mContext.getResources(); 534bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal mFolderItemUpdateDelayMs = r.getInteger(R.integer.folder_item_refresh_delay_ms); 535bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal mShowUndoBarDelay = r.getInteger(R.integer.show_undo_bar_delay_ms); 53669a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal mVeiledMatcher = VeiledAddressMatcher.newInstance(activity.getResources()); 537bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal mIsTablet = Utils.useTabletUI(r); 538a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mConversationListLoadFinishedIgnored = false; 5394a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal } 5404a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal 54187a8982af83168453b6dc219fe984bff68047bebAndy Huang @Override 54287a8982af83168453b6dc219fe984bff68047bebAndy Huang public final String toString() { 54387a8982af83168453b6dc219fe984bff68047bebAndy Huang final StringBuilder sb = new StringBuilder(super.toString()); 54487a8982af83168453b6dc219fe984bff68047bebAndy Huang sb.append("{"); 54587a8982af83168453b6dc219fe984bff68047bebAndy Huang sb.append("mCurrentConversation="); 54687a8982af83168453b6dc219fe984bff68047bebAndy Huang sb.append(mCurrentConversation); 54787a8982af83168453b6dc219fe984bff68047bebAndy Huang appendToString(sb); 54887a8982af83168453b6dc219fe984bff68047bebAndy Huang sb.append("}"); 54987a8982af83168453b6dc219fe984bff68047bebAndy Huang return sb.toString(); 55087a8982af83168453b6dc219fe984bff68047bebAndy Huang } 55187a8982af83168453b6dc219fe984bff68047bebAndy Huang 55287a8982af83168453b6dc219fe984bff68047bebAndy Huang protected void appendToString(StringBuilder sb) {} 55387a8982af83168453b6dc219fe984bff68047bebAndy Huang 554e9a81035bcef5a372fa13a992f8553eb60e6aaf0Vikram Aggarwal public Account getCurrentAccount() { 555e9a81035bcef5a372fa13a992f8553eb60e6aaf0Vikram Aggarwal return mAccount; 5564a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal } 5574a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal 5581ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public ConversationListContext getCurrentListContext() { 559e9a81035bcef5a372fa13a992f8553eb60e6aaf0Vikram Aggarwal return mConvListContext; 5604a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal } 5614a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal 562a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 563ef7c992d8cb462be6da34d42965cf185f3bb1b22Vikram Aggarwal public final ConversationCursor getConversationListCursor() { 564967ede63e059810d9d4d425c50111d606014c893Mindy Pereira return mConversationListCursor; 565967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 566967ede63e059810d9d4d425c50111d606014c893Mindy Pereira 5676902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal /** 56834a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal * Check if the fragment is attached to an activity and has a root view. 569715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param in fragment to be checked 57034a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal * @return true if the fragment is valid, false otherwise 57134a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal */ 572715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private static boolean isValidFragment(Fragment in) { 573715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal return !(in == null || in.getActivity() == null || in.getView() == null); 57434a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal } 57534a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal 57634a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal /** 57749e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * Get the conversation list fragment for this activity. If the conversation list fragment is 57849e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * not attached, this method returns null. 579839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang * 58049e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * Caution! This method returns the {@link ConversationListFragment} after the fragment has been 58149e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * added, <b>and</b> after the {@link FragmentManager} has run through its queue to add the 58249e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * fragment. There is a non-trivial amount of time after the fragment is instantiated and before 58349e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * this call returns a non-null value, depending on the {@link FragmentManager}. If you 58449e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * need the fragment immediately after adding it, consider making the fragment an observer of 58549e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * the controller and perform the task immediately on {@link Fragment#onActivityCreated(Bundle)} 5866902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal */ 5876902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal protected ConversationListFragment getConversationListFragment() { 5886902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal final Fragment fragment = mFragmentManager.findFragmentByTag(TAG_CONVERSATION_LIST); 58934a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal if (isValidFragment(fragment)) { 59034a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal return (ConversationListFragment) fragment; 5919585d7810519b7e5475d9c7458e7a8a9c12fd024Andy Huang } 59234a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal return null; 5936902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal } 5946902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal 5956902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal /** 5966902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal * Returns the folder list fragment attached with this activity. If no such fragment is attached 5976902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal * this method returns null. 598839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang * 59949e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * Caution! This method returns the {@link FolderListFragment} after the fragment has been 60049e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * added, <b>and</b> after the {@link FragmentManager} has run through its queue to add the 60149e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * fragment. There is a non-trivial amount of time after the fragment is instantiated and before 60249e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * this call returns a non-null value, depending on the {@link FragmentManager}. If you 60349e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * need the fragment immediately after adding it, consider making the fragment an observer of 60449e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * the controller and perform the task immediately on {@link Fragment#onActivityCreated(Bundle)} 6056902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal */ 6066902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal protected FolderListFragment getFolderListFragment() { 60710fcd645f703799326da326630b663df69f91508James Lemieux final String drawerPulloutTag = mActivity.getString(R.string.drawer_pullout_tag); 60810fcd645f703799326da326630b663df69f91508James Lemieux final Fragment fragment = mFragmentManager.findFragmentByTag(drawerPulloutTag); 60934a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal if (isValidFragment(fragment)) { 61034a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal return (FolderListFragment) fragment; 6119585d7810519b7e5475d9c7458e7a8a9c12fd024Andy Huang } 61234a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal return null; 6136902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal } 6146902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal 6151ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal /** 616161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * Initialize the action bar. This is not visible to OnePaneController and 617161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * TwoPaneController so they cannot override this behavior. 6181ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal */ 619abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal private void initializeActionBar() { 62052882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein final ActionBar actionBar = mActivity.getSupportActionBar(); 6215895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang if (actionBar == null) { 6225895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang return; 623abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal } 6245895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang 625c6801eb828627c37b8992584767c095dfe11df62Jin Cao mActionBarController = new ActionBarController(mContext); 6262d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.initialize(mActivity, this, actionBar); 627c6801eb828627c37b8992584767c095dfe11df62Jin Cao actionBar.setShowHideAnimationEnabled(false); 6281dd054f4e5581b69a52936c9d257fa91cb6daee7Rohan Shah 62912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // init the action bar to allow the 'up' affordance. 63012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // any configurations that disallow 'up' should do that later. 6312d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.setBackButton(); 632abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal } 633abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal 634abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal /** 635abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal * Attach the action bar to the activity. 636abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal */ 637abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal private void attachActionBar() { 63852882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein final ActionBar actionBar = mActivity.getSupportActionBar(); 639bd09150070b1aa25ebdd9af0a29e8bf9fbbf7af8Tony Mantler if (actionBar != null) { 6402d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein // Show a title 6412d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein final int mask = ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME; 642bc462cadc2dcd11d27e7810e437aeef1505f4cb2Vikram Aggarwal actionBar.setDisplayOptions(mask, mask); 6432d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.setViewModeController(mViewMode); 6441ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 645a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 646a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 647a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal /** 648161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * Returns whether the conversation list fragment is visible or not. 649161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * Different layouts will have their own notion on the visibility of 650161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * fragments, so this method needs to be overriden. 651161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * 652a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal */ 6531ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal protected abstract boolean isConversationListVisible(); 6541ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 655eb7d329e448eb42195f7c35b978035766b6f46e1Vikram Aggarwal /** 65634f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal * If required, starts wait mode for the current account. 65734f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal */ 65834f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal final void perhapsEnterWaitMode() { 65934f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal // If the account is not initialized, then show the wait fragment, since nothing can be 66034f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal // shown. 66134f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal if (mAccount.isAccountInitializationRequired()) { 66234f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal showWaitForInitialization(); 66334f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal return; 66434f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal } 66534f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal 66634f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal final boolean inWaitingMode = inWaitMode(); 66734f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal final boolean isSyncRequired = mAccount.isAccountSyncRequired(); 66834f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal if (isSyncRequired) { 66934f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal if (inWaitingMode) { 67034f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal // Update the WaitFragment's account object 67134f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal updateWaitMode(); 67234f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal } else { 67334f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal // Transition to waiting mode 67434f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal showWaitForInitialization(); 67534f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal } 67634f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal } else if (inWaitingMode) { 67734f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal // Dismiss waiting mode 67834f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal hideWaitForInitialization(); 67934f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal } 68034f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal } 68134f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal 682eb7d329e448eb42195f7c35b978035766b6f46e1Vikram Aggarwal @Override 6834cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein public void switchToDefaultInboxOrChangeAccount(Account account) { 6844cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein LogUtils.d(LOG_TAG, "AAC.switchToDefaultAccount(%s)", account); 685e764cfd130c4f92ae823fd1f361ab70439e8ec95Andy Huang if (mViewMode.isSearchMode()) { 686371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // We are in an activity on top of the main navigation activity. 687371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // We need to return to it with a result code that indicates it should navigate to 688371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // a different folder. 689371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon final Intent intent = new Intent(); 690371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon intent.putExtra(AbstractActivityController.EXTRA_ACCOUNT, account); 691371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon mActivity.setResult(Activity.RESULT_OK, intent); 692371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon mActivity.finish(); 693371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon return; 694371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon } 69566bc6ed16956963cb18660d15ea7e6adc6c62411Vikram Aggarwal final boolean firstLoad = mAccount == null; 696252684a1ddaf00119d8f2440e5d4cd93c77e5298Andrew Sapperstein final boolean switchToDefaultInbox = !firstLoad && account.uri.equals(mAccount.uri); 697d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal // If the active account has been clicked in the drawer, go to default inbox 698252684a1ddaf00119d8f2440e5d4cd93c77e5298Andrew Sapperstein if (switchToDefaultInbox) { 699252684a1ddaf00119d8f2440e5d4cd93c77e5298Andrew Sapperstein loadAccountInbox(); 700252684a1ddaf00119d8f2440e5d4cd93c77e5298Andrew Sapperstein return; 701252684a1ddaf00119d8f2440e5d4cd93c77e5298Andrew Sapperstein } 7024cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein changeAccount(account); 7034cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein } 7044cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein 7054cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein public void changeAccount(Account account) { 7064cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein LogUtils.d(LOG_TAG, "AAC.changeAccount(%s)", account); 7074cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein // Is the account or account settings different from the existing account? 7084cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein final boolean firstLoad = mAccount == null; 7094cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein final boolean accountChanged = firstLoad || !account.uri.equals(mAccount.uri); 7104cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein 711472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal // If nothing has changed, return early without wasting any more time. 712472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal if (!accountChanged && !account.settingsDiffer(mAccount)) { 713472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal return; 714472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal } 715472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal // We also don't want to do anything if the new account is null 716472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal if (account == null) { 7175fd8afd5c1b40580c069a5a97039ca0601208216Vikram Aggarwal LogUtils.e(LOG_TAG, "AAC.changeAccount(null) called."); 718472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal return; 719472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal } 72079b1156803585952a4851221dc9fa9974e606433Tony Mantler final String emailAddress = account.getEmailAddress(); 721472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal mHandler.post(new Runnable() { 722472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal @Override 723472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal public void run() { 72479b1156803585952a4851221dc9fa9974e606433Tony Mantler MailActivity.setNfcMessage(emailAddress); 725c6adce3cf6887c4c6dd5005724565702751843d0mindyp } 726472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal }); 727472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal if (accountChanged) { 728472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal commitDestructiveActions(false); 729472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal } 7302168cbc9c58d2133bdf77ecd342c3d5ee755d607Régis Décamps 731472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal // Change the account here 732472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal setAccount(account); 733472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal // And carry out associated actions. 734472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal cancelRefreshTask(); 735472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal if (accountChanged) { 736472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal loadAccountInbox(); 737472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal } 738472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal // Check if we need to force setting up an account before proceeding. 739472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal if (mAccount != null && !Uri.EMPTY.equals(mAccount.settings.setupIntentUri)) { 740472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal // Launch the intent! 741472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal final Intent intent = new Intent(Intent.ACTION_EDIT); 742ec6e2516037e7172202e208b2015d7684a78eddbTony Mantler 743ec6e2516037e7172202e208b2015d7684a78eddbTony Mantler intent.setPackage(mContext.getPackageName()); 744472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal intent.setData(mAccount.settings.setupIntentUri); 745ec6e2516037e7172202e208b2015d7684a78eddbTony Mantler 746472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal mActivity.startActivity(intent); 74728d5f72e0ad0db75b6243ee8125bfe3aadbdcb85Mindy Pereira } 748a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 749a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 750e6340bc7f2bb9868e5014a101ea69b777d7b6750Vikram Aggarwal /** 7517c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal * Adds a listener interested in change in the current account. If a class is storing a 7527c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal * reference to the current account, it should listen on changes, so it can receive updates to 7537c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal * settings. Must happen in the UI thread. 7547d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal */ 7557c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal @Override 7567c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal public void registerAccountObserver(DataSetObserver obs) { 7577c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal mAccountObservers.registerObserver(obs); 7587d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal } 7597d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal 7607d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal /** 7617c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal * Removes a listener from receiving current account changes. 7627d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal * Must happen in the UI thread. 7637d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal */ 7647c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal @Override 7657c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal public void unregisterAccountObserver(DataSetObserver obs) { 7667c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal mAccountObservers.unregisterObserver(obs); 7677d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal } 7687d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal 7697c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal @Override 77007dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal public void registerAllAccountObserver(DataSetObserver observer) { 77107dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal mAllAccountObservers.registerObserver(observer); 77207dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal } 77307dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal 77407dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal @Override 77507dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal public void unregisterAllAccountObserver(DataSetObserver observer) { 77607dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal mAllAccountObservers.unregisterObserver(observer); 77707dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal } 77807dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal 77907dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal @Override 78007dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal public Account[] getAllAccounts() { 78107dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal return mAllAccounts; 78207dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal } 78307dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal 78407dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal @Override 7857c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal public Account getAccount() { 7867c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal return mAccount; 7877d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal } 7887d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal 7890f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah @Override 79054022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler public void registerFolderOrAccountChangedObserver(final DataSetObserver observer) { 79154022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler mFolderOrAccountObservers.registerObserver(observer); 7920f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah } 7930f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah 7940f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah @Override 79554022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler public void unregisterFolderOrAccountChangedObserver(final DataSetObserver observer) { 79654022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler mFolderOrAccountObservers.unregisterObserver(observer); 7970f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah } 7980f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah 7990f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah /** 80012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * If the drawer is open, the function locks the drawer to the closed, thereby sliding in 80112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * the drawer to the left edge, disabling events, and refreshing it once it's either closed 80212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * or put in an idle state. 8030f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah */ 8040f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah @Override 805a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal public void closeDrawer(final boolean hasNewFolderOrAccount, Account nextAccount, 806a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal Folder nextFolder) { 80712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (!isDrawerEnabled()) { 80854022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler if (hasNewFolderOrAccount) { 80954022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler mFolderOrAccountObservers.notifyChanged(); 81054022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler } 81112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang return; 81212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 81312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // If there are no new folders or accounts to switch to, just close the drawer 81412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (!hasNewFolderOrAccount) { 81512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.closeDrawers(); 81612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang return; 81712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 8182f9d394867be45302bb4323da7cacf193da38f39Vikram Aggarwal // Otherwise, start preloading the conversation list for the new folder. 8192f9d394867be45302bb4323da7cacf193da38f39Vikram Aggarwal if (nextFolder != null) { 8202f9d394867be45302bb4323da7cacf193da38f39Vikram Aggarwal preloadConvList(nextAccount, nextFolder); 8212f9d394867be45302bb4323da7cacf193da38f39Vikram Aggarwal } 8222f9d394867be45302bb4323da7cacf193da38f39Vikram Aggarwal // Remember if the conversation list view is animating 82312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang final ConversationListFragment conversationList = getConversationListFragment(); 82412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (conversationList != null) { 82512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mListViewForAnimating = conversationList.getListView(); 82612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } else { 82712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // There is no conversation list to animate, so just set it to null 82812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mListViewForAnimating = null; 82912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 83012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 83112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (mDrawerContainer.isDrawerOpen(mDrawerPullout)) { 83212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // Lets the drawer listener update the drawer contents and notify the FolderListFragment 83312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mHasNewAccountOrFolder = true; 83412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); 83512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } else { 83612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // Drawer is already closed, notify observers that is the case. 83754022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler if (hasNewFolderOrAccount) { 83854022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler mFolderOrAccountObservers.notifyChanged(); 83954022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler } 84012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 8410f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah } 8420f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah 843a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal /** 844aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * Load the conversation list early for the given folder. This happens when some UI element 845aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * (usually the drawer) instructs the controller that an account change or folder change is 846aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * imminent. While the UI element is animating, the controller can preload the conversation 847aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * list for the default inbox of the account provided here or to the folder provided here. 848aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * 849aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * @param nextAccount The account which the app will switch to shortly, possibly null. 850aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * @param nextFolder The folder which the app will switch to shortly, possibly null. 851a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal */ 852a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal protected void preloadConvList(Account nextAccount, Folder nextFolder) { 853a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal // Fire off the conversation list loader for this account already with a fake 854a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal // listener. 855e2be97a58fbae98b95e51735c6468d121e465355Paul Westbrook final Bundle args = new Bundle(2); 856a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal if (nextAccount != null) { 857a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal args.putParcelable(BUNDLE_ACCOUNT_KEY, nextAccount); 858a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal } else { 859a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal args.putParcelable(BUNDLE_ACCOUNT_KEY, mAccount); 860a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal } 861a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal if (nextFolder != null) { 862a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal args.putParcelable(BUNDLE_FOLDER_KEY, nextFolder); 8632dc850446320d6b56b89dda7fefc5113c6b7d8d1Vikram Aggarwal } else { 8642dc850446320d6b56b89dda7fefc5113c6b7d8d1Vikram Aggarwal LogUtils.e(LOG_TAG, new Error(), "AAC.preloadConvList(): Got an empty folder"); 865a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal } 866a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal mFolder = null; 867a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal final LoaderManager lm = mActivity.getLoaderManager(); 868a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal lm.destroyLoader(LOADER_CONVERSATION_LIST); 869a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal lm.initLoader(LOADER_CONVERSATION_LIST, args, mListCursorCallbacks); 870a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal } 871a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal 872aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 873aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * Initiates the async request to create a fake search folder, which returns conversations that 874aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * match the query term provided by the user. Returns immediately. 875aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * @param intent Intent that the app was started with. This intent contains the search query. 876aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 877e0828393e175c9293c86a7490225f324cbec5eefMindy Pereira private void fetchSearchFolder(Intent intent) { 878e2be97a58fbae98b95e51735c6468d121e465355Paul Westbrook final Bundle args = new Bundle(1); 879ab4863650794e81f35a0fd9abc16a5564d7b102bMindy Pereira args.putString(ConversationListContext.EXTRA_SEARCH_QUERY, intent 880e0828393e175c9293c86a7490225f324cbec5eefMindy Pereira .getStringExtra(ConversationListContext.EXTRA_SEARCH_QUERY)); 881177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getLoaderManager().restartLoader(LOADER_SEARCH, args, mFolderCallbacks); 882e0828393e175c9293c86a7490225f324cbec5eefMindy Pereira } 883e0828393e175c9293c86a7490225f324cbec5eefMindy Pereira 884405a344937675f57fc9c6988b2b124410a270f13Jin Cao protected void onFolderChanged(Folder folder, final boolean force) { 885f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang if (isDrawerEnabled()) { 886f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang /** If the folder doesn't exist, or its parent URI is empty, 887f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang * this is not a child folder */ 888f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang final boolean isTopLevel = Folder.isRoot(folder); 889f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang final int mode = mViewMode.getMode(); 890207e662df01c550a4894bec03219820528365508Rohan Shah updateDrawerIndicator(mode, isTopLevel); 891f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); 892dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal 893f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerContainer.closeDrawers(); 894f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang } 8957dd0e1cec391fc2562795d6e6d9fc91ab36ca647Alice Yang 8967dd0e1cec391fc2562795d6e6d9fc91ab36ca647Alice Yang if (mFolder == null || !mFolder.equals(folder)) { 8977dd0e1cec391fc2562795d6e6d9fc91ab36ca647Alice Yang // We are actually changing the folder, so exit cab mode 8987dd0e1cec391fc2562795d6e6d9fc91ab36ca647Alice Yang exitCabMode(); 8997dd0e1cec391fc2562795d6e6d9fc91ab36ca647Alice Yang } 9007dd0e1cec391fc2562795d6e6d9fc91ab36ca647Alice Yang 901a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy final String query; 902a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy if (folder != null && folder.isType(FolderType.SEARCH)) { 903a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy query = mConvListContext.searchQuery; 904a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy } else { 905a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy query = null; 906a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy } 907a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy 908a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy changeFolder(folder, query, force); 909f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal } 910f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal 911f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal /** 912203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal * Sets the folder state without changing view mode and without creating a list fragment, if 913203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal * possible. 914715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param folder the folder whose list of conversations are to be shown 915715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param query the query string for a list of conversations matching a search 916203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal */ 917203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal private void setListContext(Folder folder, String query) { 918203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal updateFolder(folder); 919203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal if (query != null) { 920203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal mConvListContext = ConversationListContext.forSearchQuery(mAccount, mFolder, query); 921203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal } else { 922203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal mConvListContext = ConversationListContext.forFolder(mAccount, mFolder); 923203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal } 924203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal cancelRefreshTask(); 925203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal } 926203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal 927203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal /** 928f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal * Changes the folder to the value provided here. This causes the view mode to change. 929f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal * @param folder the folder to change to 930f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal * @param query if non-null, this represents the search string that the folder represents. 931ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang * @param force <code>true</code> to force a folder change, <code>false</code> to disallow 932ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang * changing to the current folder 933f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal */ 934ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang private void changeFolder(Folder folder, String query, final boolean force) { 935203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal if (!Objects.equal(mFolder, folder)) { 936203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal commitDestructiveActions(false); 937203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal } 938ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang if (folder != null && (!folder.equals(mFolder) || force) 939a1f99981919755e50f31fe300517d2fed752997eMindy Pereira || (mViewMode.getMode() != ViewMode.CONVERSATION_LIST)) { 940203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal setListContext(folder, query); 94128e0c34ad35925fc74633bec66344911f2de6a22Mindy Pereira showConversationList(mConvListContext); 94258ccd6952c0a5ed979e9cee1a3f6992b4040c732Vikram Aggarwal // Touch the current folder: it is different, and it has been accessed. 94346b5b33c4de296b5c3b61b031db9d36bf429be6aTony Mantler if (mFolder != null) { 94446b5b33c4de296b5c3b61b031db9d36bf429be6aTony Mantler mRecentFolderList.touchFolder(mFolder, mAccount); 94546b5b33c4de296b5c3b61b031db9d36bf429be6aTony Mantler } 94628e0c34ad35925fc74633bec66344911f2de6a22Mindy Pereira } 94793dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal resetActionBarIcon(); 948a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 949a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 95013c12a628bd4f1e52b9a4fc44a18b85bfdaeb88bMindy Pereira @Override 951505df5f59c92adbe8eaa734321c1d3f91be84a4aMindy Pereira public void onFolderSelected(Folder folder) { 952ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang onFolderChanged(folder, false /* force */); 95313c12a628bd4f1e52b9a4fc44a18b85bfdaeb88bMindy Pereira } 95413c12a628bd4f1e52b9a4fc44a18b85bfdaeb88bMindy Pereira 955792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal /** 95658cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal * Adds a listener interested in change in the recent folders. If a class is storing a 95758cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal * reference to the recent folders, it should listen on changes, so it can receive updates. 95858cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal * Must happen in the UI thread. 95958cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal */ 96058cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal @Override 96158cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal public void registerRecentFolderObserver(DataSetObserver obs) { 96258cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal mRecentFolderObservers.registerObserver(obs); 96358cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal } 96458cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal 96558cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal /** 96658cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal * Removes a listener from receiving recent folder changes. 96758cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal * Must happen in the UI thread. 96858cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal */ 96958cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal @Override 97058cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal public void unregisterRecentFolderObserver(DataSetObserver obs) { 97158cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal mRecentFolderObservers.unregisterObserver(obs); 97258cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal } 97358cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal 97458cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal @Override 97558cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal public RecentFolderList getRecentFolders() { 97658cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal return mRecentFolderList; 97758cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal } 97858cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal 979405a344937675f57fc9c6988b2b124410a270f13Jin Cao /** 980405a344937675f57fc9c6988b2b124410a270f13Jin Cao * Load the default inbox associated with the current account. 981405a344937675f57fc9c6988b2b124410a270f13Jin Cao */ 982405a344937675f57fc9c6988b2b124410a270f13Jin Cao protected void loadAccountInbox() { 98377ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal boolean handled = false; 98477ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal if (mFolderWatcher != null) { 98577ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal final Folder inbox = mFolderWatcher.getDefaultInbox(mAccount); 98677ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal if (inbox != null) { 987ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang onFolderChanged(inbox, false /* force */); 98877ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal handled = true; 98977ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal } 99077ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal } 99177ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal if (!handled) { 9921bf20e01767d6864ef8ed196195cf7771dc2c45cPaul Westbrook LogUtils.d(LOG_TAG, "Starting a LOADER_ACCOUNT_INBOX for %s", mAccount); 99377ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal restartOptionalLoader(LOADER_ACCOUNT_INBOX, mFolderCallbacks, Bundle.EMPTY); 99477ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal } 9958cbf281d1676c21ced08c42da2aa9828cdadd87dVikram Aggarwal final int mode = mViewMode.getMode(); 9968cbf281d1676c21ced08c42da2aa9828cdadd87dVikram Aggarwal if (mode == ViewMode.UNKNOWN || mode == ViewMode.WAITING_FOR_ACCOUNT_INITIALIZATION) { 997e6459424b3e46d768865c908af1caa932f783095Andy Huang mViewMode.enterConversationListMode(); 998e6459424b3e46d768865c908af1caa932f783095Andy Huang } 999f6acdade010b2d0f49fd425b33e7f7b376286490Mindy Pereira } 1000f6acdade010b2d0f49fd425b33e7f7b376286490Mindy Pereira 100177ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal @Override 100277ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal public void setFolderWatcher(FolderWatcher watcher) { 100377ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal mFolderWatcher = watcher; 100477ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal } 100577ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal 100669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal /** 1007d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal * Marks the {@link #mFolderChanged} value if the newFolder is different from the existing 1008d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal * {@link #mFolder}. This should be called immediately <b>before</b> assigning newFolder to 1009d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal * mFolder. 1010715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param newFolder the new folder we are switching to. 1011d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal */ 1012715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void setHasFolderChanged(final Folder newFolder) { 1013d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal // We should never try to assign a null folder. But in the rare event that we do, we should 1014d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal // only set the bit when we have a valid folder, and null is not valid. 1015d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal if (newFolder == null) { 1016d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal return; 1017d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal } 1018d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal // If the previous folder was null, or if the two folders represent different data, then we 1019d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal // consider that the folder has changed. 1020259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy if (mFolder == null || !newFolder.equals(mFolder)) { 1021d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal mFolderChanged = true; 1022d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal } 1023d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal } 1024d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal 1025d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal /** 102669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal * Sets the current folder if it is different from the object provided here. This method does 102769b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal * NOT notify the folder observers that a change has happened. Observers are notified when we 102869b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal * get an updated folder from the loaders, which will happen as a consequence of this method 102969b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal * (since this method starts/restarts the loaders). 103069b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal * @param folder The folder to assign 103169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal */ 103211e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira private void updateFolder(Folder folder) { 10331672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal if (folder == null || !folder.isInitialized()) { 10341672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal LogUtils.e(LOG_TAG, new Error(), "AAC.setFolder(%s): Bad input", folder); 10351672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal return; 10361672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal } 10371672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal if (folder.equals(mFolder)) { 10381672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal LogUtils.d(LOG_TAG, "AAC.setFolder(%s): Input matches mFolder", folder); 10391672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal return; 10401672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal } 10411672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal final boolean wasNull = mFolder == null; 10421672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal LogUtils.d(LOG_TAG, "AbstractActivityController.setFolder(%s)", folder.name); 10431672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal final LoaderManager lm = mActivity.getLoaderManager(); 10441672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // updateFolder is called from AAC.onLoadFinished() on folder changes. We need to 10451672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // ensure that the folder is different from the previous folder before marking the 10461672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // folder changed. 10471672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal setHasFolderChanged(folder); 10481672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal mFolder = folder; 10491672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal 10501672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // We do not need to notify folder observers yet. Instead we start the loaders and 10511672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // when the load finishes, we will get an updated folder. Then, we notify the 10521672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // folderObservers in onLoadFinished. 10532d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.setFolder(mFolder); 10541672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal 10551672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // Only when we switch from one folder to another do we want to restart the 10561672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // folder and conversation list loaders (to trigger onCreateLoader). 10571672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // The first time this runs when the activity is [re-]initialized, we want to re-use the 10581672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // previous loader's instance and data upon configuration change (e.g. rotation). 10591672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // If there was not already an instance of the loader, init it. 10601672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal if (lm.getLoader(LOADER_FOLDER_CURSOR) == null) { 1061177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal lm.initLoader(LOADER_FOLDER_CURSOR, Bundle.EMPTY, mFolderCallbacks); 10621672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal } else { 1063177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal lm.restartLoader(LOADER_FOLDER_CURSOR, Bundle.EMPTY, mFolderCallbacks); 10641672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal } 1065a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal if (!wasNull && lm.getLoader(LOADER_CONVERSATION_LIST) != null) { 1066a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal // If there was an existing folder AND we have changed 10671672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // folders, we want to restart the loader to get the information 10681672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // for the newly selected folder 10691672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal lm.destroyLoader(LOADER_CONVERSATION_LIST); 10705cb0c3e684150d6d8ed4d9df4fb73a7606086aaaMindy Pereira } 1071e2be97a58fbae98b95e51735c6468d121e465355Paul Westbrook final Bundle args = new Bundle(2); 10722dc850446320d6b56b89dda7fefc5113c6b7d8d1Vikram Aggarwal args.putParcelable(BUNDLE_ACCOUNT_KEY, mAccount); 1073a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal args.putParcelable(BUNDLE_FOLDER_KEY, mFolder); 10745bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein args.putBoolean(BUNDLE_IGNORE_INITIAL_CONVERSATION_LIMIT_KEY, 10755bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein mIgnoreInitialConversationLimit); 10765bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein mIgnoreInitialConversationLimit = false; 1077a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal lm.initLoader(LOADER_CONVERSATION_LIST, args, mListCursorCallbacks); 10785cb0c3e684150d6d8ed4d9df4fb73a7606086aaaMindy Pereira } 10795cb0c3e684150d6d8ed4d9df4fb73a7606086aaaMindy Pereira 1080a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 1081090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang public Folder getFolder() { 1082090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang return mFolder; 1083090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 1084090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang 1085090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang @Override 1086c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira public Folder getHierarchyFolder() { 1087c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira return mFolderListFolder; 1088c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira } 1089c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira 1090405a344937675f57fc9c6988b2b124410a270f13Jin Cao /** 1091405a344937675f57fc9c6988b2b124410a270f13Jin Cao * Set the folder currently selected in the folder selection hierarchy fragments. 1092405a344937675f57fc9c6988b2b124410a270f13Jin Cao */ 1093405a344937675f57fc9c6988b2b124410a270f13Jin Cao protected void setHierarchyFolder(Folder folder) { 1094c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira mFolderListFolder = folder; 109523aadfd1c83e08b6723d4cb9357b2908cc464a86Mindy Pereira } 109623aadfd1c83e08b6723d4cb9357b2908cc464a86Mindy Pereira 10976aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal /** 10986aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * The mail activity calls other activities for two specific reasons: 10996aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <ul> 11006aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>To add an account. And receives the result {@link #ADD_ACCOUNT_REQUEST_CODE}</li> 11016aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>To update the password on a current account. The result {@link 11026aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * #REAUTHENTICATE_REQUEST_CODE} is received.</li> 11036aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </ul> 11046aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * @param requestCode 11056aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * @param resultCode 11066aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * @param data 11076aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal */ 110823aadfd1c83e08b6723d4cb9357b2908cc464a86Mindy Pereira @Override 11091ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public void onActivityResult(int requestCode, int resultCode, Intent data) { 1110122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook switch (requestCode) { 1111122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook case ADD_ACCOUNT_REQUEST_CODE: 1112122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook // We were waiting for the user to create an account 1113122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook if (resultCode == Activity.RESULT_OK) { 1114122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook // restart the loader to get the updated list of accounts 1115177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, Bundle.EMPTY, 1116177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mAccountCallbacks); 1117122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook } else { 1118122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook // The user failed to create an account, just exit the app 1119122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook mActivity.finish(); 1120122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook } 1121122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook break; 1122122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook case REAUTHENTICATE_REQUEST_CODE: 1123122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook if (resultCode == Activity.RESULT_OK) { 1124122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook // The user successfully authenticated, attempt to refresh the list 1125122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook final Uri refreshUri = mFolder != null ? mFolder.refreshUri : null; 1126122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook if (refreshUri != null) { 1127122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook startAsyncRefreshTask(refreshUri); 1128122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook } 1129122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook } 1130122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook break; 1131371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon case CHANGE_NAVIGATION_REQUEST_CODE: 1132c6801eb828627c37b8992584767c095dfe11df62Jin Cao if (ViewMode.isSearchMode(mViewMode.getMode())) { 1133c6801eb828627c37b8992584767c095dfe11df62Jin Cao mActivity.setResult(resultCode, data); 1134c6801eb828627c37b8992584767c095dfe11df62Jin Cao mActivity.finish(); 1135c6801eb828627c37b8992584767c095dfe11df62Jin Cao } else if (resultCode == Activity.RESULT_OK && data != null) { 1136371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // We have have received a result that indicates we need to navigate to a 1137371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // different folder or account. This happens if someone navigates using the 1138371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // drawer on the search results activity. 1139371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon final Folder folder = data.getParcelableExtra(EXTRA_FOLDER); 1140371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon final Account account = data.getParcelableExtra(EXTRA_ACCOUNT); 1141371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon if (folder != null) { 1142371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon onFolderSelected(folder); 1143371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon mViewMode.enterConversationListMode(); 1144371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon } else if (account != null) { 1145371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon switchToDefaultInboxOrChangeAccount(account); 1146371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon mViewMode.enterConversationListMode(); 1147371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon } 1148371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon } 1149371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon break; 1150406ae08b92f78f26fe83830897570c9db1ab23aaGreg Bullock case VOICE_SEARCH_REQUEST_CODE: 1151c6801eb828627c37b8992584767c095dfe11df62Jin Cao if (resultCode == Activity.RESULT_OK) { 1152c6801eb828627c37b8992584767c095dfe11df62Jin Cao final ArrayList<String> matches = data.getStringArrayListExtra( 1153c6801eb828627c37b8992584767c095dfe11df62Jin Cao RecognizerIntent.EXTRA_RESULTS); 1154c6801eb828627c37b8992584767c095dfe11df62Jin Cao if (!matches.isEmpty()) { 1155c6801eb828627c37b8992584767c095dfe11df62Jin Cao // not sure how dependable the API is, but it's all we have. 1156c6801eb828627c37b8992584767c095dfe11df62Jin Cao // take the top choice. 1157c6801eb828627c37b8992584767c095dfe11df62Jin Cao mSearchViewController.onSearchPerformed(matches.get(0)); 1158c6801eb828627c37b8992584767c095dfe11df62Jin Cao } 1159c6801eb828627c37b8992584767c095dfe11df62Jin Cao } 1160c6801eb828627c37b8992584767c095dfe11df62Jin Cao break; 11612388c5d208acd4e4e658aaacbbc5f080ee8e9f7cPaul Westbrook } 1162a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 1163a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 116469b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal /** 116569b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal * Inform the conversation cursor that there has been a visibility change. 1166715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param visible true if the conversation list is visible, false otherwise. 116769b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal */ 116869b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal protected synchronized void informCursorVisiblity(boolean visible) { 11699f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook if (mConversationListCursor != null) { 117069b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal Utils.setConversationCursorVisibility(mConversationListCursor, visible, mFolderChanged); 117169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal // We have informed the cursor. Subsequent visibility changes should not tell it that 117269b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal // the folder has changed. 117369b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal mFolderChanged = false; 11749f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook } 1175a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 1176a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 117769b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal @Override 117869b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal public void onConversationListVisibilityChanged(boolean visible) { 11794a0456bf96896de1dcd1e655dbdc0cd96cbe3d33Jin Cao mFloatingComposeButton.setVisibility( 11804a0456bf96896de1dcd1e655dbdc0cd96cbe3d33Jin Cao !ViewMode.isSearchMode(mViewMode.getMode()) && visible ? View.VISIBLE : View.GONE); 118192ae766a1eb3182efe5225af224c6ddd7be40931Andy Huang 118269b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal informCursorVisiblity(visible); 1183c94d07f4460d00db898237603de311d226707a96Andy Huang commitAutoAdvanceOperation(); 118432ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy 118532ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy // Notify special views 118632ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy final ConversationListFragment convListFragment = getConversationListFragment(); 118732ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy if (convListFragment != null && convListFragment.getAnimatedAdapter() != null) { 118832ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy convListFragment.getAnimatedAdapter().onConversationListVisibilityChanged(visible); 118932ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy } 119069b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal } 119169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal 11921ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal /** 11937dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal * Called when a conversation is visible. Child classes must call the super class implementation 11947dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal * before performing local computation. 11951ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal */ 11961ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 11971ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public void onConversationVisibilityChanged(boolean visible) { 1198c94d07f4460d00db898237603de311d226707a96Andy Huang commitAutoAdvanceOperation(); 1199c94d07f4460d00db898237603de311d226707a96Andy Huang } 1200c94d07f4460d00db898237603de311d226707a96Andy Huang 1201c94d07f4460d00db898237603de311d226707a96Andy Huang /** 1202c94d07f4460d00db898237603de311d226707a96Andy Huang * Commits any pending destructive action that was earlier deferred by an auto-advance 1203c94d07f4460d00db898237603de311d226707a96Andy Huang * mode-change transition. 1204c94d07f4460d00db898237603de311d226707a96Andy Huang */ 1205c94d07f4460d00db898237603de311d226707a96Andy Huang private void commitAutoAdvanceOperation() { 1206c94d07f4460d00db898237603de311d226707a96Andy Huang if (mAutoAdvanceOp != null) { 1207c94d07f4460d00db898237603de311d226707a96Andy Huang mAutoAdvanceOp.run(); 1208c94d07f4460d00db898237603de311d226707a96Andy Huang mAutoAdvanceOp = null; 1209c94d07f4460d00db898237603de311d226707a96Andy Huang } 12101ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 12111ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 121259f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal /** 121359f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal * Initialize development time logging. This can potentially log a lot of PII, and we don't want 121459f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal * to turn it on for shipped versions. 121559f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal */ 121659f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal private void initializeDevLoggingService() { 121759f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal if (!MailLogService.DEBUG_ENABLED) { 121859f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal return; 121959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } 122059f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal // Check every 5 minutes. 122159f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal final int WAIT_TIME = 5 * 60 * 1000; 122259f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal // Start a runnable that periodically checks the log level and starts/stops the service. 122359f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mLogServiceChecker = new Runnable() { 122459f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal /** True if currently logging. */ 122559f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal private boolean mCurrentlyLogging = false; 122659f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal 122759f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal /** 122859f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal * If the logging level has been changed since the previous run, start or stop the 122959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal * service. 123059f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal */ 123159f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal private void startOrStopService() { 123259f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal // If the log level is already high, start the service. 123359f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal final Intent i = new Intent(mContext, MailLogService.class); 123459f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal final boolean loggingEnabled = MailLogService.isLoggingLevelHighEnough(); 123559f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal if (mCurrentlyLogging == loggingEnabled) { 123659f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal // No change since previous run, just return; 123759f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal return; 123859f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } 123959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal if (loggingEnabled) { 124059f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal LogUtils.e(LOG_TAG, "Starting MailLogService"); 124159f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mContext.startService(i); 124259f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } else { 124359f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal LogUtils.e(LOG_TAG, "Stopping MailLogService"); 124459f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mContext.stopService(i); 124559f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } 124659f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mCurrentlyLogging = loggingEnabled; 124759f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } 124859f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal 124959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal @Override 125059f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal public void run() { 125159f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal startOrStopService(); 125259f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mHandler.postDelayed(this, WAIT_TIME); 125359f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } 125459f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal }; 125559f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal // Start the runnable right away. 125659f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mHandler.post(mLogServiceChecker); 125759f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } 125859f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal 12596aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal /** 12606aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * The application can be started from the following entry points: 12616aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <ul> 12626aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Launcher: you tap on the Gmail icon in the launcher. This is what most users think of 12636aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * as “Starting the app”.</li> 12646aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Shortcut: Users can make a shortcut to take them directly to a label.</li> 12656aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Widget: Shows the contents of a synced label, and allows: 12666aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <ul> 12676aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Viewing the list (tapping on the title)</li> 12686aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Composing a new message (tapping on the new message icon in the title. This 12696aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * launches the {@link ComposeActivity}. 12706aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </li> 12716aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Viewing a single message (tapping on a list element)</li> 12726aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </ul> 12736aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * 12746aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </li> 12756aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Tapping on a notification: 12766aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <ul> 12776aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Shows message list if more than one message</li> 12786aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Shows the conversation if the notification is for a single message</li> 12796aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </ul> 12806aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </li> 12816aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>...and most importantly, the activity life cycle can tear down the application and 12826aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * restart it: 12836aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <ul> 12846aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Rotate the application: it is destroyed and recreated.</li> 12856aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Navigate away, and return from recent applications.</li> 12866aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </ul> 12876aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </li> 12886aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Add a new account: fires off an intent to add an account, 12896aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * and returns in {@link #onActivityResult(int, int, android.content.Intent)} .</li> 12906aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Re-authenticate your account: again returns in onActivityResult().</li> 12916aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Composing can happen from many entry points: third party applications fire off an 12926aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * intent to compose email, and launch directly into the {@link ComposeActivity} 12936aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * .</li> 12946aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </ul> 12956aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * {@inheritDoc} 12966aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal */ 12971ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 129887a8982af83168453b6dc219fe984bff68047bebAndy Huang public void onCreate(Bundle savedState) { 1299abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal initializeActionBar(); 130059f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal initializeDevLoggingService(); 13011ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal // Allow shortcut keys to function for the ActionBar and menus. 13021ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal mActivity.setDefaultKeyMode(Activity.DEFAULT_KEYS_SHORTCUT); 130380aeac5356b5a14a5ef2aff8f0f72a464c9a3cb4Vikram Aggarwal mResolver = mActivity.getContentResolver(); 13046ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook mNewEmailReceiver = new SuppressNotificationReceiver(); 13057c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal mRecentFolderList.initialize(mActivity); 130669a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal mVeiledMatcher.initialize(this); 13076ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook 13081a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux mFloatingComposeButton = mActivity.findViewById(R.id.compose_button); 13091a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux mFloatingComposeButton.setOnClickListener(this); 13105d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux 1311f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang if (isDrawerEnabled()) { 1312355dd90d120bc105f5ad37aa5a5c7449e665a566Andrew Sapperstein mDrawerToggle = new ActionBarDrawerToggle(mActivity, mDrawerContainer, 1313355dd90d120bc105f5ad37aa5a5c7449e665a566Andrew Sapperstein R.string.drawer_open, R.string.drawer_close); 1314f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerContainer.setDrawerListener(mDrawerListener); 1315f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerContainer.setDrawerShadow( 1316f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mContext.getResources().getDrawable(R.drawable.drawer_shadow), Gravity.START); 131712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 1318207e662df01c550a4894bec03219820528365508Rohan Shah // Disable default drawer indicator as we are setting the drawer indicator icons. 1319207e662df01c550a4894bec03219820528365508Rohan Shah // TODO(shahrk): Once we can disable/enable drawer animation, go back to using 1320207e662df01c550a4894bec03219820528365508Rohan Shah // drawer indicators. 1321207e662df01c550a4894bec03219820528365508Rohan Shah mDrawerToggle.setDrawerIndicatorEnabled(false); 1322375faf0f8cf1d1de1d4aca7b9a7598e168dc9bf3Rohan Shah mDrawerToggle.setHomeAsUpIndicator(R.drawable.ic_menu_wht_24dp); 1323f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang } else { 132452882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein final ActionBar ab = mActivity.getSupportActionBar(); 1325375faf0f8cf1d1de1d4aca7b9a7598e168dc9bf3Rohan Shah ab.setHomeAsUpIndicator(R.drawable.ic_menu_wht_24dp); 1326f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang ab.setHomeActionContentDescription(R.string.drawer_open); 1327f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang ab.setDisplayHomeAsUpEnabled(true); 1328f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang } 132912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 1330161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira // All the individual UI components listen for ViewMode changes. This 1331b849dfbda3c917f078a5c09f03906886c27ecbecMindy Pereira // simplifies the amount of logic in the AbstractActivityController, but increases the 1332b849dfbda3c917f078a5c09f03906886c27ecbecMindy Pereira // possibility of timing-related bugs. 13331ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal mViewMode.addListener(this); 1334632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mPagerController = new ConversationPagerController(mActivity, this); 13359a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux mToastBar = findActionableToastBar(mActivity); 1336ada517849ada8a3c3a62d81c5163f392bc674eb7Vikram Aggarwal attachActionBar(); 13371ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 1338144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang mDrawIdler.setRootView(mActivity.getWindow().getDecorView()); 1339144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang 1340632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final Intent intent = mActivity.getIntent(); 13414fe0af81874976a1995191321e35c844b2229811Andy Huang 1342c6801eb828627c37b8992584767c095dfe11df62Jin Cao mSearchViewController = new MaterialSearchViewController(mActivity, this, intent, 1343c6801eb828627c37b8992584767c095dfe11df62Jin Cao savedState); 1344524ded5f9d27dda75c53d256922a39c867857575Jin Cao addConversationListLayoutListener(mSearchViewController); 1345c6801eb828627c37b8992584767c095dfe11df62Jin Cao 1346abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal // Immediately handle a clean launch with intent, and any state restoration 1347632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // that does not rely on restored fragments or loader data 1348632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // any state restoration that relies on those can be done later in 1349632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // onRestoreInstanceState, once fragments are up and loader data is re-delivered 1350632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (savedState != null) { 1351632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (savedState.containsKey(SAVED_ACCOUNT)) { 1352632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang setAccount((Account) savedState.getParcelable(SAVED_ACCOUNT)); 1353632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 1354632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (savedState.containsKey(SAVED_FOLDER)) { 13552bc8bc1f69faacaddab41ab61e1d2e8658f4181fAndy Huang final Folder folder = savedState.getParcelable(SAVED_FOLDER); 1356203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal final String query = savedState.getString(SAVED_QUERY, null); 1357649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal setListContext(folder, query); 1358632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 13596cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal if (savedState.containsKey(SAVED_ACTION)) { 13606cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal mDialogAction = savedState.getInt(SAVED_ACTION); 13616cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal } 1362a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal mDialogFromSelectedSet = savedState.getBoolean(SAVED_ACTION_FROM_SELECTED, false); 1363649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal mViewMode.handleRestore(savedState); 1364632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } else if (intent != null) { 1365632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang handleIntent(intent); 1366632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 1367632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // Create the accounts loader; this loads the account switch spinner. 1368177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, Bundle.EMPTY, 1369177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mAccountCallbacks); 1370b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang } 1371b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang 13729a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux /** 13739a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux * @param activity the activity that has been inflated 13749a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux * @return the Actionable Toast Bar defined within the activity 13759a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux */ 13769a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux protected ActionableToastBar findActionableToastBar(MailActivity activity) { 13779a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux return (ActionableToastBar) activity.findViewById(R.id.toast_bar); 13789a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux } 13799a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux 1380b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang @Override 138157246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook public void onPostCreate(Bundle savedState) { 1382f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang if (!isDrawerEnabled()) { 1383f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang return; 1384f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang } 138512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // Sync the toggle state after onRestoreInstanceState has occurred. 138612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerToggle.syncState(); 13875747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein 1388d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal mHideMenuItems = isDrawerEnabled() && mDrawerContainer.isDrawerOpen(mDrawerPullout); 138957246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook } 139057246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook 139157246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook @Override 139257246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook public void onConfigurationChanged(Configuration newConfig) { 1393f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang if (isDrawerEnabled()) { 1394f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerToggle.onConfigurationChanged(newConfig); 1395f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang } 139612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 139712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 139812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang /** 13995d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux * This controller listens for clicks on items in the floating action bar. 14005d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux * 14015d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux * @param view the item that was clicked in the floating action bar 14025d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux */ 14035d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux @Override 14045d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux public void onClick(View view) { 140553de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein final int viewId = view.getId(); 140653de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein if (viewId == R.id.compose_button) { 140753de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein ComposeActivity.compose(mActivity.getActivityContext(), getAccount()); 140853de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein } else if (viewId == android.R.id.home) { 140953de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein // TODO: b/16627877 1410405a344937675f57fc9c6988b2b124410a270f13Jin Cao handleUpPress(); 141153de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein } 14125d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux } 14135d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux 14145d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux /** 141512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * If drawer is open/visible (even partially), close it. 141612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang */ 141712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang protected void closeDrawerIfOpen() { 141812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (!isDrawerEnabled()) { 141912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang return; 142012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 142112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if(mDrawerContainer.isDrawerOpen(mDrawerPullout)) { 142212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.closeDrawers(); 142312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 142457246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook } 142557246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook 142657246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook @Override 14271ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang public void onStart() { 14281ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang mSafeToModifyFragments = true; 1429cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy 1430cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy NotificationActionUtils.registerUndoNotificationObserver(mUndoNotificationObserver); 1431761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang 1432761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang if (mViewMode.getMode() != ViewMode.UNKNOWN) { 1433761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang Analytics.getInstance().sendView("MainActivity" + mViewMode.toString()); 1434761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang } 14351ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 14361ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 14371ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang @Override 143800179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein public void onRestart() { 1439177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final DialogFragment fragment = (DialogFragment) 144000179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein mFragmentManager.findFragmentByTag(SYNC_ERROR_DIALOG_FRAGMENT_TAG); 144100179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein if (fragment != null) { 144200179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein fragment.dismiss(); 144300179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 1444ea04f938bef8e2ec7c6f64067511f006681318fbmindyp // When the user places the app in the background by pressing "home", 1445ea04f938bef8e2ec7c6f64067511f006681318fbmindyp // dismiss the toast bar. However, since there is no way to determine if 1446ea04f938bef8e2ec7c6f64067511f006681318fbmindyp // home was pressed, just dismiss any existing toast bar when restarting 1447ea04f938bef8e2ec7c6f64067511f006681318fbmindyp // the app. 1448ea04f938bef8e2ec7c6f64067511f006681318fbmindyp if (mToastBar != null) { 1449f8ccdcfc26f362d9c20771e2295a0c0e8d1195f3Andrew Sapperstein mToastBar.hide(false, false /* actionClicked */); 1450ea04f938bef8e2ec7c6f64067511f006681318fbmindyp } 145100179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 145200179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein 145300179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein @Override 14541ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public Dialog onCreateDialog(int id, Bundle bundle) { 14551ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal return null; 14561ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 14571ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 1458a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 14594eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal public final boolean onCreateOptionsMenu(Menu menu) { 14600fa9efd6df21a92866908ab679a78b7a128bc28fAndrew Sapperstein if (mViewMode.isAdMode()) { 14610fa9efd6df21a92866908ab679a78b7a128bc28fAndrew Sapperstein return false; 14620fa9efd6df21a92866908ab679a78b7a128bc28fAndrew Sapperstein } 1463e5e917c10cbc4afd31358c0425954e2c27e0fb8eVikram Aggarwal final MenuInflater inflater = mActivity.getMenuInflater(); 14642d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein inflater.inflate(mActionBarController.getOptionsMenuId(), menu); 14652d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.onCreateOptionsMenu(menu); 146628d5f72e0ad0db75b6243ee8125bfe3aadbdcb85Mindy Pereira return true; 1467a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 1468a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 1469a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 14704eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal public final boolean onKeyDown(int keyCode, KeyEvent event) { 1471b9e1a353c6a173a2885642dbcc1939f3281f29f7Vikram Aggarwal return false; 14721ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 14731ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 147417a8e78d61bff414610e23f24889bab29955f54emindyp public abstract boolean doesActionChangeConversationListVisibility(int action); 147517a8e78d61bff414610e23f24889bab29955f54emindyp 147630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao /** 147730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * Helper function that determines if we should associate an undo callback with 147830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * the current menu action item 147930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * @param actionId the id of the action 148030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * @return the appropriate callback handler, or null if not applicable 148130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao */ 148230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao private UndoCallback getUndoCallbackForDestructiveActionsWithAutoAdvance( 148330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao int actionId, final Conversation conv) { 148430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // We associated the undoCallback if the user is going to perform an action on the current 148530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // conversation, causing the current conversation to be removed from view and replacing it 148630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // with another (via Auto Advance). The undoCallback will bring the removed conversation 148730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // back into the view if the action is undone. 148830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final Collection<Conversation> convCol = Conversation.listOf(conv); 148930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final boolean isApplicableForReshow = mAccount != null && 149030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mAccount.settings != null && 149130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mTracker != null && 149230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // ensure that we will show another conversation due to Auto Advance 149330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mTracker.getNextConversation( 149430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mAccount.settings.getAutoAdvanceSetting(), convCol) != null && 149530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // ensure that we are performing the action from conversation view 149630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao isCurrentConversationInView(convCol) && 149730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // check for the appropriate destructive actions 149830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao doesActionRemoveCurrentConversationFromView(actionId); 149930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return (isApplicableForReshow) ? 150030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao new UndoCallback() { 150130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao @Override 150230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public void performUndoCallback() { 150330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao showConversation(conv); 150430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 150530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } : null; 150630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 150730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 150830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao /** 150930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * Check if the provided action will remove the active conversation from view 151030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * @param actionId the applied action 151130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * @return true if it will remove the conversation from view, false otherwise 151230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao */ 151330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao private boolean doesActionRemoveCurrentConversationFromView(int actionId) { 151430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return actionId == R.id.archive || 151530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao actionId == R.id.delete || 1516512821c11d89d49908f3cfdee0b582601f500f3dJin Cao actionId == R.id.discard_outbox || 151730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao actionId == R.id.remove_folder || 151830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao actionId == R.id.report_spam || 151930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao actionId == R.id.report_phishing || 152030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao actionId == R.id.move_to; 152130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 152230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 15231ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 152457246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook public boolean onOptionsItemSelected(MenuItem item) { 1525761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang 152612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang /* 152712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * The action bar home/up action should open or close the drawer. 152812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * mDrawerToggle will take care of this. 152912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang */ 1530f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang if (isDrawerEnabled() && mDrawerToggle.onOptionsItemSelected(item)) { 1531042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang Analytics.getInstance().sendEvent(Analytics.EVENT_CATEGORY_MENU_ITEM, "drawer_toggle", 1532042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang null, 0); 153312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang return true; 153412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 153512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 15362b55549d4fbe25e91f673a0727fc89ff755d9327Andy Huang Analytics.getInstance().sendMenuItemEvent(Analytics.EVENT_CATEGORY_MENU_ITEM, 1537f8c59b0198bd3230ef669c5e258b86443e7ed682Andy Huang item.getItemId(), "action_bar/" + mViewMode.getModeString(), 0); 1538042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang 153954452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal final int id = item.getItemId(); 15407dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal LogUtils.d(LOG_TAG, "AbstractController.onOptionsItemSelected(%d) called.", id); 154184fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal /** This is NOT a batch action. */ 154284fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal final boolean isBatch = false; 1543ba68fdaf4f251eccba0832878a74bdaf6aa7469eMindy Pereira final Collection<Conversation> target = Conversation.listOf(mCurrentConversation); 1544112cd16335e1ca56c96d005aa3b5bb11508396dcVikram Aggarwal final Settings settings = (mAccount == null) ? null : mAccount.settings; 154584f7d32bdc79263004ed5241480988e02f8e618cmindyp // The user is choosing a new action; commit whatever they had been 154617a8e78d61bff414610e23f24889bab29955f54emindyp // doing before. Don't animate if we are launching a new screen. 154717a8e78d61bff414610e23f24889bab29955f54emindyp commitDestructiveActions(!doesActionChangeConversationListVisibility(id)); 154830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final UndoCallback undoCallback = getUndoCallbackForDestructiveActionsWithAutoAdvance( 154930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao id, mCurrentConversation); 155030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 15512d7d1eeb7ac15f09b7129860179bf5de62a85009Jin Cao // Menu items that are targetted, only perform if there actually is a target and the 15522d7d1eeb7ac15f09b7129860179bf5de62a85009Jin Cao // cursor is showing the target in the list. 1553a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao boolean handled = false; 15542d7d1eeb7ac15f09b7129860179bf5de62a85009Jin Cao if (target.size() > 0 && 15552d7d1eeb7ac15f09b7129860179bf5de62a85009Jin Cao ConversationCursor.isCursorReadyToShow(getConversationListCursor())) { 1556a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao handled = true; 1557a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao if (id == R.id.archive) { 1558a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao final boolean showDialog = (settings != null && settings.confirmArchive); 1559a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao confirmAndDelete(id, target, showDialog, R.plurals.confirm_archive_conversation, 1560a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao undoCallback); 1561a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.remove_folder) { 1562a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao delete(R.id.remove_folder, target, 1563a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao getDeferredRemoveFolder(target, mFolder, true, isBatch, true, undoCallback), 156430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao isBatch); 1565a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.delete) { 1566a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao final boolean showDialog = (settings != null && settings.confirmDelete); 1567a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao confirmAndDelete(id, target, showDialog, R.plurals.confirm_delete_conversation, 1568a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao undoCallback); 1569a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.discard_drafts) { 1570a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao // drafts are lost forever, so always confirm 1571a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao confirmAndDelete(id, target, true /* showDialog */, 1572a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao R.plurals.confirm_discard_drafts_conversation, undoCallback); 1573a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.discard_outbox) { 1574a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao // discard in outbox means we discard the failed message and save them in drafts 1575a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao delete(id, target, getDeferredAction(id, target, isBatch, undoCallback), isBatch); 1576a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.mark_important) { 15772b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy updateConversation(Conversation.listOf(mCurrentConversation), 1578a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao ConversationColumns.PRIORITY, UIProvider.ConversationPriority.HIGH); 1579a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.mark_not_important) { 1580a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao if (mFolder != null && mFolder.isImportantOnly()) { 1581a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao delete(R.id.mark_not_important, target, 1582a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao getDeferredAction(R.id.mark_not_important, target, isBatch, undoCallback), 1583a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao isBatch); 1584a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else { 1585a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao updateConversation(target, ConversationColumns.PRIORITY, 1586a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao UIProvider.ConversationPriority.LOW); 1587a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } 1588a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.mute) { 1589a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao delete(R.id.mute, target, getDeferredAction(R.id.mute, target, isBatch, undoCallback), 1590a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao isBatch); 1591a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.report_spam) { 1592a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao delete(R.id.report_spam, target, 1593a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao getDeferredAction(R.id.report_spam, target, isBatch, undoCallback), 1594a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao isBatch); 1595a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.mark_not_spam) { 1596a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao // Currently, since spam messages are only shown in list with 1597a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao // other spam messages, 1598a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao // marking a message not as spam is a destructive action 1599a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao delete(R.id.mark_not_spam, target, 1600a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao getDeferredAction(R.id.mark_not_spam, target, isBatch, undoCallback), 1601a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao isBatch); 1602a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.report_phishing) { 1603a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao delete(R.id.report_phishing, target, 1604a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao getDeferredAction(R.id.report_phishing, target, isBatch, undoCallback), 1605a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao isBatch); 1606a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.move_to || id == R.id.change_folders) { 1607a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao final FolderSelectionDialog dialog = FolderSelectionDialog.getInstance(mAccount, 1608a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao target, isBatch, mFolder, id == R.id.move_to); 1609a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao if (dialog != null) { 1610a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao dialog.show(mActivity.getFragmentManager(), null); 1611a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } 1612a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.move_to_inbox) { 1613a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao new AsyncTask<Void, Void, Folder>() { 1614a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao @Override 1615a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao protected Folder doInBackground(final Void... params) { 1616a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao // Get the "move to" inbox 1617a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao return Utils.getFolder(mContext, mAccount.settings.moveToInbox, 1618a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao true /* allowHidden */); 1619a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } 1620a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao 1621a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao @Override 1622a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao protected void onPostExecute(final Folder moveToInbox) { 1623a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao final List<FolderOperation> ops = Lists.newArrayListWithCapacity(1); 1624a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao // Add inbox 1625a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao ops.add(new FolderOperation(moveToInbox, true)); 1626a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao assignFolder(ops, target, true, true /* showUndo */, false /* isMoveTo */); 1627a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } 1628a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao }.execute((Void[]) null); 1629a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else { 1630a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao handled = false; 1631ba68fdaf4f251eccba0832878a74bdaf6aa7469eMindy Pereira } 1632a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } 1633a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao 1634a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao // Not handled by the targetted menu items, check the general ones. 1635a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao if (!handled) { 1636a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao handled = true; 1637a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao if (id == android.R.id.home) { 1638a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao handleUpPress(); 1639a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.compose) { 1640a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao ComposeActivity.compose(mActivity.getActivityContext(), mAccount); 1641a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.refresh) { 1642a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao requestFolderRefresh(); 1643a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.toggle_drawer) { 1644a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao toggleDrawerState(); 1645a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.settings) { 1646a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao Utils.showSettings(mActivity.getActivityContext(), mAccount); 1647a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.help_info_menu_item) { 1648a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao mActivity.showHelp(mAccount, mViewMode.getMode()); 1649a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.empty_trash) { 1650a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao showEmptyDialog(); 1651a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.empty_spam) { 1652a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao showEmptyDialog(); 1653a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else if (id == R.id.search) { 1654a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao mSearchViewController.showSearchActionBar( 1655a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao MaterialSearchViewController.SEARCH_VIEW_STATE_VISIBLE); 1656a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } else { 1657a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao handled = false; 1658a8e4318bb9921e2ec6045c5f7187a4b78c55fe10Vikram Aggarwal } 1659a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao } 1660dd2ec688cf18e0ec132d936168ccaa3c43cdefb1Scott Kennedy 1661a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao // If the controller didn't handle this event, check the CAB menu if it's active. 1662a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao // This is necessary because keyboard shortcuts don't seem to check CAB menus. 1663a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao if (!handled && mCabActionMenu != null && mCabActionMenu.isActivated() && 1664a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao mCabActionMenu.onActionItemClicked(item)) { 1665a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao handled = true; 166628d5f72e0ad0db75b6243ee8125bfe3aadbdcb85Mindy Pereira } 1667a6b45218b8d90d7fc3a5ca0901293c71df404553Jin Cao 16689b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira return handled; 1669a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 1670a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 1671ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein /** 1672ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein * Opens an {@link EmptyFolderDialogFragment} for the current folder. 1673ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein */ 1674ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein private void showEmptyDialog() { 1675ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein if (mFolder != null) { 1676ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein final EmptyFolderDialogFragment fragment = 1677ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein EmptyFolderDialogFragment.newInstance(mFolder.totalCount, mFolder.type); 1678ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein fragment.setListener(this); 1679ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein fragment.show(mActivity.getFragmentManager(), EmptyFolderDialogFragment.FRAGMENT_TAG); 1680ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein } 1681ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein } 1682ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein 1683ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein @Override 1684ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein public void onFolderEmptied() { 1685ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein emptyFolder(); 1686ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein } 1687ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein 1688ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein /** 1689ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein * Performs the work of emptying the currently visible folder. 1690ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein */ 16917ee089ea2ef96e31504e88637b5f3b0969b3c7c1Scott Kennedy private void emptyFolder() { 16921d0f1f839023e405b24ffc6a670b5c26b36f24e0Yorke Lee if (mConversationListCursor != null) { 16931d0f1f839023e405b24ffc6a670b5c26b36f24e0Yorke Lee mConversationListCursor.emptyFolder(); 16941d0f1f839023e405b24ffc6a670b5c26b36f24e0Yorke Lee } 16957ee089ea2ef96e31504e88637b5f3b0969b3c7c1Scott Kennedy } 16967ee089ea2ef96e31504e88637b5f3b0969b3c7c1Scott Kennedy 1697ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein private void attachEmptyFolderDialogFragmentListener() { 1698ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein final EmptyFolderDialogFragment fragment = 1699ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein (EmptyFolderDialogFragment) mActivity.getFragmentManager() 1700ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein .findFragmentByTag(EmptyFolderDialogFragment.FRAGMENT_TAG); 1701ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein 1702ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein if (fragment != null) { 1703ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein fragment.setListener(this); 1704ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein } 1705ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein } 1706ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein 17078e65c6d2527c7539b689e0e8548c84f690badca5Rohan Shah /** 170812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * Toggles the drawer pullout. If it was open (Fully extended), the 170912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * drawer will be closed. Otherwise, the drawer will be opened. This should 171012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * only be called when used with a toggle item. Other cases should be handled 171112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * explicitly with just closeDrawers() or openDrawer(View drawerView); 17128e65c6d2527c7539b689e0e8548c84f690badca5Rohan Shah */ 1713d9eaca8676ad4c6c58122fd41be799872bfd9cdaTony Mantler protected void toggleDrawerState() { 171412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (!isDrawerEnabled()) { 171512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang return; 171612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 171712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if(mDrawerContainer.isDrawerOpen(mDrawerPullout)) { 171812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.closeDrawers(); 171912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } else { 172012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.openDrawer(mDrawerPullout); 172112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 17228e65c6d2527c7539b689e0e8548c84f690badca5Rohan Shah } 17238e65c6d2527c7539b689e0e8548c84f690badca5Rohan Shah 1724531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal @Override 1725c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang public final boolean onBackPressed() { 172612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (isDrawerEnabled() && mDrawerContainer.isDrawerVisible(mDrawerPullout)) { 172712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.closeDrawers(); 172812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang return true; 1729c6801eb828627c37b8992584767c095dfe11df62Jin Cao } else if (mSearchViewController.handleBackPress()) { 1730c6801eb828627c37b8992584767c095dfe11df62Jin Cao return true; 17314c92874d9acedc81184339645b24eaeebacbb782Andrew Sapperstein // If we're in CAB mode, let the activity handle onBackPressed. 17324c92874d9acedc81184339645b24eaeebacbb782Andrew Sapperstein // It will handle closing CAB mode for us. 17334c92874d9acedc81184339645b24eaeebacbb782Andrew Sapperstein } else if (mCabActionMenu != null && mCabActionMenu.isActivated()) { 17344c92874d9acedc81184339645b24eaeebacbb782Andrew Sapperstein return false; 173512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 173612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 1737c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang return handleBackPress(); 1738c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang } 1739c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang 1740c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang protected abstract boolean handleBackPress(); 1741ede2e52e725abc625ae963f979639ff8ecc40cf5Greg Bullock 1742c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang protected abstract boolean handleUpPress(); 1743c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang 1744c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang @Override 17456c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira public void updateConversation(Collection<Conversation> target, ContentValues values) { 17469e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateValues(target, values); 17476c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira refreshConversationList(); 17486c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira } 17496c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira 17506c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira @Override 1751531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal public void updateConversation(Collection <Conversation> target, String columnName, 1752531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal boolean value) { 17539e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateBoolean(target, columnName, value); 175475daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal refreshConversationList(); 175554452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal } 175654452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal 1757531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal @Override 17586c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira public void updateConversation(Collection <Conversation> target, String columnName, 17596c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira int value) { 17609e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateInt(target, columnName, value); 176175daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal refreshConversationList(); 1762c9d59184da271d5a6974edb709e3b39a5a970fa7Mindy Pereira } 1763c9d59184da271d5a6974edb709e3b39a5a970fa7Mindy Pereira 1764531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal @Override 1765531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal public void updateConversation(Collection <Conversation> target, String columnName, 1766531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal String value) { 17679e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateString(target, columnName, value); 176875daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal refreshConversationList(); 176954452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal } 177054452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal 1771839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang @Override 17727c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu public void markConversationMessagesUnread(final Conversation conv, 17737c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu final Set<Uri> unreadMessageUris, final byte[] originalConversationInfo) { 177487a8982af83168453b6dc219fe984bff68047bebAndy Huang onPreMarkUnread(); 17758f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang 1776839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // locally mark conversation unread (the provider is supposed to propagate message unread 1777839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // to conversation unread) 1778839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang conv.read = false; 17791faf93d79a00acb0fe607495c39f87d53a05889bPaul Westbrook if (mConversationListCursor == null) { 178081230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, "markConversationMessagesUnread(id=%d), deferring", conv.id); 17817c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu 17827c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu mConversationListLoadFinishedCallbacks.add(new LoadFinishedCallback() { 17837c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu @Override 17847c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu public void onLoadFinished() { 17857c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu doMarkConversationMessagesUnread(conv, unreadMessageUris, 17867c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu originalConversationInfo); 17877c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } 17887c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu }); 17897c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } else { 179081230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, "markConversationMessagesUnread(id=%d), performing", conv.id); 17917c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu doMarkConversationMessagesUnread(conv, unreadMessageUris, originalConversationInfo); 17921faf93d79a00acb0fe607495c39f87d53a05889bPaul Westbrook } 17937c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } 17941faf93d79a00acb0fe607495c39f87d53a05889bPaul Westbrook 179587a8982af83168453b6dc219fe984bff68047bebAndy Huang /** 179687a8982af83168453b6dc219fe984bff68047bebAndy Huang * Hook to do stuff before actually marking a conversation unread (only called from within 179787a8982af83168453b6dc219fe984bff68047bebAndy Huang * conversation view). Most configurations do the default behavior of popping out of 179887a8982af83168453b6dc219fe984bff68047bebAndy Huang * CV to go back to TL. 179987a8982af83168453b6dc219fe984bff68047bebAndy Huang * 180087a8982af83168453b6dc219fe984bff68047bebAndy Huang */ 180187a8982af83168453b6dc219fe984bff68047bebAndy Huang protected void onPreMarkUnread() { 180287a8982af83168453b6dc219fe984bff68047bebAndy Huang // The only caller of this method is the conversation view, from where marking unread should 180387a8982af83168453b6dc219fe984bff68047bebAndy Huang // take you back to list mode in most cases. Two-pane view is the exception. 180487a8982af83168453b6dc219fe984bff68047bebAndy Huang showConversation(null); 180587a8982af83168453b6dc219fe984bff68047bebAndy Huang } 180687a8982af83168453b6dc219fe984bff68047bebAndy Huang 18077c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu private void doMarkConversationMessagesUnread(Conversation conv, Set<Uri> unreadMessageUris, 18087c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu byte[] originalConversationInfo) { 180981230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal // Only do a granular 'mark unread' if a subset of messages are unread 181028e31e2417d775b343919cf6018f85871e40a294Andy Huang final int unreadCount = (unreadMessageUris == null) ? 0 : unreadMessageUris.size(); 18110972e0793cc321670391d063348aecb5031b2677Mindy Pereira final int numMessages = conv.getNumMessages(); 18120972e0793cc321670391d063348aecb5031b2677Mindy Pereira final boolean subsetIsUnread = (numMessages > 1 && unreadCount > 0 18130972e0793cc321670391d063348aecb5031b2677Mindy Pereira && unreadCount < numMessages); 181428e31e2417d775b343919cf6018f85871e40a294Andy Huang 18159e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huang LogUtils.d(LOG_TAG, "markConversationMessagesUnread(conv=%s)" 181681230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal + ", numMessages=%d, unreadCount=%d, subsetIsUnread=%b", 18179e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huang conv, numMessages, unreadCount, subsetIsUnread); 181828e31e2417d775b343919cf6018f85871e40a294Andy Huang if (!subsetIsUnread) { 181966bc2aaf76bb0dfa4fc38f8fcbaaf9e413e321ddVikram Aggarwal // Conversations are neither marked read, nor viewed, and we don't want to show 182066bc2aaf76bb0dfa4fc38f8fcbaaf9e413e321ddVikram Aggarwal // the next conversation. 182181230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, ". . doing full mark unread"); 1822caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy markConversationsRead(Collections.singletonList(conv), false, false, false); 1823839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } else { 182481230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) { 182581230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal final ConversationInfo info = ConversationInfo.fromBlob(originalConversationInfo); 182681230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, ". . doing subset mark unread, originalConversationInfo = %s", 182781230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal info); 182881230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal } 1829daa06aba887e8e3748453f45ae52c1e571fe9f2eAndy Huang mConversationListCursor.setConversationColumn(conv.uri, ConversationColumns.READ, 0); 1830839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 183181230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal // Locally update conversation's conversationInfo to revert to original version 183228e31e2417d775b343919cf6018f85871e40a294Andy Huang if (originalConversationInfo != null) { 183328e31e2417d775b343919cf6018f85871e40a294Andy Huang mConversationListCursor.setConversationColumn(conv.uri, 183428e31e2417d775b343919cf6018f85871e40a294Andy Huang ConversationColumns.CONVERSATION_INFO, originalConversationInfo); 183528e31e2417d775b343919cf6018f85871e40a294Andy Huang } 1836839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 1837839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // applyBatch with each CPO as an UPDATE op on each affected message uri 1838839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang final ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 1839839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang String authority = null; 1840839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang for (Uri messageUri : unreadMessageUris) { 1841839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang if (authority == null) { 1842839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang authority = messageUri.getAuthority(); 1843839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1844839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang ops.add(ContentProviderOperation.newUpdate(messageUri) 1845839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang .withValue(UIProvider.MessageColumns.READ, 0) 1846839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang .build()); 184781230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, ". . Adding op: read=0, uri=%s", messageUri); 1848839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 184981230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, ". . operations = %s", ops); 1850839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang new ContentProviderTask() { 1851839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang @Override 1852839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang protected void onPostExecute(Result result) { 1853d9895b65e074a2cd68ad2aaa87d7b49f05bacdbeVikram Aggarwal if (result.exception != null) { 1854d9895b65e074a2cd68ad2aaa87d7b49f05bacdbeVikram Aggarwal LogUtils.e(LOG_TAG, result.exception, "ContentProviderTask() ERROR."); 1855d9895b65e074a2cd68ad2aaa87d7b49f05bacdbeVikram Aggarwal } else { 18569e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huang LogUtils.d(LOG_TAG, "ContentProviderTask(): success %s", 18579e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huang Arrays.toString(result.results)); 1858d9895b65e074a2cd68ad2aaa87d7b49f05bacdbeVikram Aggarwal } 1859839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1860839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang }.run(mResolver, authority, ops); 1861839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1862839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1863839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 186487a8982af83168453b6dc219fe984bff68047bebAndy Huang /** 186587a8982af83168453b6dc219fe984bff68047bebAndy Huang * Mark a single conversation 'seen', which is a combination of 'viewed' and 'read'. In some 186687a8982af83168453b6dc219fe984bff68047bebAndy Huang * configurations (peek mode), this operation may be prevented and the method will return false. 186787a8982af83168453b6dc219fe984bff68047bebAndy Huang * 186887a8982af83168453b6dc219fe984bff68047bebAndy Huang * @param conv the conversation to mark seen 186987a8982af83168453b6dc219fe984bff68047bebAndy Huang * @return true if the operation was a success 187087a8982af83168453b6dc219fe984bff68047bebAndy Huang */ 187187a8982af83168453b6dc219fe984bff68047bebAndy Huang @Override 187287a8982af83168453b6dc219fe984bff68047bebAndy Huang public boolean markConversationSeen(Conversation conv) { 187387a8982af83168453b6dc219fe984bff68047bebAndy Huang if (isCurrentConversationJustPeeking()) { 187487a8982af83168453b6dc219fe984bff68047bebAndy Huang LogUtils.i(LOG_TAG, "AAC is in peek mode, not marking seen. conv=%s", conv); 187587a8982af83168453b6dc219fe984bff68047bebAndy Huang return false; 187687a8982af83168453b6dc219fe984bff68047bebAndy Huang } else { 187787a8982af83168453b6dc219fe984bff68047bebAndy Huang markConversationsRead(Arrays.asList(conv), true /* read */, true /* viewed */); 187887a8982af83168453b6dc219fe984bff68047bebAndy Huang return true; 187987a8982af83168453b6dc219fe984bff68047bebAndy Huang } 188087a8982af83168453b6dc219fe984bff68047bebAndy Huang } 188187a8982af83168453b6dc219fe984bff68047bebAndy Huang 1882839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang @Override 18837c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu public void markConversationsRead(final Collection<Conversation> targets, final boolean read, 18847c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu final boolean viewed) { 1885919d01a1144dc14f114860949ff4af79a9165ec7Scott Kennedy LogUtils.d(LOG_TAG, "markConversationsRead(targets=%s)", targets.toArray()); 1886919d01a1144dc14f114860949ff4af79a9165ec7Scott Kennedy 18877c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu if (mConversationListCursor == null) { 188881230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) { 188981230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, "markConversationsRead(targets=%s), deferring", 189081230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal targets.toArray()); 189181230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal } 18927c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu mConversationListLoadFinishedCallbacks.add(new LoadFinishedCallback() { 18937c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu @Override 18947c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu public void onLoadFinished() { 1895caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy markConversationsRead(targets, read, viewed, true); 18967c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } 18977c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu }); 18987c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } else { 18997c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu // We want to show the next conversation if we are marking unread. 1900caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy markConversationsRead(targets, read, viewed, true); 19017c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } 19028f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang } 19038f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang 19040d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy private void markConversationsRead(final Collection<Conversation> targets, final boolean read, 1905caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy final boolean markViewed, final boolean showNext) { 19067c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu LogUtils.d(LOG_TAG, "performing markConversationsRead"); 1907cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal // Auto-advance if requested and the current conversation is being marked unread 19088f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang if (showNext && !read) { 19090d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy final Runnable operation = new Runnable() { 19100d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy @Override 19110d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy public void run() { 1912caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy markConversationsRead(targets, read, markViewed, showNext); 19130d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy } 19140d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy }; 19150d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 1916caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy if (!showNextConversation(targets, operation)) { 19170d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy // This method will be called again if the user selects an autoadvance option 19180d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy return; 19190d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy } 19208f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang } 19210d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 1922cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal final int size = targets.size(); 1923cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal final List<ConversationOperation> opList = new ArrayList<ConversationOperation>(size); 1924cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal for (final Conversation target : targets) { 1925e2be97a58fbae98b95e51735c6468d121e465355Paul Westbrook final ContentValues value = new ContentValues(4); 1926cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal value.put(ConversationColumns.READ, read); 19275109c516b5cac279b4f99271953a27dd9a4828d8Paul Westbrook 1928d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy // We never want to mark unseen here, but we do want to mark it seen 1929d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (read || markViewed) { 1930d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy value.put(ConversationColumns.SEEN, Boolean.TRUE); 1931d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy } 1932d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy 19335109c516b5cac279b4f99271953a27dd9a4828d8Paul Westbrook // The mark read/unread/viewed operations do not show an undo bar 19345109c516b5cac279b4f99271953a27dd9a4828d8Paul Westbrook value.put(ConversationOperations.Parameters.SUPPRESS_UNDO, true); 193566bc2aaf76bb0dfa4fc38f8fcbaaf9e413e321ddVikram Aggarwal if (markViewed) { 1936cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal value.put(ConversationColumns.VIEWED, true); 193766bc2aaf76bb0dfa4fc38f8fcbaaf9e413e321ddVikram Aggarwal } 1938192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal final ConversationInfo info = target.conversationInfo; 1939edd6c1a2807d2ade930dfd4622707298dc470d64Tony Mantler final boolean changed = info.markRead(read); 1940edd6c1a2807d2ade930dfd4622707298dc470d64Tony Mantler if (changed) { 1941edd6c1a2807d2ade930dfd4622707298dc470d64Tony Mantler value.put(ConversationColumns.CONVERSATION_INFO, info.toBlob()); 1942839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1943cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal opList.add(mConversationListCursor.getOperationForConversation( 1944cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal target, ConversationOperation.UPDATE, value)); 1945cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal // Update the local conversation objects so they immediately change state. 1946cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal target.read = read; 1947cd5c5eeae167885ffa2959c200233fea2f39c5f7Andy Huang if (markViewed) { 1948cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal target.markViewed(); 1949cd5c5eeae167885ffa2959c200233fea2f39c5f7Andy Huang } 1950839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 19519e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateBulkValues(opList); 1952839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1953839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 19548f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang /** 19558f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang * Auto-advance to a different conversation if the currently visible conversation in 19568f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang * conversation mode is affected (deleted, marked unread, etc.). 19578f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang * 19580d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * <p>Does nothing if outside of conversation mode.</p> 19598f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang * 19608f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang * @param target the set of conversations being deleted/marked unread 19618f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang */ 19629365a826b46b0e274df88e92534f7d871eef2aa2mindyp @Override 19630d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy public void showNextConversation(final Collection<Conversation> target) { 1964caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy showNextConversation(target, null); 19650d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy } 19660d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 19670d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy /** 196830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * Helper function to determine if the provided set of conversations is in view 196930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * @param target set of conversations that we are interested in 197030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * @return true if they are in view, false otherwise 197130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao */ 197230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao private boolean isCurrentConversationInView(final Collection<Conversation> target) { 197330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final int viewMode = mViewMode.getMode(); 197430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return (viewMode == ViewMode.CONVERSATION 197530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao || viewMode == ViewMode.SEARCH_RESULTS_CONVERSATION) 197630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao && Conversation.contains(target, mCurrentConversation); 197730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 197830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 197930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao /** 19800d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * Auto-advance to a different conversation if the currently visible conversation in 19810d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * conversation mode is affected (deleted, marked unread, etc.). 19820d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * 19830d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * <p>Does nothing if outside of conversation mode.</p> 1984c94d07f4460d00db898237603de311d226707a96Andy Huang * <p> 1985c94d07f4460d00db898237603de311d226707a96Andy Huang * Clients may pass an operation to execute on the target that this method will run after 1986c94d07f4460d00db898237603de311d226707a96Andy Huang * auto-advance is complete. The operation, if provided, may run immediately, or it may run 1987c94d07f4460d00db898237603de311d226707a96Andy Huang * later, or not at all. Reasons it may run later include: 1988c94d07f4460d00db898237603de311d226707a96Andy Huang * <ul> 1989c94d07f4460d00db898237603de311d226707a96Andy Huang * <li>the auto-advance setting is uninitialized and we need to wait for the user to set it</li> 1990c94d07f4460d00db898237603de311d226707a96Andy Huang * <li>auto-advance in this configuration requires a mode change, and we need to wait for the 1991c94d07f4460d00db898237603de311d226707a96Andy Huang * mode change transition to finish</li> 1992c94d07f4460d00db898237603de311d226707a96Andy Huang * </ul> 1993c94d07f4460d00db898237603de311d226707a96Andy Huang * <p>If the current conversation is not in the target collection, this method will do nothing, 1994c94d07f4460d00db898237603de311d226707a96Andy Huang * and will not execute the operation. 19950d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * 19960d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * @param target the set of conversations being deleted/marked unread 1997c94d07f4460d00db898237603de311d226707a96Andy Huang * @param operation (optional) the operation to execute after advancing 1998c94d07f4460d00db898237603de311d226707a96Andy Huang * @return <code>false</code> if this method handled or will execute the operation, 1999c94d07f4460d00db898237603de311d226707a96Andy Huang * <code>true</code> otherwise. 20000d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy */ 20010d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy private boolean showNextConversation(final Collection<Conversation> target, 2002caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy final Runnable operation) { 200330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao if (isCurrentConversationInView(target)) { 20040d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy final int autoAdvanceSetting = mAccount.settings.getAutoAdvanceSetting(); 20050d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 200693e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler // If we don't have one set, but we're here, just take the default 200793e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler final int autoAdvance = (autoAdvanceSetting == AutoAdvance.UNSET) ? 200893e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler AutoAdvance.DEFAULT : autoAdvanceSetting; 20090d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 201093e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler // Set mAutoAdvanceOp *before* showConversation() to ensure that it runs when the 201193e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler // transition doesn't run (i.e. it "completes" immediately). 201293e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler mAutoAdvanceOp = operation; 201387a8982af83168453b6dc219fe984bff68047bebAndy Huang doShowNextConversation(target, autoAdvance); 201493e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler return (mAutoAdvanceOp == null); 20150d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy } 20160d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 201793e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler return true; 20188f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang } 20198f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang 202087a8982af83168453b6dc219fe984bff68047bebAndy Huang /** 202187a8982af83168453b6dc219fe984bff68047bebAndy Huang * Do the actual work of selecting a next conversation to show and showing it. Two-pane 202287a8982af83168453b6dc219fe984bff68047bebAndy Huang * overrides this in landscape to prefer peeking rather than staring at an empty CV pane when 202387a8982af83168453b6dc219fe984bff68047bebAndy Huang * auto-advance=LIST. 202487a8982af83168453b6dc219fe984bff68047bebAndy Huang * 202587a8982af83168453b6dc219fe984bff68047bebAndy Huang * @param target conversations being destroyed, of which the current convo is one 202687a8982af83168453b6dc219fe984bff68047bebAndy Huang * @param autoAdvance auto-advance pref value 202787a8982af83168453b6dc219fe984bff68047bebAndy Huang */ 202887a8982af83168453b6dc219fe984bff68047bebAndy Huang protected void doShowNextConversation(Collection<Conversation> target, int autoAdvance) { 202987a8982af83168453b6dc219fe984bff68047bebAndy Huang final Conversation next = mTracker.getNextConversation(autoAdvance, target); 203087a8982af83168453b6dc219fe984bff68047bebAndy Huang LogUtils.d(LOG_TAG, "showNextConversation: showing %s next.", next); 203187a8982af83168453b6dc219fe984bff68047bebAndy Huang showConversation(next); 203287a8982af83168453b6dc219fe984bff68047bebAndy Huang } 203387a8982af83168453b6dc219fe984bff68047bebAndy Huang 2034839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang @Override 2035839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang public void starMessage(ConversationMessage msg, boolean starred) { 2036839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang if (msg.starred == starred) { 2037839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang return; 2038839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 2039839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 2040b537167ea6f8acb3874dc6416e07a7101539639cTony Mantler msg.setStarredInConversation(starred); 2041839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 2042839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // locally propagate the change to the owning conversation 2043839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // (figure the provider will properly propagate the change when it commits it) 2044839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // 2045839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // when unstarring, only propagate the change if this was the only message starred 2046839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang final boolean conversationStarred = starred || msg.isConversationStarred(); 2047cd12e82dead8a920b060340c037d51b144966a73Andy Huang final Conversation conv = msg.getConversation(); 2048cd12e82dead8a920b060340c037d51b144966a73Andy Huang if (conversationStarred != conv.starred) { 2049cd12e82dead8a920b060340c037d51b144966a73Andy Huang conv.starred = conversationStarred; 2050cd12e82dead8a920b060340c037d51b144966a73Andy Huang mConversationListCursor.setConversationColumn(conv.uri, 2051839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang ConversationColumns.STARRED, conversationStarred); 2052839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 2053839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 2054839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang final ContentValues values = new ContentValues(1); 2055839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang values.put(UIProvider.MessageColumns.STARRED, starred ? 1 : 0); 2056839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 2057839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang new ContentProviderTask.UpdateTask() { 2058839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang @Override 2059839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang protected void onPostExecute(Result result) { 2060839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // TODO: handle errors? 2061839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 2062839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang }.run(mResolver, msg.uri, values, null /* selection*/, null /* selectionArgs */); 2063839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 2064839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 206512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang @Override 2066486e63e5bc7a88455e6fcb83d9cb251df203f727Alice Yang public void requestFolderRefresh() { 206737dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang if (mFolder == null) { 206837dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang return; 206937dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang } 207037dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang final ConversationListFragment convList = getConversationListFragment(); 207137dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang if (convList == null) { 207237dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang // This could happen if this account is in initial sync (user 207337dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang // is seeing the "your mail will appear shortly" message) 207437dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang return; 207537dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang } 207637dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang convList.showSyncStatusBar(); 20770d74a662f6e96b5a21e37978eb6e3b46545e3cbfAlice Yang 207837dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang if (mAsyncRefreshTask != null) { 207937dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang mAsyncRefreshTask.cancel(true); 208028e0c34ad35925fc74633bec66344911f2de6a22Mindy Pereira } 208137dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang mAsyncRefreshTask = new AsyncRefreshTask(mContext, mFolder.refreshUri); 208237dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang mAsyncRefreshTask.execute(); 208328e0c34ad35925fc74633bec66344911f2de6a22Mindy Pereira } 208428e0c34ad35925fc74633bec66344911f2de6a22Mindy Pereira 2085fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira /** 2086fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira * Confirm (based on user's settings) and delete a conversation from the conversation list and 2087fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira * from the database. 2088b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal * @param actionId the ID of the menu item that caused the delete: R.id.delete, R.id.archive... 20893d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal * @param target the conversations to act upon 20903d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal * @param showDialog true if a confirmation dialog is to be shown, false otherwise. 20913d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal * @param confirmResource the resource ID of the string that is shown in the confirmation dialog 2092fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira */ 2093b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal private void confirmAndDelete(int actionId, final Collection<Conversation> target, 209430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao boolean showDialog, int confirmResource, UndoCallback undoCallback) { 209584fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal final boolean isBatch = false; 2096fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira if (showDialog) { 209730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao makeDialogListener(actionId, isBatch, undoCallback); 20983d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal final CharSequence message = Utils.formatPlural(mContext, confirmResource, 20993d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal target.size()); 2100b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal final ConfirmDialogFragment c = ConfirmDialogFragment.newInstance(message); 2101b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal c.displayDialog(mActivity.getFragmentManager()); 2102fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } else { 210330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao delete(0, target, getDeferredAction(actionId, target, isBatch, undoCallback), isBatch); 2104fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } 2105fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } 2106fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira 21074f4782bcc53e13b30f1fd417beb1a6c04a54faedVikram Aggarwal @Override 21080d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy public void delete(final int actionId, final Collection<Conversation> target, 2109caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy final DestructiveAction action, final boolean isBatch) { 211084f7d32bdc79263004ed5241480988e02f8e618cmindyp // Order of events is critical! The Conversation View Fragment must be 211184f7d32bdc79263004ed5241480988e02f8e618cmindyp // notified of the next conversation with showConversation(next) *before* the 211284f7d32bdc79263004ed5241480988e02f8e618cmindyp // conversation list 2113192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal // fragment has a chance to delete the conversation, animating it away. 2114192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal 211584f7d32bdc79263004ed5241480988e02f8e618cmindyp // Update the conversation fragment if the current conversation is 211684f7d32bdc79263004ed5241480988e02f8e618cmindyp // deleted. 21170d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy final Runnable operation = new Runnable() { 21180d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy @Override 21190d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy public void run() { 2120caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy delete(actionId, target, action, isBatch); 21210d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy } 21220d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy }; 21230d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 212452bab6f5e293c8c16e7229c3e42412f169d47752Rohan Shah showNextConversation(target, operation); 212552bab6f5e293c8c16e7229c3e42412f169d47752Rohan Shah 2126ab1b5b6d16800ff675116cdab33cf26ab3514732Vikram Aggarwal // If the conversation is in the selected set, remove it from the set. 212784fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal // Batch selections are cleared in the end of the action, so not done for batch actions. 212884fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal if (!isBatch) { 212984fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal for (final Conversation conv : target) { 2130ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao if (mCheckedSet.contains(conv)) { 2131ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao mCheckedSet.toggle(conv); 213284fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal } 2133ab1b5b6d16800ff675116cdab33cf26ab3514732Vikram Aggarwal } 2134ab1b5b6d16800ff675116cdab33cf26ab3514732Vikram Aggarwal } 2135192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal // The conversation list deletes and performs the action if it exists. 2136192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal final ConversationListFragment convListFragment = getConversationListFragment(); 2137192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal if (convListFragment != null) { 2138193e05a8c38b87c400ac594b53b54eb211d35602Alice Yang LogUtils.i(LOG_TAG, "AAC.requestDelete: ListFragment is handling delete."); 2139669947bf67a3d0eed377b18099bb873604ad5009Vikram Aggarwal convListFragment.requestDelete(actionId, target, action); 2140192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal return; 2141192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal } 214284f7d32bdc79263004ed5241480988e02f8e618cmindyp // No visible UI element handled it on our behalf. Perform the action 214384f7d32bdc79263004ed5241480988e02f8e618cmindyp // ourself. 2144193e05a8c38b87c400ac594b53b54eb211d35602Alice Yang LogUtils.i(LOG_TAG, "ACC.requestDelete: performing remove action ourselves"); 2145d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal action.performAction(); 2146d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal } 2147d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal 2148d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal /** 2149d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal * Requests that the action be performed and the UI state is updated to reflect the new change. 2150715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param action the action to be performed, specified as a menu id: R.id.archive, ... 2151d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal */ 2152715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void requestUpdate(final DestructiveAction action) { 2153d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal action.performAction(); 2154d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal refreshConversationList(); 215575daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal } 21566fbc87affe46f6d49c584a307ec836e68163c182Vikram Aggarwal 21576fbc87affe46f6d49c584a307ec836e68163c182Vikram Aggarwal @Override 21581ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public void onPrepareDialog(int id, Dialog dialog, Bundle bundle) { 21591ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal // TODO(viki): Auto-generated method stub 21601ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 21611ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 21621ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 216387a8982af83168453b6dc219fe984bff68047bebAndy Huang public void onPrepareOptionsMenu(Menu menu) { 216487a8982af83168453b6dc219fe984bff68047bebAndy Huang mActionBarController.onPrepareOptionsMenu(menu); 2165a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 2166a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 216768f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira @Override 216868f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira public void onPause() { 2169c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal mHaveAccountList = false; 21706ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook enableNotifications(); 217194e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 217294e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook 2173a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 21741ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public void onResume() { 21756ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // Register the receiver that will prevent the status receiver from 21766ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // displaying its notification icon as long as we're running. 21776ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // The SupressNotificationReceiver will block the broadcast if we're looking at the folder 21786ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // that the notification was received for. 21796ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook disableNotifications(); 21801ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 21811ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang mSafeToModifyFragments = true; 2182ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein 2183ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein attachEmptyFolderDialogFragmentListener(); 218423e3313977d35d5caf152baf6cb27c9cc2d8ab91Andrew Sapperstein 218523e3313977d35d5caf152baf6cb27c9cc2d8ab91Andrew Sapperstein // Invalidating the options menu so that when we make changes in settings, 218623e3313977d35d5caf152baf6cb27c9cc2d8ab91Andrew Sapperstein // the changes will always be updated in the action bar/options menu/ 218723e3313977d35d5caf152baf6cb27c9cc2d8ab91Andrew Sapperstein mActivity.invalidateOptionsMenu(); 21881ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 21891ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 21901ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 2191a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal public void onSaveInstanceState(Bundle outState) { 2192649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal mViewMode.handleSaveInstanceState(outState); 21936c51158ad3269f157424e6c7bd488425c98da08fVikram Aggarwal if (mAccount != null) { 21946c51158ad3269f157424e6c7bd488425c98da08fVikram Aggarwal outState.putParcelable(SAVED_ACCOUNT, mAccount); 21956c51158ad3269f157424e6c7bd488425c98da08fVikram Aggarwal } 21965e478d2c4087b50764756b0edc95941cb6094f68Mindy Pereira if (mFolder != null) { 21975e478d2c4087b50764756b0edc95941cb6094f68Mindy Pereira outState.putParcelable(SAVED_FOLDER, mFolder); 21988b15263097bd9ce1a28db981b6a85261e6cb6886Vikram Aggarwal } 2199f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal // If this is a search activity, let's store the search query term as well. 2200f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal if (ConversationListContext.isSearchResult(mConvListContext)) { 2201f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal outState.putString(SAVED_QUERY, mConvListContext.searchQuery); 2202f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal } 220349e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal if (mCurrentConversation != null && mViewMode.isConversationMode()) { 220426f23fc8cc0d49bc0bea1eeec4c0c4742928f693Mindy Pereira outState.putParcelable(SAVED_CONVERSATION, mCurrentConversation); 220526f23fc8cc0d49bc0bea1eeec4c0c4742928f693Mindy Pereira } 2206ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao if (!mCheckedSet.isEmpty()) { 2207ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao outState.putParcelable(SAVED_SELECTED_SET, mCheckedSet); 22084556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang } 2209d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira if (mToastBar.getVisibility() == View.VISIBLE) { 2210d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira outState.putParcelable(SAVED_TOAST_BAR_OP, mToastBar.getOperation()); 2211d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira } 2212649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal final ConversationListFragment convListFragment = getConversationListFragment(); 2213d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira if (convListFragment != null) { 2214649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal convListFragment.getAnimatedAdapter().onSaveInstanceState(outState); 2215d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira } 2216b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal // If there is a dialog being shown, save the state so we can create a listener for it. 22176cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal if (mDialogAction != -1) { 22186cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal outState.putInt(SAVED_ACTION, mDialogAction); 2219b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal outState.putBoolean(SAVED_ACTION_FROM_SELECTED, mDialogFromSelectedSet); 22206cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal } 2221a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal if (mDetachedConvUri != null) { 2222a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal outState.putParcelable(SAVED_DETACHED_CONV_URI, mDetachedConvUri); 2223a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 22245747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein 2225b10212ef23a4e2317fc43c62dff9ad177b5bcf2cScott Kennedy outState.putParcelable(SAVED_HIERARCHICAL_FOLDER, mFolderListFolder); 22265747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein mSafeToModifyFragments = false; 2227ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 2228ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang outState.putParcelable(SAVED_INBOX_KEY, mInbox); 2229f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy 2230f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy outState.putBundle(SAVED_CONVERSATION_LIST_SCROLL_POSITIONS, 2231f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy mConversationListScrollPositions); 2232c6801eb828627c37b8992584767c095dfe11df62Jin Cao 2233c6801eb828627c37b8992584767c095dfe11df62Jin Cao mSearchViewController.saveState(outState); 22341ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 22351ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 22361ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang /** 22371ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * @see #mSafeToModifyFragments 22381ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang */ 22391ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang protected boolean safeToModifyFragments() { 22401ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang return mSafeToModifyFragments; 2241a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 2242a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 2243a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 2244313ac13095a386be366bd25f8106fbb34b4a7098Andy Huang public void executeSearch(String query) { 2245779dd6012a6c5b4d71255085059e57d94eab1a3fJin Cao AnalyticsTimer.getInstance().trackStart(AnalyticsTimer.SEARCH_TO_LIST); 224668f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira Intent intent = new Intent(); 224768f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira intent.setAction(Intent.ACTION_SEARCH); 224868f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira intent.putExtra(ConversationListContext.EXTRA_SEARCH_QUERY, query); 224968f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira intent.putExtra(Utils.EXTRA_ACCOUNT, mAccount); 225068f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira intent.setComponent(mActivity.getComponentName()); 2251c6801eb828627c37b8992584767c095dfe11df62Jin Cao mSearchViewController.showSearchActionBar( 2252c6801eb828627c37b8992584767c095dfe11df62Jin Cao MaterialSearchViewController.SEARCH_VIEW_STATE_GONE); 2253371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // Call startActivityForResult here so we can tell if we have navigated to a different folder 2254371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // or account from search results. 2255371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon mActivity.startActivityForResult(intent, CHANGE_NAVIGATION_REQUEST_CODE); 2256a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 2257a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 2258a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 22591ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public void onStop() { 2260cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy NotificationActionUtils.unregisterUndoNotificationObserver(mUndoNotificationObserver); 2261a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 2262a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 2263632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 2264632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void onDestroy() { 2265b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang // stop listening to the cursor on e.g. configuration changes 2266b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang if (mConversationListCursor != null) { 2267b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang mConversationListCursor.removeListener(this); 2268b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang } 2269144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang mDrawIdler.setListener(null); 2270144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang mDrawIdler.setRootView(null); 2271632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // unregister the ViewPager's observer on the conversation cursor 2272632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mPagerController.onDestroy(); 22732d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.onDestroy(); 22747c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal mRecentFolderList.destroy(); 22754e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang mDestroyed = true; 227659f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mHandler.removeCallbacks(mLogServiceChecker); 227759f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mLogServiceChecker = null; 2278c6801eb828627c37b8992584767c095dfe11df62Jin Cao mSearchViewController.onDestroy(); 2279632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2280632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2281fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal /** 228293dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal * Set the Action Bar icon according to the mode. The Action Bar icon can contain a back button 228393dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal * or not. The individual controller is responsible for changing the icon based on the mode. 228493dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal */ 228593dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal protected abstract void resetActionBarIcon(); 228693dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal 228793dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal /** 2288161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * {@inheritDoc} Subclasses must override this to listen to mode changes 2289161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * from the ViewMode. Subclasses <b>must</b> call the parent's 2290161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * onViewModeChanged since the parent will handle common state changes. 2291fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal */ 2292a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 2293fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal public void onViewModeChanged(int newMode) { 229449e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal // When we step away from the conversation mode, we don't have a current conversation 229549e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal // anymore. Let's blank it out so clients calling getCurrentConversation are not misled. 229649e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal if (!ViewMode.isConversationMode(newMode)) { 229749e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal setCurrentConversation(null); 229849e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal } 22996c570db71b8adc43d7dc2f31e6fa63cf50c1426eAndrew Sapperstein 230093dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal // If the viewmode is not set, preserve existing icon. 230193dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal if (newMode != ViewMode.UNKNOWN) { 230293dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal resetActionBarIcon(); 230393dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal } 230412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 230512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (isDrawerEnabled()) { 2306dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal /** If the folder doesn't exist, or its parent URI is empty, 2307dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal * this is not a child folder */ 23089695e0046f79bd2d7166a411d6feff4cf0fb2539Jin Cao final boolean isTopLevel = Folder.isRoot(mFolder); 2309207e662df01c550a4894bec03219820528365508Rohan Shah updateDrawerIndicator(newMode, isTopLevel); 2310371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); 231112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang closeDrawerIfOpen(); 231212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 2313a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 2314a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 2315dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal /** 2316207e662df01c550a4894bec03219820528365508Rohan Shah * Update the drawer indicator to either be the burger or the back arrow. 2317dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal * @param viewMode the current view mode 2318dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal * @param isTopLevel true if the current folder is not a child 2319dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal */ 2320207e662df01c550a4894bec03219820528365508Rohan Shah private void updateDrawerIndicator(final int viewMode, final boolean isTopLevel) { 2321207e662df01c550a4894bec03219820528365508Rohan Shah // Show burger if we're either in conversation list or folder list mode. 2322207e662df01c550a4894bec03219820528365508Rohan Shah if (isDrawerEnabled() && !ViewMode.isSearchMode(viewMode) 2323207e662df01c550a4894bec03219820528365508Rohan Shah && (viewMode == ViewMode.CONVERSATION_LIST && isTopLevel)) { 2324375faf0f8cf1d1de1d4aca7b9a7598e168dc9bf3Rohan Shah mDrawerToggle.setHomeAsUpIndicator(R.drawable.ic_menu_wht_24dp); 2325207e662df01c550a4894bec03219820528365508Rohan Shah 2326207e662df01c550a4894bec03219820528365508Rohan Shah // Otherwise, show the back arrow for the indicator. 2327207e662df01c550a4894bec03219820528365508Rohan Shah } else { 2328207e662df01c550a4894bec03219820528365508Rohan Shah mDrawerToggle.setHomeAsUpIndicator(R.drawable.ic_arrow_back_wht_24dp_with_rtl); 2329207e662df01c550a4894bec03219820528365508Rohan Shah } 23308a72b8590d9166ada55f69eeb083d2b8c5c915c9Scott Kennedy } 23318a72b8590d9166ada55f69eeb083d2b8c5c915c9Scott Kennedy 23323825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang public void disablePagerUpdates() { 23333825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang mPagerController.stopListening(); 23343825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang } 23353825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang 23364e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang public boolean isDestroyed() { 23374e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang return mDestroyed; 23384e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang } 23394e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang 234054f120f6ada40c7191811dfff99b151e9e192c78mindyp @Override 234154f120f6ada40c7191811dfff99b151e9e192c78mindyp public void commitDestructiveActions(boolean animate) { 2342c6adce3cf6887c4c6dd5005724565702751843d0mindyp ConversationListFragment fragment = getConversationListFragment(); 23431e2573bbba613fb700e8fa01c58c9382c0027b5eMindy Pereira if (fragment != null) { 2344c6adce3cf6887c4c6dd5005724565702751843d0mindyp fragment.commitDestructiveActions(animate); 23451e2573bbba613fb700e8fa01c58c9382c0027b5eMindy Pereira } 23461e2573bbba613fb700e8fa01c58c9382c0027b5eMindy Pereira } 23471e2573bbba613fb700e8fa01c58c9382c0027b5eMindy Pereira 2348a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 23491ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public void onWindowFocusChanged(boolean hasFocus) { 235069b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal final ConversationListFragment convList = getConversationListFragment(); 23516422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal // hasFocus already ensures that the window is in focus, so we don't need to call 23526422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal // AAC.isFragmentVisible(convList) here. 23539f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook if (hasFocus && convList != null && convList.isVisible()) { 23549f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook // The conversation list is visible. 235569b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal informCursorVisiblity(true); 23569f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook } 2357a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 2358a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 2359ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal /** 2360ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal * Set the account, and carry out all the account-related changes that rely on this. 2361715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param account new account to set to. 2362ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal */ 236375181e846462659d1c9b919d0f1250e34647a280Mindy Pereira private void setAccount(Account account) { 2364b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang if (account == null) { 2365b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang LogUtils.w(LOG_TAG, new Error(), 2366b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang "AAC ignoring null (presumably invalid) account restoration"); 2367b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang return; 2368b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang } 2369b114841b6f2a91d92b8d0af4ec05ce81a5ba5599Andy Huang LogUtils.d(LOG_TAG, "AbstractActivityController.setAccount(): account = %s", account.uri); 237091e8737780f631a65633434447b0da864beb5baeVikram Aggarwal mAccount = account; 23712168cbc9c58d2133bdf77ecd342c3d5ee755d607Régis Décamps 23722168cbc9c58d2133bdf77ecd342c3d5ee755d607Régis Décamps Analytics.getInstance().setEmail(account.getEmailAddress(), account.getType()); 23732168cbc9c58d2133bdf77ecd342c3d5ee755d607Régis Décamps 2374ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal // Only change AAC state here. Do *not* modify any other object's state. The object 2375ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal // should listen on account changes. 2376177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal restartOptionalLoader(LOADER_RECENT_FOLDERS, mFolderCallbacks, Bundle.EMPTY); 2377ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal mActivity.invalidateOptionsMenu(); 2378ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal disableNotificationsOnAccountChange(mAccount); 2379177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal restartOptionalLoader(LOADER_ACCOUNT_UPDATE_CURSOR, mAccountCallbacks, Bundle.EMPTY); 23802fe343f37226123e7cd5741d40be606dcf4edaabVikram Aggarwal // The Mail instance can be null during test runs. 23812fe343f37226123e7cd5741d40be606dcf4edaabVikram Aggarwal final MailAppProvider instance = MailAppProvider.getInstance(); 23822fe343f37226123e7cd5741d40be606dcf4edaabVikram Aggarwal if (instance != null) { 23832fe343f37226123e7cd5741d40be606dcf4edaabVikram Aggarwal instance.setLastViewedAccount(mAccount.uri.toString()); 23842fe343f37226123e7cd5741d40be606dcf4edaabVikram Aggarwal } 238591e8737780f631a65633434447b0da864beb5baeVikram Aggarwal if (account.settings == null) { 238691e8737780f631a65633434447b0da864beb5baeVikram Aggarwal LogUtils.w(LOG_TAG, new Error(), "AAC ignoring account with null settings."); 238791e8737780f631a65633434447b0da864beb5baeVikram Aggarwal return; 238891e8737780f631a65633434447b0da864beb5baeVikram Aggarwal } 23897c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal mAccountObservers.notifyChanged(); 239034f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal perhapsEnterWaitMode(); 239175181e846462659d1c9b919d0f1250e34647a280Mindy Pereira } 239275181e846462659d1c9b919d0f1250e34647a280Mindy Pereira 23931ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal /** 2394161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * Restore the state from the previous bundle. Subclasses should call this 2395161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * method from the parent class, since it performs important UI 2396161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * initialization. 2397161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * 2398715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param savedState previous state 23991ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal */ 2400632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 2401632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void onRestoreInstanceState(Bundle savedState) { 2402a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal mDetachedConvUri = savedState.getParcelable(SAVED_DETACHED_CONV_URI); 2403632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (savedState.containsKey(SAVED_CONVERSATION)) { 2404632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // Open the conversation. 24052bc8bc1f69faacaddab41ab61e1d2e8658f4181fAndy Huang final Conversation conversation = savedState.getParcelable(SAVED_CONVERSATION); 240687a8982af83168453b6dc219fe984bff68047bebAndy Huang restoreConversation(conversation); 2407632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2408632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2409d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira if (savedState.containsKey(SAVED_TOAST_BAR_OP)) { 24102bc8bc1f69faacaddab41ab61e1d2e8658f4181fAndy Huang ToastBarOperation op = savedState.getParcelable(SAVED_TOAST_BAR_OP); 2411d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira if (op != null) { 2412d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira if (op.getType() == ToastBarOperation.UNDO) { 2413d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira onUndoAvailable(op); 24149d7519d18e8ddbcdd59b37eec7c85210fca0e8c2Andrew Sapperstein } else if (op.getType() == ToastBarOperation.ERROR) { 24159d7519d18e8ddbcdd59b37eec7c85210fca0e8c2Andrew Sapperstein onError(mFolder, true); 2416d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira } 2417d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira } 2418d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira } 2419b10212ef23a4e2317fc43c62dff9ad177b5bcf2cScott Kennedy mFolderListFolder = savedState.getParcelable(SAVED_HIERARCHICAL_FOLDER); 2420649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal final ConversationListFragment convListFragment = getConversationListFragment(); 2421d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira if (convListFragment != null) { 2422649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal convListFragment.getAnimatedAdapter().onRestoreInstanceState(savedState); 2423d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira } 2424b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal /* 2425632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Restore the state of selected conversations. This needs to be done after the correct mode 2426632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * is set and the action bar is fully initialized. If not, several key pieces of state 2427632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * information will be missing, and the split views may not be initialized correctly. 2428632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang */ 2429632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang restoreSelectedConversations(savedState); 2430b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal // Order is important!!! 2431b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal // The dialog listener needs to happen *after* the selected set is restored. 2432b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal 2433b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal // If there has been an orientation change, and we need to recreate the listener for the 2434b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal // confirm dialog fragment (delete/archive/...), then do it here. 2435b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal if (mDialogAction != -1) { 243630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao makeDialogListener(mDialogAction, mDialogFromSelectedSet, 243730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao getUndoCallbackForDestructiveActionsWithAutoAdvance( 243830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mDialogAction, mCurrentConversation)); 2439b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal } 2440ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 2441ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang mInbox = savedState.getParcelable(SAVED_INBOX_KEY); 2442f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy 2443f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy mConversationListScrollPositions.clear(); 2444f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy mConversationListScrollPositions.putAll( 2445f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy savedState.getBundle(SAVED_CONVERSATION_LIST_SCROLL_POSITIONS)); 2446632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2447632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2448649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal /** 2449649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal * Handle an intent to open the app. This method is called only when there is no saved state, 2450649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal * so we need to set state that wasn't set before. It is correct to change the viewmode here 2451649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal * since it has not been previously set. 24526aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * 24536aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * This method is called for a subset of the reasons mentioned in 24546aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * {@link #onCreate(android.os.Bundle)}. Notably, this is called when launching the app from 24556aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * notifications, widgets, and shortcuts. 2456715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param intent intent passed to the activity. 2457649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal */ 2458632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private void handleIntent(Intent intent) { 2459e6459424b3e46d768865c908af1caa932f783095Andy Huang LogUtils.d(LOG_TAG, "IN AAC.handleIntent. action=%s", intent.getAction()); 2460632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (Intent.ACTION_VIEW.equals(intent.getAction())) { 2461632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (intent.hasExtra(Utils.EXTRA_ACCOUNT)) { 246226a20758413f0f8629ea71a0943304e3ae740165Tony Mantler setAccount(Account.newInstance(intent.getStringExtra(Utils.EXTRA_ACCOUNT))); 2463632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2464b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang if (mAccount == null) { 2465b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang return; 24665e478d2c4087b50764756b0edc95941cb6094f68Mindy Pereira } 24671a249e094e961f463ff392390d591a1d37106e69Vikram Aggarwal final boolean isConversationMode = intent.hasExtra(Utils.EXTRA_CONVERSATION); 24684fe0af81874976a1995191321e35c844b2229811Andy Huang 24694fe0af81874976a1995191321e35c844b2229811Andy Huang if (intent.getBooleanExtra(Utils.EXTRA_FROM_NOTIFICATION, false)) { 24702168cbc9c58d2133bdf77ecd342c3d5ee755d607Régis Décamps Analytics.getInstance().setEmail(mAccount.getEmailAddress(), mAccount.getType()); 24714fe0af81874976a1995191321e35c844b2229811Andy Huang Analytics.getInstance().sendEvent("notification_click", 24724fe0af81874976a1995191321e35c844b2229811Andy Huang isConversationMode ? "conversation" : "conversation_list", null, 0); 24734fe0af81874976a1995191321e35c844b2229811Andy Huang } 24744fe0af81874976a1995191321e35c844b2229811Andy Huang 2475649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal if (isConversationMode && mViewMode.getMode() == ViewMode.UNKNOWN) { 24761a249e094e961f463ff392390d591a1d37106e69Vikram Aggarwal mViewMode.enterConversationMode(); 24771a249e094e961f463ff392390d591a1d37106e69Vikram Aggarwal } else { 24781a249e094e961f463ff392390d591a1d37106e69Vikram Aggarwal mViewMode.enterConversationListMode(); 24791a249e094e961f463ff392390d591a1d37106e69Vikram Aggarwal } 2480177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Put the folder and conversation, and ask the loader to create this folder. 2481177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Bundle args = new Bundle(); 248248cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy 248348cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy final Uri folderUri; 248448cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy if (intent.hasExtra(Utils.EXTRA_FOLDER_URI)) { 24855bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein folderUri = intent.getParcelableExtra(Utils.EXTRA_FOLDER_URI); 248648cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy } else if (intent.hasExtra(Utils.EXTRA_FOLDER)) { 248748cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy final Folder folder = 248848cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy Folder.fromString(intent.getStringExtra(Utils.EXTRA_FOLDER)); 2489259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy folderUri = folder.folderUri.fullUri; 249048cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy } else { 249172727efe0bac563c72c208737c381296c35f94a9Scott Kennedy final Bundle extras = intent.getExtras(); 249272727efe0bac563c72c208737c381296c35f94a9Scott Kennedy LogUtils.d(LOG_TAG, "Couldn't find a folder URI in the extras: %s", 249372727efe0bac563c72c208737c381296c35f94a9Scott Kennedy extras == null ? "null" : extras.toString()); 249448cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy folderUri = mAccount.settings.defaultInbox; 249548cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy } 249648cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy 24975bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein // Check if we should load all conversations instead of using 24985bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein // the default behavior which loads an initial subset. 24995bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein mIgnoreInitialConversationLimit = 25005bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein intent.getBooleanExtra(Utils.EXTRA_IGNORE_INITIAL_CONVERSATION_LIMIT, false); 25015bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein 250260593354f1126b9687d09c3b11a852a3459f7118Scott Kennedy args.putParcelable(Utils.EXTRA_FOLDER_URI, folderUri); 2503177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal args.putParcelable(Utils.EXTRA_CONVERSATION, 2504177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal intent.getParcelableExtra(Utils.EXTRA_CONVERSATION)); 2505177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal restartOptionalLoader(LOADER_FIRST_FOLDER, mFolderCallbacks, args); 2506632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } else if (Intent.ACTION_SEARCH.equals(intent.getAction())) { 2507632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (intent.hasExtra(Utils.EXTRA_ACCOUNT)) { 2508f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal mHaveSearchResults = false; 2509c6801eb828627c37b8992584767c095dfe11df62Jin Cao // Save this search query for future suggestions 2510632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final String query = intent.getStringExtra(SearchManager.QUERY); 2511c6801eb828627c37b8992584767c095dfe11df62Jin Cao mSearchViewController.saveRecentQuery(query); 2512f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal setAccount((Account) intent.getParcelableExtra(Utils.EXTRA_ACCOUNT)); 2513f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal fetchSearchFolder(intent); 2514f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal if (shouldEnterSearchConvMode()) { 2515ac2548293e93c14b1d14e6de53328c561ba1cca6Mindy Pereira mViewMode.enterSearchResultsConversationMode(); 2516ac2548293e93c14b1d14e6de53328c561ba1cca6Mindy Pereira } else { 2517ac2548293e93c14b1d14e6de53328c561ba1cca6Mindy Pereira mViewMode.enterSearchResultsListMode(); 2518ac2548293e93c14b1d14e6de53328c561ba1cca6Mindy Pereira } 2519632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } else { 2520632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.e(LOG_TAG, "Missing account extra from search intent. Finishing"); 2521632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mActivity.finish(); 25222d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 25231ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 2524632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (mAccount != null) { 2525177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal restartOptionalLoader(LOADER_ACCOUNT_UPDATE_CURSOR, mAccountCallbacks, Bundle.EMPTY); 2526b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy } 2527b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy } 2528b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy 25294556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang /** 2530f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal * Returns true if we should enter conversation mode with search. 2531f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal */ 2532f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal protected final boolean shouldEnterSearchConvMode() { 253387a8982af83168453b6dc219fe984bff68047bebAndy Huang return mHaveSearchResults && shouldShowFirstConversation(); 2534f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal } 2535f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal 2536f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal /** 25374556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang * Copy any selected conversations stored in the saved bundle into our selection set, 25384556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang * triggering {@link ConversationSetObserver} callbacks as our selection set changes. 25394556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang * 25404556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang */ 2541715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void restoreSelectedConversations(Bundle savedState) { 2542967ede63e059810d9d4d425c50111d606014c893Mindy Pereira if (savedState == null) { 2543ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao mCheckedSet.clear(); 2544967ede63e059810d9d4d425c50111d606014c893Mindy Pereira return; 2545967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 2546ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao final ConversationCheckedSet selectedSet = savedState.getParcelable(SAVED_SELECTED_SET); 25474556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang if (selectedSet == null || selectedSet.isEmpty()) { 2548ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao mCheckedSet.clear(); 2549967ede63e059810d9d4d425c50111d606014c893Mindy Pereira return; 2550967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 2551632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2552632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // putAll will take care of calling our registered onSetPopulated method 2553ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao mCheckedSet.putAll(selectedSet); 2554967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 2555967ede63e059810d9d4d425c50111d606014c893Mindy Pereira 255687a8982af83168453b6dc219fe984bff68047bebAndy Huang protected void restoreConversation(Conversation conversation) { 255787a8982af83168453b6dc219fe984bff68047bebAndy Huang if (conversation != null && conversation.position < 0) { 255887a8982af83168453b6dc219fe984bff68047bebAndy Huang // Set the position to 0 on this conversation, as we don't know where it is 255987a8982af83168453b6dc219fe984bff68047bebAndy Huang // in the list 256087a8982af83168453b6dc219fe984bff68047bebAndy Huang conversation.position = 0; 256187a8982af83168453b6dc219fe984bff68047bebAndy Huang } 256287a8982af83168453b6dc219fe984bff68047bebAndy Huang showConversation(conversation); 256387a8982af83168453b6dc219fe984bff68047bebAndy Huang } 256487a8982af83168453b6dc219fe984bff68047bebAndy Huang 2565ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal /** 256649e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * Show the conversation provided in the arguments. It is safe to pass a null conversation 256749e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * object, which is a signal to back out of conversation view mode. 256849e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * Child classes must call super.showConversation() <b>before</b> their own implementations. 256959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal * @param conversation the conversation to be shown, or null if we want to back out to list 257059f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal * mode. 2571177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal * onLoadFinished(Loader, Cursor) on any callback. 2572ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal */ 257330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao protected void showConversation(Conversation conversation) { 257418512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah showConversation(conversation, false /* shouldAnimate */); 2575d23f6d1cd1dd8248cba755bf91c5355a31fbb885Jin Cao } 2576d23f6d1cd1dd8248cba755bf91c5355a31fbb885Jin Cao 257718512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah /** 257818512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah * Helper method to allow for conversation view animation control. Implementing classes should 257918512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah * directly override this to handle the animation. 258018512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah * @param conversation 258118512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah * @param shouldAnimate true if we want to animate the conversation in, false otherwise 258218512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah */ 258318512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah protected void showConversation(Conversation conversation, boolean shouldAnimate) { 258418512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah showConversationWithPeek(conversation, false /* peek */); 258518512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah } 258618512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah 258718512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah protected void showConversationWithPeek(Conversation conversation, boolean peek) { 2588243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang if (conversation != null) { 2589243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang Utils.sConvLoadTimer.start(); 2590243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang } 2591243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang 259254e925ec6eb14bf711af563e8e40979f07f17a68Andy Huang MailLogService.log("AbstractActivityController", "showConversation(%s)", conversation); 2593c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal // Set the current conversation just in case it wasn't already set. 2594c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal setCurrentConversation(conversation); 2595ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal } 2596ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal 2597e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal /** 2598405a344937675f57fc9c6988b2b124410a270f13Jin Cao * Show the wait for account initialization mode. 25992d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook * Children can override this method, but they must call super.showWaitForInitialization(). 26002d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook */ 2601405a344937675f57fc9c6988b2b124410a270f13Jin Cao protected void showWaitForInitialization() { 26022d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook mViewMode.enterWaitingForInitializationMode(); 2603c96efcc4a2f65b11a9b2057320ca828ee80f32ffAndy Huang mWaitFragment = WaitFragment.newInstance(mAccount, true /* expectingMessages */); 26042d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 26052d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook 2606dd6a7ce32c4003bd0941e2f18fcf5b80b5cd43c5Vikram Aggarwal private void updateWaitMode() { 26072d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook final FragmentManager manager = mActivity.getFragmentManager(); 26082d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook final WaitFragment waitFragment = 26096902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal (WaitFragment)manager.findFragmentByTag(TAG_WAIT); 26102d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook if (waitFragment != null) { 26112d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook waitFragment.updateAccount(mAccount); 26122d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 26132d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 26142d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook 2615a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal /** 2616a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal * Remove the "Waiting for Initialization" fragment. Child classes are free to override this 2617a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal * method, though they must call the parent implementation <b>after</b> they do anything. 2618a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal */ 2619a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal protected void hideWaitForInitialization() { 2620a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal mWaitFragment = null; 2621a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal } 2622a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal 2623a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal /** 2624a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal * Use the instance variable and the wait fragment's tag to get the wait fragment. This is 2625a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal * far superior to using the value of mWaitFragment, which might be invalid or might refer 2626a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal * to a fragment after it has been destroyed. 2627715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @return a wait fragment that is already attached to the activity, if one exists 2628a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal */ 2629a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal protected final WaitFragment getWaitFragment() { 2630a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal final FragmentManager manager = mActivity.getFragmentManager(); 2631a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal final WaitFragment waitFrag = (WaitFragment) manager.findFragmentByTag(TAG_WAIT); 2632a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal if (waitFrag != null) { 2633a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal // The Fragment Manager knows better, so use its instance. 2634a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal mWaitFragment = waitFrag; 2635a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal } 2636a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal return mWaitFragment; 2637a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal } 2638dd6a7ce32c4003bd0941e2f18fcf5b80b5cd43c5Vikram Aggarwal 263948b2a6c5fe209f0603fdf85d35cf399f7f7d462eVikram Aggarwal /** 264048b2a6c5fe209f0603fdf85d35cf399f7f7d462eVikram Aggarwal * Returns true if we are waiting for the account to sync, and cannot show any folders or 264148b2a6c5fe209f0603fdf85d35cf399f7f7d462eVikram Aggarwal * conversation for the current account yet. 264248b2a6c5fe209f0603fdf85d35cf399f7f7d462eVikram Aggarwal */ 2643dd6a7ce32c4003bd0941e2f18fcf5b80b5cd43c5Vikram Aggarwal private boolean inWaitMode() { 2644a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal final WaitFragment waitFragment = getWaitFragment(); 26452d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook if (waitFragment != null) { 26462d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook final Account fragmentAccount = waitFragment.getAccount(); 2647339004b1d81b34682ef56f6ea0b3b9fccc133753Paul Westbrook return fragmentAccount != null && fragmentAccount.uri.equals(mAccount.uri) && 26482d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook mViewMode.getMode() == ViewMode.WAITING_FOR_ACCOUNT_INITIALIZATION; 26492d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 26502d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook return false; 26512d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 26522d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook 26532d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook /** 2654405a344937675f57fc9c6988b2b124410a270f13Jin Cao * Show the conversation List with the list context provided here. On certain layouts, this 2655405a344937675f57fc9c6988b2b124410a270f13Jin Cao * might show more than just the conversation list. For instance, on tablets this might show 2656405a344937675f57fc9c6988b2b124410a270f13Jin Cao * the conversations along with the conversation list. 2657405a344937675f57fc9c6988b2b124410a270f13Jin Cao * @param listContext context providing information on what conversation list to display. 2658e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal */ 2659405a344937675f57fc9c6988b2b124410a270f13Jin Cao protected abstract void showConversationList(ConversationListContext listContext); 2660e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal 26611ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 26620b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao public void onConversationSelected(Conversation conversation, boolean inLoaderCallbacks) { 2663fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang final ConversationListFragment convListFragment = getConversationListFragment(); 2664fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang if (convListFragment != null && convListFragment.getAnimatedAdapter() != null) { 2665fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang convListFragment.getAnimatedAdapter().onConversationSelected(); 2666fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang } 2667aa55bc9cb210a46a950874f368baa07f041a4302mindyp // Only animate destructive actions if we are going to be showing the 2668aa55bc9cb210a46a950874f368baa07f041a4302mindyp // conversation list when we show the next conversation. 2669bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal commitDestructiveActions(mIsTablet); 267018512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah showConversation(conversation, true /* shouldAnimate */); 26711ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 26721ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 26731ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang @Override 26742f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein public final void onCabModeEntered() { 26752f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein final ConversationListFragment convListFragment = getConversationListFragment(); 26762f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein if (convListFragment != null && convListFragment.getAnimatedAdapter() != null) { 26772f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein convListFragment.getAnimatedAdapter().onCabModeEntered(); 26782f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein } 26792f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein } 26802f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein 26812f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein @Override 2682cc139833bc5829ba70244519e9870de783c41848Scott Kennedy public final void onCabModeExited() { 2683cc139833bc5829ba70244519e9870de783c41848Scott Kennedy final ConversationListFragment convListFragment = getConversationListFragment(); 2684cc139833bc5829ba70244519e9870de783c41848Scott Kennedy if (convListFragment != null && convListFragment.getAnimatedAdapter() != null) { 2685cc139833bc5829ba70244519e9870de783c41848Scott Kennedy convListFragment.getAnimatedAdapter().onCabModeExited(); 2686cc139833bc5829ba70244519e9870de783c41848Scott Kennedy } 2687cc139833bc5829ba70244519e9870de783c41848Scott Kennedy } 2688cc139833bc5829ba70244519e9870de783c41848Scott Kennedy 2689cc139833bc5829ba70244519e9870de783c41848Scott Kennedy @Override 26901ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang public Conversation getCurrentConversation() { 26911ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang return mCurrentConversation; 26927d602884ed70d07a42f1adf999fdf51b258f23f9Vikram Aggarwal } 2693555140c7b7d5129fb2b17df66106cbd6eeef37a0Mindy Pereira 2694c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal /** 2695c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal * Set the current conversation. This is the conversation on which all actions are performed. 2696c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal * Do not modify mCurrentConversation except through this method, which makes it easy to 2697c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal * perform common actions associated with changing the current conversation. 2698715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param conversation new conversation to view. Passing null indicates that we are backing 2699715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * out to conversation list mode. 2700c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal */ 2701632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 2702632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void setCurrentConversation(Conversation conversation) { 2703a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // The controller should come out of detached mode if a new conversation is viewed, or if 270481230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal // we are going back to conversation list mode. 270581230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal if (mDetachedConvUri != null && (conversation == null 270681230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal || !mDetachedConvUri.equals(conversation.uri))) { 2707a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal clearDetachedMode(); 2708a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 2709a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal 2710a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // Must happen *before* setting mCurrentConversation because this sets 2711a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // conversation.position if a cursor is available. 27128883f228890572a8d85d06b1e0bf08c65bd42db4Andy Huang mTracker.initialize(conversation); 271317f373ecf6961112f77a7516ab1bbcb4fcdf2884Vikram Aggarwal mCurrentConversation = conversation; 27147d64612104fd861474a09994f13768360f92041dAndy Huang 27157d64612104fd861474a09994f13768360f92041dAndy Huang if (mCurrentConversation != null) { 27162d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.setCurrentConversation(mCurrentConversation); 2717f807ba7ac1011f7fd1e0d382dcc0518ba3529810Yorke Lee mActivity.invalidateOptionsMenu(); 27187d64612104fd861474a09994f13768360f92041dAndy Huang } 27195040f1a73e3c5684901d8a9e2e30a5d58286509fMindy Pereira } 27205040f1a73e3c5684901d8a9e2e30a5d58286509fMindy Pereira 2721a9b93f35035dc4badd0ac40f4016e1ff809b26b0Vikram Aggarwal /** 272287a8982af83168453b6dc219fe984bff68047bebAndy Huang * Invoked by {@link ConversationPagerAdapter} when a new page in the ViewPager is selected. 272387a8982af83168453b6dc219fe984bff68047bebAndy Huang * 272487a8982af83168453b6dc219fe984bff68047bebAndy Huang * @param conversation the conversation of the now currently visible fragment 272587a8982af83168453b6dc219fe984bff68047bebAndy Huang * 272687a8982af83168453b6dc219fe984bff68047bebAndy Huang */ 272787a8982af83168453b6dc219fe984bff68047bebAndy Huang @Override 272887a8982af83168453b6dc219fe984bff68047bebAndy Huang public void onConversationViewSwitched(Conversation conversation) { 272987a8982af83168453b6dc219fe984bff68047bebAndy Huang setCurrentConversation(conversation); 273087a8982af83168453b6dc219fe984bff68047bebAndy Huang } 273187a8982af83168453b6dc219fe984bff68047bebAndy Huang 273287a8982af83168453b6dc219fe984bff68047bebAndy Huang @Override 273387a8982af83168453b6dc219fe984bff68047bebAndy Huang public boolean isCurrentConversationJustPeeking() { 273487a8982af83168453b6dc219fe984bff68047bebAndy Huang return false; 273587a8982af83168453b6dc219fe984bff68047bebAndy Huang } 273687a8982af83168453b6dc219fe984bff68047bebAndy Huang 273787a8982af83168453b6dc219fe984bff68047bebAndy Huang /** 2738f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * {@link LoaderManager} currently has a bug in 2739f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * {@link LoaderManager#restartLoader(int, Bundle, android.app.LoaderManager.LoaderCallbacks)} 2740f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * where, if a previous onCreateLoader returned a null loader, this method will NPE. Work around 2741f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * this bug by destroying any loaders that may have been created as null (essentially because 2742f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * they are optional loads, and may not apply to a particular account). 2743f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * <p> 2744f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * A simple null check before restarting a loader will not work, because that would not 2745f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * give the controller a chance to invalidate UI corresponding the prior loader result. 2746f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * 2747f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * @param id loader ID to safely restart 2748177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal * @param handler the LoaderCallback which will handle this loader ID. 2749177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal * @param args arguments, if any, to be passed to the loader. Use {@link Bundle#EMPTY} if no 2750177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal * arguments need to be specified. 2751f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang */ 2752177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private void restartOptionalLoader(int id, LoaderManager.LoaderCallbacks handler, Bundle args) { 2753f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang final LoaderManager lm = mActivity.getLoaderManager(); 2754f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang lm.destroyLoader(id); 2755177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal lm.restartLoader(id, args, handler); 275694c94de8f36698be849da8f103387e7e4d744d42Vikram Aggarwal } 275794c94de8f36698be849da8f103387e7e4d744d42Vikram Aggarwal 2758632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 2759632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void registerConversationListObserver(DataSetObserver observer) { 2760632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mConversationListObservable.registerObserver(observer); 2761632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2762632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2763632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 2764632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void unregisterConversationListObserver(DataSetObserver observer) { 2765647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang try { 2766647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang mConversationListObservable.unregisterObserver(observer); 2767647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang } catch (IllegalStateException e) { 2768647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang // Log instead of crash 2769647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang LogUtils.e(LOG_TAG, e, "unregisterConversationListObserver called for an observer that " 2770647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang + "hasn't been registered"); 2771647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang } 2772632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2773632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2774090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang @Override 2775090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang public void registerFolderObserver(DataSetObserver observer) { 2776090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang mFolderObservable.registerObserver(observer); 2777090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 2778090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang 2779090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang @Override 2780090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang public void unregisterFolderObserver(DataSetObserver observer) { 2781647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang try { 2782647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang mFolderObservable.unregisterObserver(observer); 2783647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang } catch (IllegalStateException e) { 2784647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang // Log instead of crash 2785647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang LogUtils.e(LOG_TAG, e, "unregisterFolderObserver called for an observer that " 2786647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang + "hasn't been registered"); 2787647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang } 2788090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 2789090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang 27909d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang @Override 27919d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang public void registerConversationLoadedObserver(DataSetObserver observer) { 27929d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang mPagerController.registerConversationLoadedObserver(observer); 27939d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang } 27949d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang 27959d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang @Override 27969d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang public void unregisterConversationLoadedObserver(DataSetObserver observer) { 2797647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang try { 2798647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang mPagerController.unregisterConversationLoadedObserver(observer); 2799647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang } catch (IllegalStateException e) { 2800647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang // Log instead of crash 2801647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang LogUtils.e(LOG_TAG, e, "unregisterConversationLoadedObserver called for an observer " 2802647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang + "that hasn't been registered"); 2803647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang } 28049d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang } 28059d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang 28066006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal /** 2807c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal * Returns true if the number of accounts is different, or if the current account has 2808c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal * changed. This method is meant to filter frequent changes to the list of 2809c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal * accounts, and only return true if the new list is substantially different from the existing 2810c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal * list. Returning true is safe here, it leads to more work in creating the 2811c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal * same account list again. 2812715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param accountCursor the cursor which points to all the accounts. 2813715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @return true if the number of accounts is changed or current account missing from the list. 28146006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal */ 2815177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private boolean accountsUpdated(ObjectCursor<Account> accountCursor) { 281623b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook // Check to see if the current account hasn't been set, or the account cursor is empty 281723b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook if (mAccount == null || !accountCursor.moveToFirst()) { 28186c51158ad3269f157424e6c7bd488425c98da08fVikram Aggarwal return true; 281923b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } 282023b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 282123b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook // Check to see if the number of accounts are different, from the number we saw on the last 282223b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook // updated 282323b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook if (mCurrentAccountUris.size() != accountCursor.getCount()) { 282423b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook return true; 282523b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } 282623b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 282723b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook // Check to see if the account list is different or if the current account is not found in 282823b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook // the cursor. 282923b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook boolean foundCurrentAccount = false; 28307dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal do { 2831c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal final Account account = accountCursor.getModel(); 2832c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal if (!foundCurrentAccount && mAccount.uri.equals(account.uri)) { 2833c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal if (mAccount.settingsDiffer(account)) { 2834c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal // Settings changed, and we don't need to look any further. 2835c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal return true; 2836c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal } 283723b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook foundCurrentAccount = true; 283823b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } 28396006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // Is there a new account that we do not know about? 2840c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal if (!mCurrentAccountUris.contains(account.uri)) { 284123b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook return true; 284223b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } 28437dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal } while (accountCursor.moveToNext()); 284423b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 284523b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook // As long as we found the current account, the list hasn't been updated 284623b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook return !foundCurrentAccount; 28477dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal } 28487dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal 28497dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal /** 28506006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal * Updates accounts for the app. If the current account is missing, the first 28516006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal * account in the list is set to the current account (we <em>have</em> to choose something). 2852161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * 28536c51158ad3269f157424e6c7bd488425c98da08fVikram Aggarwal * @param accounts cursor into the AccountCache 28547dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal * @return true if the update was successful, false otherwise 28557dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal */ 2856177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private boolean updateAccounts(ObjectCursor<Account> accounts) { 28577dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal if (accounts == null || !accounts.moveToFirst()) { 28587dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal return false; 28597dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal } 286023b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 2861a9b93f35035dc4badd0ac40f4016e1ff809b26b0Vikram Aggarwal final Account[] allAccounts = Account.getAllAccounts(accounts); 28626006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // A match for the current account's URI in the list of accounts. 28636006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal Account currentFromList = null; 286423b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 2865636c1a1bf144e28a8a1ab022dfcfba83c7b1ca1bVikram Aggarwal // Save the uris for the accounts and find the current account in the updated cursor. 286623b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook mCurrentAccountUris.clear(); 2867636c1a1bf144e28a8a1ab022dfcfba83c7b1ca1bVikram Aggarwal for (final Account account : allAccounts) { 28686006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal LogUtils.d(LOG_TAG, "updateAccounts(%s)", account); 286923b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook mCurrentAccountUris.add(account.uri); 28706006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (mAccount != null && account.uri.equals(mAccount.uri)) { 28716006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal currentFromList = account; 28726006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal } 287323b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } 287423b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 28756006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // 1. current account is already set and is in allAccounts: 28766006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // 1a. It has changed -> load the updated account. 2877406ae08b92f78f26fe83830897570c9db1ab23aaGreg Bullock // 1b. It is unchanged -> no-op 28780d647354209f4bf57cffa35f008e09853977b189Andy Huang // 2. current account is set and is not in allAccounts -> pick first (acct was deleted?) 28796006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // 3. saved preference has an account -> pick that one 28800d647354209f4bf57cffa35f008e09853977b189Andy Huang // 4. otherwise just pick first 28810d647354209f4bf57cffa35f008e09853977b189Andy Huang 28826006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal boolean accountChanged = false; 28836006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal /// Assume case 4, initialize to first account, and see if we can find anything better. 28846006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal Account newAccount = allAccounts[0]; 28856006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (currentFromList != null) { 28866006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // Case 1: Current account exists but has changed 28876006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (!currentFromList.equals(mAccount)) { 28886006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal newAccount = currentFromList; 28896006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal accountChanged = true; 28900d647354209f4bf57cffa35f008e09853977b189Andy Huang } 28916006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // Case 1b: else, current account is unchanged: nothing to do. 289223b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } else { 28936006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // Case 2: Current account is not in allAccounts, the account needs to change. 28946006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal accountChanged = true; 28956006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (mAccount == null) { 28966006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // Case 3: Check for last viewed account, and check if it exists in the list. 28976006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal final String lastAccountUri = MailAppProvider.getInstance().getLastViewedAccount(); 28986006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (lastAccountUri != null) { 28996006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal for (final Account account : allAccounts) { 29006006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (lastAccountUri.equals(account.uri.toString())) { 29016006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal newAccount = account; 29026006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal break; 29036006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal } 29040d647354209f4bf57cffa35f008e09853977b189Andy Huang } 29050d647354209f4bf57cffa35f008e09853977b189Andy Huang } 29060d647354209f4bf57cffa35f008e09853977b189Andy Huang } 290723b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } 29086006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (accountChanged) { 29095fd8afd5c1b40580c069a5a97039ca0601208216Vikram Aggarwal changeAccount(newAccount); 29106006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal } 291107dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal 29126006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // Whether we have updated the current account or not, we need to update the list of 29136006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // accounts in the ActionBar. 2914b905f0ea18ee0dc5774adb29c57cd7c122058c71Rohan Shah mAllAccounts = allAccounts; 291507dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal mAllAccountObservers.notifyChanged(); 2916a9b93f35035dc4badd0ac40f4016e1ff809b26b0Vikram Aggarwal return (allAccounts.length > 0); 29177dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal } 29187dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal 29196ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook private void disableNotifications() { 29206ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook mNewEmailReceiver.activate(mContext, this); 29216ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook } 29226ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook 29236ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook private void enableNotifications() { 29246ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook mNewEmailReceiver.deactivate(); 29256ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook } 29266ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook 29276ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook private void disableNotificationsOnAccountChange(Account account) { 29286ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // If the new mail suppression receiver is activated for a different account, we want to 29296ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // activate it for the new account. 29306ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook if (mNewEmailReceiver.activated() && 29316ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook !mNewEmailReceiver.notificationsDisabledForAccount(account)) { 29326ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // Deactivate the current receiver, otherwise multiple receivers may be registered. 29336ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook mNewEmailReceiver.deactivate(); 29346ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook mNewEmailReceiver.activate(mContext, this); 29356ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook } 29366ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook } 29376ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook 2938a9b93f35035dc4badd0ac40f4016e1ff809b26b0Vikram Aggarwal /** 2939c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal * Destructive actions on Conversations. This class should only be created by controllers, and 2940c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal * clients should only require {@link DestructiveAction}s, not specific implementations of the. 2941c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal * Only the controllers should know what kind of destructive actions are being created. 2942c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal */ 2943de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira public class ConversationAction implements DestructiveAction { 2944acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal /** 2945acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal * The action to be performed. This is specified as the resource ID of the menu item 2946acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal * corresponding to this action: R.id.delete, R.id.report_spam, etc. 2947acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal */ 29487f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal private final int mAction; 2949bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal /** The action will act upon these conversations */ 295077eee625cd8c317c605acfd06cd3a7e22120a0fdPaul Westbrook private final Collection<Conversation> mTarget; 29517f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal /** Whether this destructive action has already been performed */ 29527f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal private boolean mCompleted; 2953c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal /** Whether this is an action on the currently selected set. */ 2954c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal private final boolean mIsSelectedSet; 2955e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal 295630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao private UndoCallback mCallback; 295730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 2958fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira /** 2959715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * Create a listener object. 2960715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param action action is one of four constants: R.id.y_button (archive), 2961fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira * R.id.delete , R.id.mute, and R.id.report_spam. 2962bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal * @param target Conversation that we want to apply the action to. 2963c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal * @param isBatch whether the conversations are in the currently selected batch set. 2964c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal */ 2965c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal public ConversationAction(int action, Collection<Conversation> target, boolean isBatch) { 2966fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira mAction = action; 296777eee625cd8c317c605acfd06cd3a7e22120a0fdPaul Westbrook mTarget = ImmutableList.copyOf(target); 2968c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal mIsSelectedSet = isBatch; 2969fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } 2970fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira 297130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao @Override 297230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public void setUndoCallback(UndoCallback undoCallback) { 297330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mCallback = undoCallback; 297430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 297530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 2976acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal /** 2977acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal * The action common to child classes. This performs the action specified in the constructor 2978acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal * on the conversations given here. 2979acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal */ 2980bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal @Override 2981bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal public void performAction() { 29827f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal if (isPerformed()) { 29837f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal return; 29847f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal } 29853cb28b5e1598f74dedbdb87b187d9bd7e132ff0fMindy Pereira boolean undoEnabled = mAccount.supportsCapability(AccountCapabilities.UNDO); 29867dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal 29877dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal // Are we destroying the currently shown conversation? Show the next one. 29887dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)){ 29898742a614a238c5ae55d767461000d0a10d1da4d4Vikram Aggarwal LogUtils.d(LOG_TAG, "ConversationAction.performAction():" 29908742a614a238c5ae55d767461000d0a10d1da4d4Vikram Aggarwal + "\nmTarget=%s\nCurrent=%s", 29917dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal Conversation.toString(mTarget), mCurrentConversation); 29927dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal } 29937dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal 2994e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook if (mConversationListCursor == null) { 2995e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook LogUtils.e(LOG_TAG, "null ConversationCursor in ConversationAction.performAction():" 2996e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook + "\nmTarget=%s\nCurrent=%s", 2997e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook Conversation.toString(mTarget), mCurrentConversation); 2998e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook return; 2999e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook } 3000e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook 30012b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mAction == R.id.archive) { 30022b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Archiving"); 300330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mConversationListCursor.archive(mTarget, mCallback); 30042b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.delete) { 30052b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Deleting"); 300630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mConversationListCursor.delete(mTarget, mCallback); 30072b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mFolder.supportsCapability(FolderCapabilities.DELETE_ACTION_FINAL)) { 30082b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy undoEnabled = false; 30092b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 30102b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.mute) { 30112b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Muting"); 30122b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mFolder.supportsCapability(FolderCapabilities.DESTRUCTIVE_MUTE)) { 30132b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy for (Conversation c : mTarget) { 30142b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy c.localDeleteOnUpdate = true; 3015bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal } 30162b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 301730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mConversationListCursor.mute(mTarget, mCallback); 30182b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.report_spam) { 30192b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Reporting spam"); 302030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mConversationListCursor.reportSpam(mTarget, mCallback); 30212b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.mark_not_spam) { 30222b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Marking not spam"); 302330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mConversationListCursor.reportNotSpam(mTarget, mCallback); 30242b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.report_phishing) { 30252b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Reporting phishing"); 302630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mConversationListCursor.reportPhishing(mTarget, mCallback); 30272b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.remove_star) { 30282b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Removing star"); 30292b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Star removal is destructive in the Starred folder. 30302b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mConversationListCursor.updateBoolean(mTarget, ConversationColumns.STARRED, 30312b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy false); 30322b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.mark_not_important) { 30332b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Marking not-important"); 30342b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Marking not important is destructive in a mailbox 30352b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // containing only important messages 30362b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mFolder != null && mFolder.isImportantOnly()) { 30372b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy for (Conversation conv : mTarget) { 30382b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy conv.localDeleteOnUpdate = true; 3039445be2114aed6b28cab53b488735d4bb812353a5Mindy Pereira } 30402b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 30412b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mConversationListCursor.updateInt(mTarget, ConversationColumns.PRIORITY, 30422b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy UIProvider.ConversationPriority.LOW); 30432b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.discard_drafts) { 30442b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Discarding draft messages"); 30452b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Discarding draft messages is destructive in a "draft" mailbox 30462b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mFolder != null && mFolder.isDraft()) { 30472b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy for (Conversation conv : mTarget) { 30482b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy conv.localDeleteOnUpdate = true; 3049ef3625472596326b910a4445307d1a8eb8c9cc3fPaul Westbrook } 30502b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 30512b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mConversationListCursor.discardDrafts(mTarget); 30522b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // We don't support undoing discarding drafts 30532b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy undoEnabled = false; 3054512821c11d89d49908f3cfdee0b582601f500f3dJin Cao } else if (mAction == R.id.discard_outbox) { 3055512821c11d89d49908f3cfdee0b582601f500f3dJin Cao LogUtils.d(LOG_TAG, "Discarding failed messages in Outbox"); 3056512821c11d89d49908f3cfdee0b582601f500f3dJin Cao mConversationListCursor.moveFailedIntoDrafts(mTarget); 3057512821c11d89d49908f3cfdee0b582601f500f3dJin Cao undoEnabled = false; 30583d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal } 30592cb6c1ca2b508331ee29d16b71f5ec024cd22555Jin Cao if (undoEnabled && mTarget.size() > 0) { 3060ead5039b6d606fcc39668a472f8973cbd0bef4e1mindyp mHandler.postDelayed(new Runnable() { 3061ead5039b6d606fcc39668a472f8973cbd0bef4e1mindyp @Override 3062ead5039b6d606fcc39668a472f8973cbd0bef4e1mindyp public void run() { 3063ead5039b6d606fcc39668a472f8973cbd0bef4e1mindyp onUndoAvailable(new ToastBarOperation(mTarget.size(), mAction, 30646a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy ToastBarOperation.UNDO, mIsSelectedSet, mFolder)); 3065ead5039b6d606fcc39668a472f8973cbd0bef4e1mindyp } 3066ead5039b6d606fcc39668a472f8973cbd0bef4e1mindyp }, mShowUndoBarDelay); 30673d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal } 3068bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal refreshConversationList(); 3069c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal if (mIsSelectedSet) { 3070ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao mCheckedSet.clear(); 3071c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal } 3072fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } 30737f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal 30747f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal /** 30757f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal * Returns true if this action has been performed, false otherwise. 3076839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang * 30777f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal */ 30787f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal private synchronized boolean isPerformed() { 30797f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal if (mCompleted) { 30807f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal return true; 30817f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal } 30827f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal mCompleted = true; 30837f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal return false; 30847f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal } 3085fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } 3086e5f4dc0661dad02e2cb39ffa62ff2157147ac387Mindy Pereira 3087d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal // Called from the FolderSelectionDialog after a user is done selecting folders to assign the 3088d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal // conversations to. 3089e5f4dc0661dad02e2cb39ffa62ff2157147ac387Mindy Pereira @Override 30908db7e407109532557718c6b8064792f2df7a073dMindy Pereira public final void assignFolder(Collection<FolderOperation> folderOps, 30916a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy Collection<Conversation> target, boolean batch, boolean showUndo, 30926a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy final boolean isMoveTo) { 3093479753fdbb4d71558c4d2c8d9cc8c7eb803a7837Jin Cao // Actions are destructive only when the current folder can be un-assigned from and 30948db7e407109532557718c6b8064792f2df7a073dMindy Pereira // when the list of folders contains the current folder. 30958db7e407109532557718c6b8064792f2df7a073dMindy Pereira final boolean isDestructive = mFolder 3096479753fdbb4d71558c4d2c8d9cc8c7eb803a7837Jin Cao .supportsCapability(FolderCapabilities.ALLOWS_REMOVE_CONVERSATION) 30978db7e407109532557718c6b8064792f2df7a073dMindy Pereira && FolderOperation.isDestructive(folderOps, mFolder); 3098d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal LogUtils.d(LOG_TAG, "onFolderChangesCommit: isDestructive = %b", isDestructive); 3099d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal if (isDestructive) { 3100d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal for (final Conversation c : target) { 3101d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal c.localDeleteOnUpdate = true; 31026778f4663a790d3e9d4c6a2f43292eef43c1e0bdMindy Pereira } 3103e5f4dc0661dad02e2cb39ffa62ff2157147ac387Mindy Pereira } 3104c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp final DestructiveAction folderChange; 310530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final UndoCallback undoCallback = isMoveTo ? 310630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao getUndoCallbackForDestructiveActionsWithAutoAdvance(R.id.move_to, 310730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mCurrentConversation) 310830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao : null; 3109d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal // Update the UI elements depending no their visibility and availability 31103d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal // TODO(viki): Consolidate this into a single method requestDelete. 3111d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal if (isDestructive) { 31126a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy /* 31136a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy * If this is a MOVE operation, we want the action folder to be the destination folder. 31146a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy * Otherwise, we want it to be the current folder. 31156a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy * 31166a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy * A set of folder operations is a move if there are exactly two operations: an add and 31176a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy * a remove. 31186a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy */ 31196a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy final Folder actionFolder; 31206a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy if (folderOps.size() != 2) { 31216a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy actionFolder = mFolder; 31226a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } else { 31236a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy Folder addedFolder = null; 31246a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy boolean hasRemove = false; 31256a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy for (final FolderOperation folderOperation : folderOps) { 31266a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy if (folderOperation.mAdd) { 31276a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy addedFolder = folderOperation.mFolder; 31286a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } else { 31296a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy hasRemove = true; 31306a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } 31316a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } 31326a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy 31336a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy if (hasRemove && addedFolder != null) { 31346a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy actionFolder = addedFolder; 31356a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } else { 31366a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy actionFolder = mFolder; 31376a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } 31386a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } 31396a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy 3140c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp folderChange = getDeferredFolderChange(target, folderOps, isDestructive, 314130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao batch, showUndo, isMoveTo, actionFolder, undoCallback); 3142caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy delete(0, target, folderChange, batch); 31436902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal } else { 3144c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp folderChange = getFolderChange(target, folderOps, isDestructive, 314530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao batch, showUndo, false /* isMoveTo */, mFolder, undoCallback); 3146715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal requestUpdate(folderChange); 3147e5f4dc0661dad02e2cb39ffa62ff2157147ac387Mindy Pereira } 3148e5f4dc0661dad02e2cb39ffa62ff2157147ac387Mindy Pereira } 3149e5f4dc0661dad02e2cb39ffa62ff2157147ac387Mindy Pereira 3150967ede63e059810d9d4d425c50111d606014c893Mindy Pereira @Override 31513d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal public final void onRefreshRequired() { 315212a05d22f6ac528e96716de9a451c5b7bee7a26dAndy Huang if (isAnimating()) { 3153f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang final ConversationListFragment f = getConversationListFragment(); 3154f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang LogUtils.w(ConversationCursor.LOG_TAG, 3155f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang "onRefreshRequired: delay until animating done. cursor=%s adapter=%s", 3156f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang mConversationListCursor, (f != null) ? f.getAnimatedAdapter() : null); 315769e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira return; 315869e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira } 3159bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank // Refresh the query in the background 3160cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook if (mConversationListCursor.isRefreshRequired()) { 3161cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook mConversationListCursor.refresh(); 3162cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook } 3163bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3164bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 31655390fcabb7baf683fc14bd68d8612913dac70a81mindyp @Override 31666f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp public boolean isAnimating() { 316769e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira boolean isAnimating = false; 316869e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira ConversationListFragment convListFragment = getConversationListFragment(); 316969e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira if (convListFragment != null) { 317048ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang isAnimating = convListFragment.isAnimating(); 317169e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira } 317269e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira return isAnimating; 317369e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira } 317469e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira 3175bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank /** 3176bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank * Called when the {@link ConversationCursor} is changed or has new data in it. 3177bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank * <p> 3178bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank * {@inheritDoc} 3179bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank */ 3180bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank @Override 31813d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal public final void onRefreshReady() { 31825c1d8354ce98be2fc77d458bcc5c3346765046a0mindyp LogUtils.d(LOG_TAG, "Received refresh ready callback for folder %s", 31835c1d8354ce98be2fc77d458bcc5c3346765046a0mindyp mFolder != null ? mFolder.id : "-1"); 3184b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang 3185b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang if (mDestroyed) { 3186b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang LogUtils.i(LOG_TAG, "ignoring onRefreshReady on destroyed AAC"); 3187b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang return; 3188b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang } 3189b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang 3190cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook if (!isAnimating()) { 3191bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank // Swap cursors 3192bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mConversationListCursor.sync(); 3193f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang } else { 3194f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang // (CLF guaranteed to be non-null due to check in isAnimating) 3195f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang LogUtils.w(LOG_TAG, 3196f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang "AAC.onRefreshReady suppressing sync() due to animation. cursor=%s aa=%s", 3197f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang mConversationListCursor, getConversationListFragment().getAnimatedAdapter()); 3198bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3199937c94f025ed55c19bd46c7c077fa3575ab6be52Paul Westbrook mTracker.onCursorUpdated(); 320087a8982af83168453b6dc219fe984bff68047bebAndy Huang perhapsShowFirstConversation(); 3201bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3202bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3203bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank @Override 32043d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal public final void onDataSetChanged() { 32059f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook updateConversationListFragment(); 3206632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mConversationListObservable.notifyChanged(); 3207ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao mCheckedSet.validateAgainstCursor(mConversationListCursor); 3208bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3209bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 32103d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal /** 32113d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal * If the Conversation List Fragment is visible, updates the fragment. 32123d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal */ 3213715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void updateConversationListFragment() { 3214bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank final ConversationListFragment convList = getConversationListFragment(); 3215bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank if (convList != null) { 321675daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal refreshConversationList(); 32176422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal if (isFragmentVisible(convList)) { 321869b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal informCursorVisiblity(true); 32199f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook } 3220bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3221bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3222bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3223bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank /** 3224bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank * This class handles throttled refresh of the conversation list 3225bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank */ 3226bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank static class RefreshTimerTask extends TimerTask { 3227bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank final Handler mHandler; 3228bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank final AbstractActivityController mController; 3229bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3230bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank RefreshTimerTask(AbstractActivityController controller, Handler handler) { 3231bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mHandler = handler; 3232bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mController = controller; 3233bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3234bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3235bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank @Override 3236bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank public void run() { 3237bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mHandler.post(new Runnable() { 3238bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank @Override 3239bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank public void run() { 3240bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank LogUtils.d(LOG_TAG, "Delay done... calling onRefreshRequired"); 3241bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mController.onRefreshRequired(); 3242bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank }}); 3243bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3244bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3245bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3246bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank /** 3247bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank * Cancel the refresh task, if it's running 3248bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank */ 3249bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank private void cancelRefreshTask () { 3250bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank if (mConversationListRefreshTask != null) { 3251bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mConversationListRefreshTask.cancel(); 3252bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mConversationListRefreshTask = null; 3253bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3254bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3255bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3256bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank @Override 3257cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook public void onAnimationEnd(AnimatedAdapter animatedAdapter) { 3258f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang if (animatedAdapter != null) { 3259f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang LogUtils.i(LOG_TAG, "AAC.onAnimationEnd. cursor=%s adapter=%s", mConversationListCursor, 3260f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang animatedAdapter); 3261f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang } 3262026139c958c563266294b7788ed54f57345626b8Paul Westbrook if (mConversationListCursor == null) { 3263026139c958c563266294b7788ed54f57345626b8Paul Westbrook LogUtils.e(LOG_TAG, "null ConversationCursor in onAnimationEnd"); 3264026139c958c563266294b7788ed54f57345626b8Paul Westbrook return; 3265026139c958c563266294b7788ed54f57345626b8Paul Westbrook } 3266cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook if (mConversationListCursor.isRefreshReady()) { 3267c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang LogUtils.i(ConversationCursor.LOG_TAG, "Stopped animating: try sync"); 3268cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook onRefreshReady(); 3269bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3270bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3271cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook if (mConversationListCursor.isRefreshRequired()) { 3272c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang LogUtils.i(ConversationCursor.LOG_TAG, "Stopped animating: refresh"); 3273cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook mConversationListCursor.refresh(); 3274cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook } 32756f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp if (mRecentsDataUpdated) { 32766f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp mRecentsDataUpdated = false; 32776f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp mRecentFolderObservers.notifyChanged(); 32786f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp } 3279bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3280bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3281bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank @Override 3282967ede63e059810d9d4d425c50111d606014c893Mindy Pereira public void onSetEmpty() { 32836cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal // There are no selected conversations. Ensure that the listener and its associated actions 32846cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal // are blanked out. 32856cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal setListener(null, -1); 3286967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 3287967ede63e059810d9d4d425c50111d606014c893Mindy Pereira 3288967ede63e059810d9d4d425c50111d606014c893Mindy Pereira @Override 3289ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao public void onSetPopulated(ConversationCheckedSet set) { 32907704d79def5e5f36a1cbe22fbbe6e9520503899cVikram Aggarwal mCabActionMenu = new SelectedConversationsActionMenu(mActivity, set, mFolder); 32915b9ed2b056e0757ccc26e51aba7d5ff12378baaaVikram Aggarwal if (mViewMode.isListMode() || (mIsTablet && mViewMode.isConversationMode())) { 32927704d79def5e5f36a1cbe22fbbe6e9520503899cVikram Aggarwal enableCabMode(); 32936902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal } 3294967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 3295967ede63e059810d9d4d425c50111d606014c893Mindy Pereira 3296967ede63e059810d9d4d425c50111d606014c893Mindy Pereira @Override 3297ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao public void onSetChanged(ConversationCheckedSet set) { 3298967ede63e059810d9d4d425c50111d606014c893Mindy Pereira // Do nothing. We don't care about changes to the set. 3299967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 3300967ede63e059810d9d4d425c50111d606014c893Mindy Pereira 3301967ede63e059810d9d4d425c50111d606014c893Mindy Pereira @Override 3302ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao public ConversationCheckedSet getCheckedSet() { 3303ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao return mCheckedSet; 3304967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 3305967ede63e059810d9d4d425c50111d606014c893Mindy Pereira 3306e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal /** 3307e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal * Disable the Contextual Action Bar (CAB). The selected set is not changed. 3308e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal */ 3309e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal protected void disableCabMode() { 33108937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira // Commit any previous destructive actions when entering/ exiting CAB mode. 3311c6adce3cf6887c4c6dd5005724565702751843d0mindyp commitDestructiveActions(true); 3312e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal if (mCabActionMenu != null) { 3313e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal mCabActionMenu.deactivate(); 3314e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal } 3315e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal } 3316e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal 3317e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal /** 3318e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal * Re-enable the CAB menu if required. The selection set is not changed. 3319e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal */ 3320e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal protected void enableCabMode() { 33213d6751ad5328d5a17fa637e3157974d776591b26Tony Mantler if (mCabActionMenu != null && 33223d6751ad5328d5a17fa637e3157974d776591b26Tony Mantler !(isDrawerEnabled() && mDrawerContainer.isDrawerOpen(mDrawerPullout))) { 3323e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal mCabActionMenu.activate(); 3324e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal } 3325e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal } 3326e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal 33274eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal /** 332843fab3224230c235db5be395f96096e1cac6b376Tony Mantler * Re-enable CAB mode only if we have an active selection 332943fab3224230c235db5be395f96096e1cac6b376Tony Mantler */ 333043fab3224230c235db5be395f96096e1cac6b376Tony Mantler protected void maybeEnableCabMode() { 3331ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao if (!mCheckedSet.isEmpty()) { 3332a703d8a647a7272347c47bbb394b1a4c403106a5Tony Mantler if (mCabActionMenu != null) { 3333a703d8a647a7272347c47bbb394b1a4c403106a5Tony Mantler mCabActionMenu.activate(); 3334a703d8a647a7272347c47bbb394b1a4c403106a5Tony Mantler } 333543fab3224230c235db5be395f96096e1cac6b376Tony Mantler } 333643fab3224230c235db5be395f96096e1cac6b376Tony Mantler } 333743fab3224230c235db5be395f96096e1cac6b376Tony Mantler 333843fab3224230c235db5be395f96096e1cac6b376Tony Mantler /** 33394eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal * Unselect conversations and exit CAB mode. 33404eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal */ 33414eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal protected final void exitCabMode() { 3342ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao mCheckedSet.clear(); 33434eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal } 33444eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal 3345967ede63e059810d9d4d425c50111d606014c893Mindy Pereira @Override 3346fd0c2974af56ad244006faab2651e054974a4b7bMindy Pereira public void startSearch() { 334735f19d7c052ca8074b48b2ab9d8689a72dc369c5Vikram Aggarwal if (mAccount == null) { 334835f19d7c052ca8074b48b2ab9d8689a72dc369c5Vikram Aggarwal // We cannot search if there is no account. Drop the request to the floor. 334935f19d7c052ca8074b48b2ab9d8689a72dc369c5Vikram Aggarwal LogUtils.d(LOG_TAG, "AbstractActivityController.startSearch(): null account"); 335035f19d7c052ca8074b48b2ab9d8689a72dc369c5Vikram Aggarwal return; 335135f19d7c052ca8074b48b2ab9d8689a72dc369c5Vikram Aggarwal } 33523531d7ee9b36c9f9dd909be79ab899dd60cd71aeJames Lemieux if (mAccount.supportsSearch()) { 3353c6801eb828627c37b8992584767c095dfe11df62Jin Cao mSearchViewController.showSearchActionBar( 3354c6801eb828627c37b8992584767c095dfe11df62Jin Cao MaterialSearchViewController.SEARCH_VIEW_STATE_VISIBLE); 3355fd0c2974af56ad244006faab2651e054974a4b7bMindy Pereira } else { 3356fd0c2974af56ad244006faab2651e054974a4b7bMindy Pereira Toast.makeText(mActivity.getActivityContext(), mActivity.getActivityContext() 3357a46c29980f2d81da3529b2f1dfddf7291c94a102Mindy Pereira .getString(R.string.search_unsupported), Toast.LENGTH_SHORT).show(); 3358fd0c2974af56ad244006faab2651e054974a4b7bMindy Pereira } 3359fd0c2974af56ad244006faab2651e054974a4b7bMindy Pereira } 3360acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira 33610963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira @Override 33620963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira public void onTouchEvent(MotionEvent event) { 33630963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira if (event.getAction() == MotionEvent.ACTION_DOWN) { 3364c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein if (mToastBar != null && !mToastBar.isEventInToastBar(event)) { 33659a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux // if the toast bar is still animating, ignore this attempt to hide it 33669a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux if (mToastBar.isAnimating()) { 33679a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux return; 33689a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux } 33699a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux 33709a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux // if the toast bar has not been seen long enough, ignore this attempt to hide it 33719a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux if (mToastBar.cannotBeHidden()) { 33729a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux return; 33739a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux } 33749a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux 33759a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux // hide the toast bar 33769a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux mToastBar.hide(true /* animated */, false /* actionClicked */); 33770963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira } 33780963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira } 33790963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira } 3380b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang 3381632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 33823b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy public void onConversationSeen() { 33833b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy mPagerController.onConversationSeen(); 3384632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 3385632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 33869d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang @Override 33879d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang public boolean isInitialConversationLoading() { 33889d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang return mPagerController.isInitialConversationLoading(); 33899d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang } 33909d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang 33916422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal /** 33926422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal * Check if the fragment given here is visible. Checking {@link Fragment#isVisible()} is 33936422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal * insufficient because that doesn't check if the window is currently in focus or not. 33946422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal */ 3395715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private boolean isFragmentVisible(Fragment in) { 33966422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal return in != null && in.isVisible() && mActivity.hasWindowFocus(); 33976422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal } 33986422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal 3399d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal /** 3400d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal * This class handles callbacks that create a {@link ConversationCursor}. 3401d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal */ 3402b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang private class ConversationListLoaderCallbacks implements 3403b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang LoaderManager.LoaderCallbacks<ConversationCursor> { 3404b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang 3405b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang @Override 3406b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang public Loader<ConversationCursor> onCreateLoader(int id, Bundle args) { 3407a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal final Account account = args.getParcelable(BUNDLE_ACCOUNT_KEY); 3408a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal final Folder folder = args.getParcelable(BUNDLE_FOLDER_KEY); 34095bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein final boolean ignoreInitialConversationLimit = 34105bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein args.getBoolean(BUNDLE_IGNORE_INITIAL_CONVERSATION_LIMIT_KEY, false); 3411a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal if (account == null || folder == null) { 3412a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal return null; 3413a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal } 34145bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein return new ConversationCursorLoader(mActivity, account, 3415f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang folder.conversationListUri, folder.getTypeDescription(), 3416f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang ignoreInitialConversationLimit); 3417b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang } 3418b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang 3419b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang @Override 3420b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang public void onLoadFinished(Loader<ConversationCursor> loader, ConversationCursor data) { 3421144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang LogUtils.d(LOG_TAG, 3422144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang "IN AAC.ConversationCursor.onLoadFinished, data=%s loader=%s this=%s", 3423144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang data, loader, this); 34240c532efa4ec664b50a0ccff989667599e72cc4fcTony Mantler if (isDestroyed()) { 34250c532efa4ec664b50a0ccff989667599e72cc4fcTony Mantler return; 34260c532efa4ec664b50a0ccff989667599e72cc4fcTony Mantler } 3427a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein if (isDrawerEnabled() && mDrawerListener.getDrawerState() != DrawerLayout.STATE_IDLE) { 3428a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal LogUtils.d(LOG_TAG, "ConversationListLoaderCallbacks.onLoadFinished: ignoring."); 3429a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mConversationListLoadFinishedIgnored = true; 3430a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal return; 3431a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal } 3432e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal // Clear our all pending destructive actions before swapping the conversation cursor 3433e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal destroyPending(null); 3434b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang mConversationListCursor = data; 3435bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook mConversationListCursor.addListener(AbstractActivityController.this); 3436144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang mDrawIdler.setListener(mConversationListCursor); 3437937c94f025ed55c19bd46c7c077fa3575ab6be52Paul Westbrook mTracker.onCursorUpdated(); 3438e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang mConversationListObservable.notifyChanged(); 34397c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu // Handle actions that were deferred until after the conversation list was loaded. 34407c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu for (LoadFinishedCallback callback : mConversationListLoadFinishedCallbacks) { 34417c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu callback.onLoadFinished(); 34427c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } 34437c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu mConversationListLoadFinishedCallbacks.clear(); 34449f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook 344517f373ecf6961112f77a7516ab1bbcb4fcdf2884Vikram Aggarwal final ConversationListFragment convList = getConversationListFragment(); 34466422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal if (isFragmentVisible(convList)) { 344717f373ecf6961112f77a7516ab1bbcb4fcdf2884Vikram Aggarwal // The conversation list is already listening to list changes and gets notified 344817f373ecf6961112f77a7516ab1bbcb4fcdf2884Vikram Aggarwal // in the mConversationListObservable.notifyChanged() line above. We only need to 344917f373ecf6961112f77a7516ab1bbcb4fcdf2884Vikram Aggarwal // check and inform the cursor of the change in visibility here. 345017f373ecf6961112f77a7516ab1bbcb4fcdf2884Vikram Aggarwal informCursorVisiblity(true); 3451b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang } 345287a8982af83168453b6dc219fe984bff68047bebAndy Huang perhapsShowFirstConversation(); 3453b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang } 3454b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang 3455b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang @Override 3456b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang public void onLoaderReset(Loader<ConversationCursor> loader) { 3457144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang LogUtils.d(LOG_TAG, 3458144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang "IN AAC.ConversationCursor.onLoaderReset, data=%s loader=%s this=%s", 3459144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang mConversationListCursor, loader, this); 34609a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook 34619a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook if (mConversationListCursor != null) { 34629a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook // Unregister the listener 34639a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook mConversationListCursor.removeListener(AbstractActivityController.this); 3464144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang mDrawIdler.setListener(null); 34659a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook mConversationListCursor = null; 34669a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook 34679a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook // Inform anyone who is interested about the change 34689a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook mTracker.onCursorUpdated(); 34699a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook mConversationListObservable.notifyChanged(); 3470b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang } 3471b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang } 3472bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook } 3473bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook 3474e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal /** 3475177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal * Class to perform {@link LoaderManager.LoaderCallbacks} for creating {@link Folder} objects. 3476177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal */ 3477177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private class FolderLoads implements LoaderManager.LoaderCallbacks<ObjectCursor<Folder>> { 3478177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3479177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal public Loader<ObjectCursor<Folder>> onCreateLoader(int id, Bundle args) { 3480177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final String[] everything = UIProvider.FOLDERS_PROJECTION; 3481177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal switch (id) { 3482177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_FOLDER_CURSOR: 3483177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_FOLDER_CURSOR created"); 3484177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final ObjectCursorLoader<Folder> loader = new 3485177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal ObjectCursorLoader<Folder>( 3486259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy mContext, mFolder.folderUri.fullUri, everything, Folder.FACTORY); 3487177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal loader.setUpdateThrottle(mFolderItemUpdateDelayMs); 3488177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return loader; 3489177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_RECENT_FOLDERS: 3490177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_RECENT_FOLDERS created"); 3491f2632b979d7f17a548c34cccae94b2a0046cee32Yu Ping Hu if (mAccount != null && mAccount.recentFolderListUri != null 3492f2632b979d7f17a548c34cccae94b2a0046cee32Yu Ping Hu && !mAccount.recentFolderListUri.equals(Uri.EMPTY)) { 3493177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return new ObjectCursorLoader<Folder>(mContext, 3494177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mAccount.recentFolderListUri, everything, Folder.FACTORY); 3495177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3496177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3497177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_ACCOUNT_INBOX: 3498177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_ACCOUNT_INBOX created"); 3499177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Uri defaultInbox = Settings.getDefaultInboxUri(mAccount.settings); 3500177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Uri inboxUri = defaultInbox.equals(Uri.EMPTY) ? 3501177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mAccount.folderListUri : defaultInbox; 3502177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "Loading the default inbox: %s", inboxUri); 3503177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (inboxUri != null) { 3504177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return new ObjectCursorLoader<Folder>(mContext, inboxUri, 3505177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal everything, Folder.FACTORY); 3506177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3507177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3508177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_SEARCH: 3509177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_SEARCH created"); 3510177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return Folder.forSearchResults(mAccount, 3511177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal args.getString(ConversationListContext.EXTRA_SEARCH_QUERY), 35121a864cce6321f46031d6cd43e205278d0f219f92Jin Cao // We can just use current time as a unique identifier for this search 35131a864cce6321f46031d6cd43e205278d0f219f92Jin Cao Long.toString(SystemClock.uptimeMillis()), 3514177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getActivityContext()); 3515177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_FIRST_FOLDER: 3516177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_FIRST_FOLDER created"); 3517177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Uri folderUri = args.getParcelable(Utils.EXTRA_FOLDER_URI); 3518177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mConversationToShow = args.getParcelable(Utils.EXTRA_CONVERSATION); 3519177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (mConversationToShow != null && mConversationToShow.position < 0){ 3520177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mConversationToShow.position = 0; 3521177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3522177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return new ObjectCursorLoader<Folder>(mContext, folderUri, 3523177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal everything, Folder.FACTORY); 3524177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal default: 3525177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.wtf(LOG_TAG, "FolderLoads.onCreateLoader(%d) for invalid id", id); 3526177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return null; 3527177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3528177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return null; 3529177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3530177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3531177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3532177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal public void onLoadFinished(Loader<ObjectCursor<Folder>> loader, ObjectCursor<Folder> data) { 3533177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data == null) { 3534177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.e(LOG_TAG, "Received null cursor from loader id: %d", loader.getId()); 3535177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 35360c532efa4ec664b50a0ccff989667599e72cc4fcTony Mantler if (isDestroyed()) { 35370c532efa4ec664b50a0ccff989667599e72cc4fcTony Mantler return; 35380c532efa4ec664b50a0ccff989667599e72cc4fcTony Mantler } 3539177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal switch (loader.getId()) { 3540177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_FOLDER_CURSOR: 3541177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data != null && data.moveToFirst()) { 3542177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Folder folder = data.getModel(); 3543177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal setHasFolderChanged(folder); 3544177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mFolder = folder; 3545177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mFolderObservable.notifyChanged(); 3546177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } else { 3547177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "Unable to get the folder %s", 354826a20758413f0f8629ea71a0943304e3ae740165Tony Mantler mFolder != null ? mFolder.name : ""); 3549177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3550177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3551177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_RECENT_FOLDERS: 3552177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Few recent folders and we are running on a phone? Populate the default 3553177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // recents. The number of default recent folders is at least 2: every provider 3554177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // has at least two folders, and the recent folder count never decreases. 3555177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Having a single recent folder is an erroneous case, and we can gracefully 3556177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // recover by populating default recents. The default recents will not stomp on 3557177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // the existing value: it will be shown in addition to the default folders: 3558177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // the max number of recent folders is more than 1+num(defaultRecents). 3559177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data != null && data.getCount() <= 1 && !mIsTablet) { 3560177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final class PopulateDefault extends AsyncTask<Uri, Void, Void> { 3561177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3562177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal protected Void doInBackground(Uri... uri) { 3563177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Asking for an update on the URI and ignore the result. 3564177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final ContentResolver resolver = mContext.getContentResolver(); 3565177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal resolver.update(uri[0], null, null, null); 3566177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return null; 3567177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3568177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3569177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Uri uri = mAccount.defaultRecentFolderListUri; 3570177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.v(LOG_TAG, "Default recents at %s", uri); 3571177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal new PopulateDefault().execute(uri); 3572177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3573177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3574177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.v(LOG_TAG, "Reading recent folders from the cursor."); 3575177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mRecentFolderList.loadFromUiProvider(data); 3576177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (isAnimating()) { 3577177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mRecentsDataUpdated = true; 3578177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } else { 3579177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mRecentFolderObservers.notifyChanged(); 3580177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3581177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3582177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_ACCOUNT_INBOX: 3583177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data != null && !data.isClosed() && data.moveToFirst()) { 3584177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Folder inbox = data.getModel(); 3585ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang onFolderChanged(inbox, false /* force */); 3586177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Just want to get the inbox, don't care about updates to it 3587177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // as this will be tracked by the folder change listener. 3588177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getLoaderManager().destroyLoader(LOADER_ACCOUNT_INBOX); 3589177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } else { 3590177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "Unable to get the account inbox for account %s", 359126a20758413f0f8629ea71a0943304e3ae740165Tony Mantler mAccount != null ? mAccount.getEmailAddress() : ""); 3592177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3593177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3594177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_SEARCH: 3595177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data != null && data.getCount() > 0) { 3596177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal data.moveToFirst(); 3597177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Folder search = data.getModel(); 3598177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal updateFolder(search); 3599177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mConvListContext = ConversationListContext.forSearchQuery(mAccount, mFolder, 3600177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getIntent() 3601177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal .getStringExtra(UIProvider.SearchQueryParameters.QUERY)); 3602177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal showConversationList(mConvListContext); 3603177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.invalidateOptionsMenu(); 3604177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mHaveSearchResults = search.totalCount > 0; 3605177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getLoaderManager().destroyLoader(LOADER_SEARCH); 3606177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } else { 3607177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.e(LOG_TAG, "Null/empty cursor returned by LOADER_SEARCH loader"); 3608177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3609177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3610177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_FIRST_FOLDER: 3611177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data == null || data.getCount() <=0 || !data.moveToFirst()) { 3612177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return; 3613177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3614177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Folder folder = data.getModel(); 3615177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal boolean handled = false; 3616177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (folder != null) { 3617ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang onFolderChanged(folder, false /* force */); 3618177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal handled = true; 3619177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3620177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (mConversationToShow != null) { 3621177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Open the conversation. 3622177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal showConversation(mConversationToShow); 3623177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal handled = true; 3624177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3625177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (!handled) { 3626177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // We have an account, but nothing else: load the default inbox. 3627177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal loadAccountInbox(); 3628177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3629177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mConversationToShow = null; 3630177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // And don't run this anymore. 3631177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getLoaderManager().destroyLoader(LOADER_FIRST_FOLDER); 3632177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3633177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3634177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3635177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3636177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3637177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal public void onLoaderReset(Loader<ObjectCursor<Folder>> loader) { 3638177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3639177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3640177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3641177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal /** 3642177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal * Class to perform {@link LoaderManager.LoaderCallbacks} for creating {@link Account} objects. 3643177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal */ 3644177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private class AccountLoads implements LoaderManager.LoaderCallbacks<ObjectCursor<Account>> { 3645177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final String[] mProjection = UIProvider.ACCOUNTS_PROJECTION; 3646177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final CursorCreator<Account> mFactory = Account.FACTORY; 3647177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3648177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3649177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal public Loader<ObjectCursor<Account>> onCreateLoader(int id, Bundle args) { 3650177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal switch (id) { 3651177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_ACCOUNT_CURSOR: 3652177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_ACCOUNT_CURSOR created"); 3653177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return new ObjectCursorLoader<Account>(mContext, 3654177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal MailAppProvider.getAccountsUri(), mProjection, mFactory); 3655177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_ACCOUNT_UPDATE_CURSOR: 3656177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_ACCOUNT_UPDATE_CURSOR created"); 3657177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return new ObjectCursorLoader<Account>(mContext, mAccount.uri, mProjection, 3658177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mFactory); 3659177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal default: 3660177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.wtf(LOG_TAG, "Got an id (%d) that I cannot create!", id); 3661177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3662177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3663177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return null; 3664177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3665177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3666177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3667177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal public void onLoadFinished(Loader<ObjectCursor<Account>> loader, 3668177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal ObjectCursor<Account> data) { 3669177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data == null) { 3670177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.e(LOG_TAG, "Received null cursor from loader id: %d", loader.getId()); 3671177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 36720c532efa4ec664b50a0ccff989667599e72cc4fcTony Mantler if (isDestroyed()) { 36730c532efa4ec664b50a0ccff989667599e72cc4fcTony Mantler return; 36740c532efa4ec664b50a0ccff989667599e72cc4fcTony Mantler } 3675177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal switch (loader.getId()) { 3676177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_ACCOUNT_CURSOR: 3677d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal // We have received an update on the list of accounts. 3678177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data == null) { 3679177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Nothing useful to do if we have no valid data. 3680177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3681177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3682761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang final long count = data.getCount(); 3683761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang if (count == 0) { 3684177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // If an empty cursor is returned, the MailAppProvider is indicating that 3685177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // no accounts have been specified. We want to navigate to the 3686177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // "add account" activity that will handle the intent returned by the 3687177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // MailAppProvider 3688177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3689177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // If the MailAppProvider believes that all accounts have been loaded, 3690177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // and the account list is still empty, we want to prompt the user to add 3691177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // an account. 3692177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Bundle extras = data.getExtras(); 3693177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final boolean accountsLoaded = 3694177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal extras.getInt(AccountCursorExtraKeys.ACCOUNTS_LOADED) != 0; 3695177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3696177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (accountsLoaded) { 3697177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Intent noAccountIntent = MailAppProvider.getNoAccountIntent 3698177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal (mContext); 3699177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (noAccountIntent != null) { 3700177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.startActivityForResult(noAccountIntent, 3701177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal ADD_ACCOUNT_REQUEST_CODE); 3702177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3703177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3704177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } else { 3705177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final boolean accountListUpdated = accountsUpdated(data); 3706c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal if (!mHaveAccountList || accountListUpdated) { 3707c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal mHaveAccountList = updateAccounts(data); 3708177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3709761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang Analytics.getInstance().setCustomDimension(Analytics.CD_INDEX_ACCOUNT_COUNT, 3710761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang Long.toString(count)); 3711177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3712177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3713177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_ACCOUNT_UPDATE_CURSOR: 3714177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // We have received an update for current account. 3715177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data != null && data.moveToFirst()) { 3716177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Account updatedAccount = data.getModel(); 3717d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal // Make sure that this is an update for the current account 3718177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (updatedAccount.uri.equals(mAccount.uri)) { 3719177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Settings previousSettings = mAccount.settings; 3720177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3721177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Update the controller's reference to the current account 3722177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mAccount = updatedAccount; 3723177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "AbstractActivityController.onLoadFinished(): " 3724177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal + "mAccount = %s", mAccount.uri); 3725177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3726177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Only notify about a settings change if something differs 3727177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (!Objects.equal(mAccount.settings, previousSettings)) { 3728177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mAccountObservers.notifyChanged(); 3729177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3730177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal perhapsEnterWaitMode(); 3731177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } else { 3732177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.e(LOG_TAG, "Got update for account: %s with current account:" 3733177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal + " %s", updatedAccount.uri, mAccount.uri); 3734177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // We need to restart the loader, so the correct account information 3735177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // will be returned. 3736177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal restartOptionalLoader(LOADER_ACCOUNT_UPDATE_CURSOR, this, Bundle.EMPTY); 3737177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3738177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3739177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3740177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3741177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3742177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3743177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3744177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal public void onLoaderReset(Loader<ObjectCursor<Account>> loader) { 3745d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal // Do nothing. In onLoadFinished() we copy the relevant data from the cursor. 3746177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3747177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3748177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3749177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal /** 3750f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal * Updates controller state based on search results and shows first conversation if required. 375187a8982af83168453b6dc219fe984bff68047bebAndy Huang * Be sure to call the super-implementation if overriding. 3752f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal */ 375387a8982af83168453b6dc219fe984bff68047bebAndy Huang protected void perhapsShowFirstConversation() { 375487a8982af83168453b6dc219fe984bff68047bebAndy Huang mHaveSearchResults = Intent.ACTION_SEARCH.equals(mActivity.getIntent().getAction()) 375587a8982af83168453b6dc219fe984bff68047bebAndy Huang && mConversationListCursor.getCount() > 0; 3756f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal } 3757f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal 3758f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal /** 3759e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal * Destroy the pending {@link DestructiveAction} till now and assign the given action as the 3760e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal * next destructive action.. 3761e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal * @param nextAction the next destructive action to be performed. This can be null. 3762e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal */ 3763715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void destroyPending(DestructiveAction nextAction) { 3764e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal // If there is a pending action, perform that first. 3765e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal if (mPendingDestruction != null) { 3766e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal mPendingDestruction.performAction(); 3767e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal } 3768e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal mPendingDestruction = nextAction; 3769e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal } 3770e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal 3771e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal /** 3772e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal * Register a destructive action with the controller. This performs the previous destructive 3773acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal * action as a side effect. This method is final because we don't want the child classes to 37743d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal * embellish this method any more. 3775715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param action the action to register. 3776e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal */ 3777715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void registerDestructiveAction(DestructiveAction action) { 3778e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal // TODO(viki): This is not a good idea. The best solution is for clients to request a 3779e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal // destructive action from the controller and for the controller to own the action. This is 3780e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal // a half-way solution while refactoring DestructiveAction. 3781e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal destroyPending(action); 3782e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal } 3783e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal 3784531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal @Override 378530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public final DestructiveAction getBatchAction(int action, UndoCallback undoCallback) { 3786ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao final DestructiveAction da = new ConversationAction(action, mCheckedSet.values(), true); 378730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao da.setUndoCallback(undoCallback); 3788e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal registerDestructiveAction(da); 3789e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal return da; 3790e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal } 379141e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal 3792de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira @Override 379330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public final DestructiveAction getDeferredBatchAction(int action, UndoCallback undoCallback) { 3794ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao return getDeferredAction(action, mCheckedSet.values(), true, undoCallback); 3795f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp } 3796f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp 3797f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp /** 3798f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * Get a destructive action for a menu action. This is a temporary method, 3799f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * to control the profusion of {@link DestructiveAction} classes that are 3800f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * created. Please do not copy this paradigm. 3801f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * @param action the resource ID of the menu action: R.id.delete, for 3802f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * example 3803f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * @param target the conversations to act upon. 3804f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * @return a {@link DestructiveAction} that performs the specified action. 3805f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp */ 3806715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private DestructiveAction getDeferredAction(int action, Collection<Conversation> target, 380730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao boolean batch, UndoCallback callback) { 380830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao ConversationAction cAction = new ConversationAction(action, target, batch); 380930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao cAction.setUndoCallback(callback); 381030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return cAction; 3811de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira } 3812de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira 3813bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal /** 3814bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal * Class to change the folders that are assigned to a set of conversations. This is destructive 3815bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal * because the user can remove the current folder from the conversation, in which case it has 3816bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal * to be animated away from the current folder. 3817bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal */ 381841e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal private class FolderDestruction implements DestructiveAction { 381977eee625cd8c317c605acfd06cd3a7e22120a0fdPaul Westbrook private final Collection<Conversation> mTarget; 38208db7e407109532557718c6b8064792f2df7a073dMindy Pereira private final ArrayList<FolderOperation> mFolderOps = new ArrayList<FolderOperation>(); 382141e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal private final boolean mIsDestructive; 38227f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal /** Whether this destructive action has already been performed */ 38237f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal private boolean mCompleted; 3824e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon private final boolean mIsSelectedSet; 3825e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon private final boolean mShowUndo; 3826e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon private final int mAction; 38276a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy private final Folder mActionFolder; 382841e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal 382930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao private UndoCallback mUndoCallback; 383030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 383141e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal /** 383241e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal * Create a new folder destruction object to act on the given conversations. 3833715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param target conversations to act upon. 38346a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy * @param actionFolder the {@link Folder} being acted upon, used for displaying the undo bar 383541e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal */ 38367f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal private FolderDestruction(final Collection<Conversation> target, 38378db7e407109532557718c6b8064792f2df7a073dMindy Pereira final Collection<FolderOperation> folders, boolean isDestructive, boolean isBatch, 38386a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy boolean showUndo, int action, final Folder actionFolder) { 383977eee625cd8c317c605acfd06cd3a7e22120a0fdPaul Westbrook mTarget = ImmutableList.copyOf(target); 38408db7e407109532557718c6b8064792f2df7a073dMindy Pereira mFolderOps.addAll(folders); 384141e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal mIsDestructive = isDestructive; 3842f3a455644f0899a01fff4782811fcff473f9aff0Mindy Pereira mIsSelectedSet = isBatch; 384306642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira mShowUndo = showUndo; 384401f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira mAction = action; 38456a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy mActionFolder = actionFolder; 384641e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal } 384741e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal 384841e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal @Override 384930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public void setUndoCallback(UndoCallback undoCallback) { 385030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mUndoCallback = undoCallback; 385130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 385230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 385330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao @Override 385441e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal public void performAction() { 38557f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal if (isPerformed()) { 38567f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal return; 38577f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal } 38582cb6c1ca2b508331ee29d16b71f5ec024cd22555Jin Cao if (mIsDestructive && mShowUndo && mTarget.size() > 0) { 3859cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp ToastBarOperation undoOp = new ToastBarOperation(mTarget.size(), mAction, 38606a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy ToastBarOperation.UNDO, mIsSelectedSet, mActionFolder); 386141e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal onUndoAvailable(undoOp); 386241e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal } 38638db7e407109532557718c6b8064792f2df7a073dMindy Pereira // For each conversation, for each operation, add/ remove the 38648db7e407109532557718c6b8064792f2df7a073dMindy Pereira // appropriate folders. 3865cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp ArrayList<ConversationOperation> ops = new ArrayList<ConversationOperation>(); 3866cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp ArrayList<Uri> folderUris; 3867cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp ArrayList<Boolean> adds; 38688db7e407109532557718c6b8064792f2df7a073dMindy Pereira for (Conversation target : mTarget) { 3869cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp HashMap<Uri, Folder> targetFolders = Folder.hashMapForFolders(target 3870cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp .getRawFolders()); 3871cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp folderUris = new ArrayList<Uri>(); 3872cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp adds = new ArrayList<Boolean>(); 387301f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira if (mIsDestructive) { 387401f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira target.localDeleteOnUpdate = true; 387501f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira } 38768db7e407109532557718c6b8064792f2df7a073dMindy Pereira for (FolderOperation op : mFolderOps) { 3877259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy folderUris.add(op.mFolder.folderUri.fullUri); 3878cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp adds.add(op.mAdd ? Boolean.TRUE : Boolean.FALSE); 38798db7e407109532557718c6b8064792f2df7a073dMindy Pereira if (op.mAdd) { 3880259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy targetFolders.put(op.mFolder.folderUri.fullUri, op.mFolder); 38818db7e407109532557718c6b8064792f2df7a073dMindy Pereira } else { 3882259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy targetFolders.remove(op.mFolder.folderUri.fullUri); 38838db7e407109532557718c6b8064792f2df7a073dMindy Pereira } 38848db7e407109532557718c6b8064792f2df7a073dMindy Pereira } 388526746eb4acb159f3ce0d411c10d85a1de3e958a0Paul Westbrook ops.add(mConversationListCursor.getConversationFolderOperation(target, 388630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao folderUris, adds, targetFolders.values(), mUndoCallback)); 3887389f0b21a9b21bc3607b810c88272d06d48d0fe6mindyp } 3888389f0b21a9b21bc3607b810c88272d06d48d0fe6mindyp if (mConversationListCursor != null) { 38899e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateBulkValues(ops); 38908db7e407109532557718c6b8064792f2df7a073dMindy Pereira } 38917f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal refreshConversationList(); 3892f3a455644f0899a01fff4782811fcff473f9aff0Mindy Pereira if (mIsSelectedSet) { 3893ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao mCheckedSet.clear(); 3894f3a455644f0899a01fff4782811fcff473f9aff0Mindy Pereira } 38957f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal } 38968db7e407109532557718c6b8064792f2df7a073dMindy Pereira 38977f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal /** 38987f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal * Returns true if this action has been performed, false otherwise. 3899839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang * 39007f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal */ 39017f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal private synchronized boolean isPerformed() { 39027f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal if (mCompleted) { 39037f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal return true; 390441e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal } 39057f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal mCompleted = true; 39067f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal return false; 390741e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal } 390841e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal } 39097f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal 3910c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp public final DestructiveAction getFolderChange(Collection<Conversation> target, 3911c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp Collection<FolderOperation> folders, boolean isDestructive, boolean isBatch, 391230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao boolean showUndo, final boolean isMoveTo, final Folder actionFolder, 391330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao UndoCallback undoCallback) { 3914c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp final DestructiveAction da = getDeferredFolderChange(target, folders, isDestructive, 391530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao isBatch, showUndo, isMoveTo, actionFolder, undoCallback); 3916c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp registerDestructiveAction(da); 3917c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp return da; 3918c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp } 3919c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp 3920c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp public final DestructiveAction getDeferredFolderChange(Collection<Conversation> target, 39218db7e407109532557718c6b8064792f2df7a073dMindy Pereira Collection<FolderOperation> folders, boolean isDestructive, boolean isBatch, 392230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao boolean showUndo, final boolean isMoveTo, final Folder actionFolder, 392330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao UndoCallback undoCallback) { 392430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final DestructiveAction fd = new FolderDestruction(target, folders, isDestructive, isBatch, 392530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao showUndo, isMoveTo ? R.id.move_folder : R.id.change_folders, actionFolder); 392630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao fd.setUndoCallback(undoCallback); 392730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return fd; 392801f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira } 392901f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira 393001f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira @Override 393101f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira public final DestructiveAction getDeferredRemoveFolder(Collection<Conversation> target, 393201f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira Folder toRemove, boolean isDestructive, boolean isBatch, 393330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao boolean showUndo, UndoCallback undoCallback) { 393401f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira Collection<FolderOperation> folderOps = new ArrayList<FolderOperation>(); 393501f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira folderOps.add(new FolderOperation(toRemove, false)); 393630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final DestructiveAction da = new FolderDestruction(target, folderOps, isDestructive, isBatch, 39376a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy showUndo, R.id.remove_folder, mFolder); 393830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao da.setUndoCallback(undoCallback); 393930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return da; 394001f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira } 394101f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira 39424f4782bcc53e13b30f1fd417beb1a6c04a54faedVikram Aggarwal @Override 39434f4782bcc53e13b30f1fd417beb1a6c04a54faedVikram Aggarwal public final void refreshConversationList() { 394475daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal final ConversationListFragment convList = getConversationListFragment(); 394575daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal if (convList == null) { 394675daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal return; 394775daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal } 394875daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal convList.requestListRefresh(); 394975daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal } 3950c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein 3951c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein protected final ActionClickedListener getUndoClickedListener( 3952c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein final AnimatedAdapter listAdapter) { 3953c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein return new ActionClickedListener() { 3954c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein @Override 3955f8ccdcfc26f362d9c20771e2295a0c0e8d1195f3Andrew Sapperstein public void onActionClicked(Context context) { 3956c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein if (mAccount.undoUri != null) { 3957c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein // NOTE: We might want undo to return the messages affected, in which case 3958c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein // the resulting cursor might be interesting... 3959c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein // TODO: Use UIProvider.SEQUENCE_QUERY_PARAMETER to indicate the set of 3960c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein // commands to undo 3961c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein if (mConversationListCursor != null) { 3962c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein mConversationListCursor.undo( 3963c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein mActivity.getActivityContext(), mAccount.undoUri); 3964c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 3965c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein if (listAdapter != null) { 3966c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein listAdapter.setUndo(true); 3967c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 3968c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 3969c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 3970c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein }; 3971c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 3972c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein 397341b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal /** 397441b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal * Shows an error toast in the bottom when a folder was not fetched successfully. 397541b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal * @param folder the folder which could not be fetched. 397641b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal * @param replaceVisibleToast if true, this should replace any currently visible toast. 397741b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal */ 39789d7519d18e8ddbcdd59b37eec7c85210fca0e8c2Andrew Sapperstein protected final void showErrorToast(final Folder folder, boolean replaceVisibleToast) { 397900179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein 398041b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal final ActionClickedListener listener; 398141b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal final int actionTextResourceId; 398200179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein final int lastSyncResult = folder.lastSyncResult; 3983deee5bee475a678bc2a4efe81c2900b1e5ac54dcJames Lemieux switch (UIProvider.getResultFromLastSyncResult(lastSyncResult)) { 398400179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein case UIProvider.LastSyncResult.CONNECTION_ERROR: 3985deee5bee475a678bc2a4efe81c2900b1e5ac54dcJames Lemieux // The sync status that caused this failure. 3986deee5bee475a678bc2a4efe81c2900b1e5ac54dcJames Lemieux final int syncStatus = UIProvider.getStatusFromLastSyncResult(lastSyncResult); 398741b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // Show: User explicitly pressed the refresh button and there is no connection 398841b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // Show: The first time the user enters the app and there is no connection 398941b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // TODO(viki): Implement this. 399041b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // Reference: http://b/7202801 3991deee5bee475a678bc2a4efe81c2900b1e5ac54dcJames Lemieux final boolean showToast = (syncStatus & UIProvider.SyncStatus.USER_REFRESH) != 0; 399241b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // Don't show: Already in the app; user switches to a synced label 399341b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // Don't show: In a live label and a background sync fails 399441b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal final boolean avoidToast = !showToast && (folder.syncWindow > 0 3995deee5bee475a678bc2a4efe81c2900b1e5ac54dcJames Lemieux || (syncStatus & UIProvider.SyncStatus.BACKGROUND_SYNC) != 0); 399641b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal if (avoidToast) { 399741b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal return; 399841b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal } 399900179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein listener = getRetryClickedListener(folder); 400000179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein actionTextResourceId = R.string.retry; 400100179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein break; 400200179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein case UIProvider.LastSyncResult.AUTH_ERROR: 400300179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein listener = getSignInClickedListener(); 400400179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein actionTextResourceId = R.string.signin; 400500179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein break; 400600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein case UIProvider.LastSyncResult.SECURITY_ERROR: 400700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein return; // Currently we do nothing for security errors. 400800179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein case UIProvider.LastSyncResult.STORAGE_ERROR: 400900179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein listener = getStorageErrorClickedListener(); 401000179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein actionTextResourceId = R.string.info; 401100179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein break; 401200179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein case UIProvider.LastSyncResult.INTERNAL_ERROR: 401300179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein listener = getInternalErrorClickedListener(); 401400179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein actionTextResourceId = R.string.report; 401500179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein break; 401600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein default: 401700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein return; 401800179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 401941b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal mToastBar.show(listener, 402041b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal Utils.getSyncStatusText(mActivity.getActivityContext(), lastSyncResult), 402100179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein actionTextResourceId, 40229d7519d18e8ddbcdd59b37eec7c85210fca0e8c2Andrew Sapperstein replaceVisibleToast, 40230ec03e8d930a58c9138b5ebe84468f99c332c504James Lemieux true /* autohide */, 40246a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy new ToastBarOperation(1, 0, ToastBarOperation.ERROR, false, folder)); 4025c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 4026c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein 402700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein private ActionClickedListener getRetryClickedListener(final Folder folder) { 4028c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein return new ActionClickedListener() { 4029c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein @Override 4030f8ccdcfc26f362d9c20771e2295a0c0e8d1195f3Andrew Sapperstein public void onActionClicked(Context context) { 4031c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein final Uri uri = folder.refreshUri; 4032c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein 4033c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein if (uri != null) { 40344969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook startAsyncRefreshTask(uri); 4035c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 4036c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 4037c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein }; 4038c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 403900179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein 404000179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein private ActionClickedListener getSignInClickedListener() { 404100179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein return new ActionClickedListener() { 404200179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein @Override 4043f8ccdcfc26f362d9c20771e2295a0c0e8d1195f3Andrew Sapperstein public void onActionClicked(Context context) { 4044122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook promptUserForAuthentication(mAccount); 404500179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 404600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein }; 404700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 404800179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein 404900179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein private ActionClickedListener getStorageErrorClickedListener() { 405000179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein return new ActionClickedListener() { 405100179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein @Override 4052f8ccdcfc26f362d9c20771e2295a0c0e8d1195f3Andrew Sapperstein public void onActionClicked(Context context) { 40534969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook showStorageErrorDialog(); 405400179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 405500179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein }; 405600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 405700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein 40584969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook private void showStorageErrorDialog() { 40594969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook DialogFragment fragment = (DialogFragment) 40604969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook mFragmentManager.findFragmentByTag(SYNC_ERROR_DIALOG_FRAGMENT_TAG); 40614969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook if (fragment == null) { 40624969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook fragment = SyncErrorDialogFragment.newInstance(); 40634969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 40644969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook fragment.show(mFragmentManager, SYNC_ERROR_DIALOG_FRAGMENT_TAG); 40654969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 40664969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook 406700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein private ActionClickedListener getInternalErrorClickedListener() { 406800179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein return new ActionClickedListener() { 406900179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein @Override 4070f8ccdcfc26f362d9c20771e2295a0c0e8d1195f3Andrew Sapperstein public void onActionClicked(Context context) { 407183e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook Utils.sendFeedback(mActivity, mAccount, true /* reportingProblem */); 407200179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 407300179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein }; 407400179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 40754969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook 40764969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook @Override 40774969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook public void onFooterViewLoadMoreClick(Folder folder) { 40784969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook if (folder != null && folder.loadMoreUri != null) { 40794969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook startAsyncRefreshTask(folder.loadMoreUri); 40804969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 40814969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 40824969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook 40834969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook private void startAsyncRefreshTask(Uri uri) { 40844969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook if (mFolderSyncTask != null) { 40854969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook mFolderSyncTask.cancel(true); 40864969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 40874969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook mFolderSyncTask = new AsyncRefreshTask(mActivity.getActivityContext(), uri); 40884969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook mFolderSyncTask.execute(); 40894969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 4090122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook 4091122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook private void promptUserForAuthentication(Account account) { 4092429399b738f444911117978bf8229036e8814b1ePaul Westbrook if (account != null && !Utils.isEmpty(account.reauthenticationIntentUri)) { 4093122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook final Intent authenticationIntent = 4094122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook new Intent(Intent.ACTION_VIEW, account.reauthenticationIntentUri); 4095122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook mActivity.startActivityForResult(authenticationIntent, REAUTHENTICATE_REQUEST_CODE); 4096122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook } 4097122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook } 4098ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp 4099ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp @Override 4100ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp public void onAccessibilityStateChanged() { 4101ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp // Clear the cache of objects. 4102ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp ConversationItemViewModel.onAccessibilityUpdated(); 4103ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp // Re-render the list if it exists. 4104a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal final ConversationListFragment frag = getConversationListFragment(); 4105ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp if (frag != null) { 4106ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp AnimatedAdapter adapter = frag.getAnimatedAdapter(); 4107ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp if (adapter != null) { 4108ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp adapter.notifyDataSetInvalidated(); 4109ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp } 4110ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp } 4111ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp } 41126cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal 41136cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal @Override 411430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public void makeDialogListener (final int action, final boolean isBatch, 411530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao UndoCallback undoCallback) { 4116b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal final Collection<Conversation> target; 4117b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal if (isBatch) { 4118ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao target = mCheckedSet.values(); 4119b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal } else { 4120b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal LogUtils.d(LOG_TAG, "Will act upon %s", mCurrentConversation); 4121b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal target = Conversation.listOf(mCurrentConversation); 4122b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal } 412330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final DestructiveAction destructiveAction = getDeferredAction(action, target, isBatch, 412430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao undoCallback); 41256cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal mDialogAction = action; 4126b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal mDialogFromSelectedSet = isBatch; 41276cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal mDialogListener = new AlertDialog.OnClickListener() { 41286cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal @Override 41296cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal public void onClick(DialogInterface dialog, int which) { 4130caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy delete(action, target, destructiveAction, isBatch); 41316cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal // Afterwards, let's remove references to the listener and the action. 41326cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal setListener(null, -1); 41336cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal } 41346cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal }; 41356cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal } 41366cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal 41376cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal @Override 41386cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal public AlertDialog.OnClickListener getListener() { 41396cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal return mDialogListener; 41406cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal } 41416cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal 41426cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal /** 41436cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal * Sets the listener for the positive action on a confirmation dialog. Since only a single 41446cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal * confirmation dialog can be shown, this overwrites the previous listener. It is safe to 41456cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal * unset the listener; in which case action should be set to -1. 4146715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param listener the listener that will perform the task for this dialog's positive action. 4147715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param action the action that created this dialog. 41486cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal */ 41496cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal private void setListener(AlertDialog.OnClickListener listener, final int action){ 41506cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal mDialogListener = listener; 41516cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal mDialogAction = action; 41526cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal } 415369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 415469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal @Override 415569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal public VeiledAddressMatcher getVeiledAddressMatcher() { 415669a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal return mVeiledMatcher; 4157a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 4158a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal 4159a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal @Override 4160a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal public void setDetachedMode() { 4161a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // Tell the conversation list not to select anything. 4162a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal final ConversationListFragment frag = getConversationListFragment(); 4163a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal if (frag != null) { 4164a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal frag.setChoiceNone(); 416581230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal } else if (mIsTablet) { 416681230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal // How did we ever land here? Detached mode, and no CLF on tablet??? 4167a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal LogUtils.e(LOG_TAG, "AAC.setDetachedMode(): CLF = null!"); 4168a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 4169a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal mDetachedConvUri = mCurrentConversation.uri; 4170a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 4171a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal 4172a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal private void clearDetachedMode() { 4173a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // Tell the conversation list to go back to its usual selection behavior. 4174a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal final ConversationListFragment frag = getConversationListFragment(); 4175a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal if (frag != null) { 4176a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal frag.revertChoiceMode(); 417781230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal } else if (mIsTablet) { 417881230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal // How did we ever land here? Detached mode, and no CLF on tablet??? 417981230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.e(LOG_TAG, "AAC.clearDetachedMode(): CLF = null on tablet!"); 4180a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 4181a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal mDetachedConvUri = null; 4182a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 418312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 418461f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang @Override 41858712f412130f06cd21e68e89d87d28b226830e1aAndy Huang public boolean shouldPreventListSwipesEntirely() { 41868712f412130f06cd21e68e89d87d28b226830e1aAndy Huang return false; 41878712f412130f06cd21e68e89d87d28b226830e1aAndy Huang } 41888712f412130f06cd21e68e89d87d28b226830e1aAndy Huang 41898712f412130f06cd21e68e89d87d28b226830e1aAndy Huang @Override 419061f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang public DrawerController getDrawerController() { 419161f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang return mDrawerListener; 419261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 419361f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 419461f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private class MailDrawerListener extends Observable<DrawerLayout.DrawerListener> 419561f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang implements DrawerLayout.DrawerListener, DrawerController { 4196a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein private int mDrawerState; 4197fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein private float mOldSlideOffset; 4198a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein 4199a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein public MailDrawerListener() { 4200a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mDrawerState = DrawerLayout.STATE_IDLE; 4201fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein mOldSlideOffset = 0.f; 4202a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein } 4203a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein 420412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang @Override 42053e95fe9af0d1f8d7557d6b8e9daf4cf08aade140Andy Huang public boolean isDrawerEnabled() { 42063e95fe9af0d1f8d7557d6b8e9daf4cf08aade140Andy Huang return AbstractActivityController.this.isDrawerEnabled(); 42073e95fe9af0d1f8d7557d6b8e9daf4cf08aade140Andy Huang } 42083e95fe9af0d1f8d7557d6b8e9daf4cf08aade140Andy Huang 42093e95fe9af0d1f8d7557d6b8e9daf4cf08aade140Andy Huang @Override 421061f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang public void registerDrawerListener(DrawerLayout.DrawerListener l) { 421161f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang registerObserver(l); 421261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 421361f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 421461f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang @Override 421561f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang public void unregisterDrawerListener(DrawerLayout.DrawerListener l) { 421661f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang unregisterObserver(l); 421761f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 421861f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 421961f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang @Override 422061f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang public boolean isDrawerOpen() { 422161f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang return isDrawerEnabled() && mDrawerContainer.isDrawerOpen(mDrawerPullout); 422261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 422361f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 422461f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang @Override 422561f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang public boolean isDrawerVisible() { 422661f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang return isDrawerEnabled() && mDrawerContainer.isDrawerVisible(mDrawerPullout); 422761f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 422861f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 422961f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang @Override 4230f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang public void toggleDrawerState() { 4231f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang AbstractActivityController.this.toggleDrawerState(); 4232f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang } 4233f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang 4234f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang @Override 423512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang public void onDrawerOpened(View drawerView) { 423612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerToggle.onDrawerOpened(drawerView); 423761f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 423861f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang for (DrawerLayout.DrawerListener l : mObservers) { 423961f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang l.onDrawerOpened(drawerView); 424061f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 424112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 424212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 424312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang @Override 424412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang public void onDrawerClosed(View drawerView) { 424512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerToggle.onDrawerClosed(drawerView); 424612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (mHasNewAccountOrFolder) { 424712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang refreshDrawer(); 424812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 424910c99efe431335ce8db9924c3dcb0f977f3c63f3Scott Kennedy 425010c99efe431335ce8db9924c3dcb0f977f3c63f3Scott Kennedy // When closed, we want to use either the burger, or up, based on where we are 425110c99efe431335ce8db9924c3dcb0f977f3c63f3Scott Kennedy final int mode = mViewMode.getMode(); 42529695e0046f79bd2d7166a411d6feff4cf0fb2539Jin Cao final boolean isTopLevel = Folder.isRoot(mFolder); 4253207e662df01c550a4894bec03219820528365508Rohan Shah updateDrawerIndicator(mode, isTopLevel); 425461f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 425561f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang for (DrawerLayout.DrawerListener l : mObservers) { 425661f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang l.onDrawerClosed(drawerView); 425761f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 425812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 425912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 426012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang /** 426112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * As part of the overriden function, it will animate the alpha of the conversation list 426212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * view along with the drawer sliding when we're in the process of switching accounts or 426312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * folders. Note, this is the same amount of work done as {@link ValueAnimator#ofFloat}. 426412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang */ 426512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang @Override 426612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang public void onDrawerSlide(View drawerView, float slideOffset) { 426712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerToggle.onDrawerSlide(drawerView, slideOffset); 426812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (mHasNewAccountOrFolder && mListViewForAnimating != null) { 426912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mListViewForAnimating.setAlpha(slideOffset); 427012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 4271fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein 4272fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // This code handles when to change the visibility of action items 4273fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // based on drawer state. The basic logic is that right when we 4274fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // open the drawer, we hide the action items. We show the action items 4275fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // when the drawer closes. However, due to the animation of the drawer closing, 4276fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // to make the reshowing of the action items feel right, we make the items visible 4277fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // slightly sooner. 4278fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // 4279fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // However, to make the animating behavior work properly, we have to know whether 4280fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // we're animating open or closed. Only if we're animating closed do we want to 4281fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // show the action items early. We save the last slide offset so that we can compare 4282fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // the current slide offset to it to determine if we're opening or closing. 4283fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein if (mDrawerState == DrawerLayout.STATE_SETTLING) { 4284fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein if (mHideMenuItems && slideOffset < 0.15f && mOldSlideOffset > slideOffset) { 4285fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein mHideMenuItems = false; 428652882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein mActivity.supportInvalidateOptionsMenu(); 428743fab3224230c235db5be395f96096e1cac6b376Tony Mantler maybeEnableCabMode(); 4288fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein } else if (!mHideMenuItems && slideOffset > 0.f && mOldSlideOffset < slideOffset) { 4289fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein mHideMenuItems = true; 429052882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein mActivity.supportInvalidateOptionsMenu(); 429143fab3224230c235db5be395f96096e1cac6b376Tony Mantler disableCabMode(); 4292fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein } 4293fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein } else { 4294fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein if (mHideMenuItems && Float.compare(slideOffset, 0.f) == 0) { 4295fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein mHideMenuItems = false; 429652882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein mActivity.supportInvalidateOptionsMenu(); 429743fab3224230c235db5be395f96096e1cac6b376Tony Mantler maybeEnableCabMode(); 4298fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein } else if (!mHideMenuItems && slideOffset > 0.f) { 4299fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein mHideMenuItems = true; 430052882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein mActivity.supportInvalidateOptionsMenu(); 430143fab3224230c235db5be395f96096e1cac6b376Tony Mantler disableCabMode(); 4302fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein } 4303fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein } 4304fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein 4305fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein mOldSlideOffset = slideOffset; 430610c99efe431335ce8db9924c3dcb0f977f3c63f3Scott Kennedy 430761f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang for (DrawerLayout.DrawerListener l : mObservers) { 430861f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang l.onDrawerSlide(drawerView, slideOffset); 430961f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 431012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 431112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 431212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang /** 431312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * This condition here should only be called when the drawer is stuck in a weird state 431412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * and doesn't register the onDrawerClosed, but shows up as idle. Make sure to refresh 431512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * and, more importantly, unlock the drawer when this is the case. 431612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang */ 431712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang @Override 431812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang public void onDrawerStateChanged(int newState) { 4319371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon LogUtils.d(LOG_TAG, "AAC onDrawerStateChanged %d", newState); 4320a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mDrawerState = newState; 4321a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mDrawerToggle.onDrawerStateChanged(mDrawerState); 432261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 432361f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang for (DrawerLayout.DrawerListener l : mObservers) { 432461f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang l.onDrawerStateChanged(newState); 432561f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 432661f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 4327e764cfd130c4f92ae823fd1f361ab70439e8ec95Andy Huang if (mViewMode.isSearchMode()) { 4328371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon return; 4329371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon } 4330a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein if (mDrawerState == DrawerLayout.STATE_IDLE) { 4331a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein if (mHasNewAccountOrFolder) { 4332a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein refreshDrawer(); 4333a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein } 4334a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein if (mConversationListLoadFinishedIgnored) { 4335a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mConversationListLoadFinishedIgnored = false; 4336a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein final Bundle args = new Bundle(); 4337a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein args.putParcelable(BUNDLE_ACCOUNT_KEY, mAccount); 4338a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein args.putParcelable(BUNDLE_FOLDER_KEY, mFolder); 4339a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mActivity.getLoaderManager().initLoader( 4340a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein LOADER_CONVERSATION_LIST, args, mListCursorCallbacks); 4341a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein } 434212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 434312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 434412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 434512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang /** 434612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * If we've reached a stable drawer state, unlock the drawer for usage, clear the 434712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * conversation list, and finish end actions. Also, make 434812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * {@link #mHasNewAccountOrFolder} false to reflect we're done changing. 434912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang */ 435012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang public void refreshDrawer() { 435112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mHasNewAccountOrFolder = false; 435212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); 435312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang ConversationListFragment conversationList = getConversationListFragment(); 435412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (conversationList != null) { 435512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang conversationList.clear(); 435612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 435754022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler mFolderOrAccountObservers.notifyChanged(); 435812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 4359a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein 4360a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein /** 4361a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein * Returns the most recent update of the {@link DrawerLayout}'s state provided 4362a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein * by {@link #onDrawerStateChanged(int)}. 4363a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein * @return The {@link DrawerLayout}'s current state. One of 4364a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein * {@link DrawerLayout#STATE_DRAGGING}, {@link DrawerLayout#STATE_IDLE}, 4365a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein * or {@link DrawerLayout#STATE_SETTLING}. 4366a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein */ 4367a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein public int getDrawerState() { 4368a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein return mDrawerState; 4369a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein } 437012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 437112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 43728a72b8590d9166ada55f69eeb083d2b8c5c915c9Scott Kennedy @Override 43738a72b8590d9166ada55f69eeb083d2b8c5c915c9Scott Kennedy public boolean isDrawerPullEnabled() { 4374371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon return true; 43758a72b8590d9166ada55f69eeb083d2b8c5c915c9Scott Kennedy } 43765747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein 43775747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein @Override 43785747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein public boolean shouldHideMenuItems() { 43795747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein return mHideMenuItems; 43805747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein } 4381ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 4382ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang protected void navigateUpFolderHierarchy() { 4383ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang new AsyncTask<Void, Void, Folder>() { 4384ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang @Override 4385ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang protected Folder doInBackground(final Void... params) { 4386ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang if (mInbox == null) { 4387ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang // We don't have an inbox, but we need it 4388ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang final Cursor cursor = mContext.getContentResolver().query( 4389ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang mAccount.settings.defaultInbox, UIProvider.FOLDERS_PROJECTION, null, 4390ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang null, null); 4391ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 4392ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang if (cursor != null) { 4393ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang try { 4394ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang if (cursor.moveToFirst()) { 4395ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang mInbox = new Folder(cursor); 4396ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4397ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } finally { 4398ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang cursor.close(); 4399ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4400ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4401ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4402ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 4403ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang // Now try to load our parent 4404ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang final Folder folder; 4405ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 44065ac10036fd45cd2a6da32abd02e942617edec50dAlice Yang if (mFolder != null) { 4407e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon Cursor cursor = null; 4408e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon try { 4409e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon cursor = mContext.getContentResolver().query(mFolder.parent, 4410e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon UIProvider.FOLDERS_PROJECTION, null, null, null); 4411e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon 4412e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon if (cursor == null || !cursor.moveToFirst()) { 4413e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon // We couldn't load the parent, so use the inbox 4414e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon folder = mInbox; 4415e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon } else { 44165ac10036fd45cd2a6da32abd02e942617edec50dAlice Yang folder = new Folder(cursor); 4417e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon } 4418e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon } finally { 4419e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon if (cursor != null) { 44205ac10036fd45cd2a6da32abd02e942617edec50dAlice Yang cursor.close(); 44215ac10036fd45cd2a6da32abd02e942617edec50dAlice Yang } 4422ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 44235ac10036fd45cd2a6da32abd02e942617edec50dAlice Yang } else { 44245ac10036fd45cd2a6da32abd02e942617edec50dAlice Yang folder = mInbox; 4425ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4426ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 4427ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang return folder; 4428ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4429ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 4430ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang @Override 4431ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang protected void onPostExecute(final Folder result) { 4432ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang onFolderSelected(result); 4433ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4434ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); 4435ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4436f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy 4437f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy @Override 4438f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy public Parcelable getConversationListScrollPosition(final String folderUri) { 4439f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy return mConversationListScrollPositions.getParcelable(folderUri); 4440f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy } 4441f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy 4442f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy @Override 4443f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy public void setConversationListScrollPosition(final String folderUri, 4444f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy final Parcelable savedPosition) { 4445f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy mConversationListScrollPositions.putParcelable(folderUri, savedPosition); 4446f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy } 444753de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein 444853de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein @Override 444984662ce9ac05081b16dd58202acbc69c7e24a354Jin Cao public boolean setupEmptyIconView(Folder folder, boolean isEmpty) { 445084662ce9ac05081b16dd58202acbc69c7e24a354Jin Cao return false; 445184662ce9ac05081b16dd58202acbc69c7e24a354Jin Cao } 445284662ce9ac05081b16dd58202acbc69c7e24a354Jin Cao 445384662ce9ac05081b16dd58202acbc69c7e24a354Jin Cao @Override 445453de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein public View.OnClickListener getNavigationViewClickListener() { 445553de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein return mHomeButtonListener; 445653de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein } 445753de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein 445853de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein // TODO: Fold this into the outer class when b/16627877 is fixed 445953de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein private class HomeButtonListener implements View.OnClickListener { 446053de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein @Override 446153de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein public void onClick(View v) { 4462405a344937675f57fc9c6988b2b124410a270f13Jin Cao handleUpPress(); 446353de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein } 446453de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein } 44654a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal} 4466