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; 49e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.provider.SearchRecentSuggestions; 5012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huangimport android.support.v4.app.ActionBarDrawerToggle; 5112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huangimport android.support.v4.widget.DrawerLayout; 5252882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sappersteinimport android.support.v7.app.ActionBar; 53acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereiraimport android.view.DragEvent; 5412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huangimport android.view.Gravity; 55a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.view.KeyEvent; 56a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.view.Menu; 5728d5f72e0ad0db75b6243ee8125bfe3aadbdcb85Mindy Pereiraimport android.view.MenuInflater; 58a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.view.MenuItem; 59a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalimport android.view.MotionEvent; 60d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereiraimport android.view.View; 6112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huangimport android.widget.ListView; 62fd0c2974af56ad244006faab2651e054974a4b7bMindy Pereiraimport android.widget.Toast; 63a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 64b9e1a353c6a173a2885642dbcc1939f3281f29f7Vikram Aggarwalimport com.android.mail.ConversationListContext; 6559f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwalimport com.android.mail.MailLogService; 66f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huangimport com.android.mail.R; 67761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huangimport com.android.mail.analytics.Analytics; 68779dd6012a6c5b4d71255085059e57d94eab1a3fJin Caoimport com.android.mail.analytics.AnalyticsTimer; 69761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huangimport com.android.mail.analytics.AnalyticsUtils; 706cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwalimport com.android.mail.browse.ConfirmDialogFragment; 71967ede63e059810d9d4d425c50111d606014c893Mindy Pereiraimport com.android.mail.browse.ConversationCursor; 727c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Huimport com.android.mail.browse.ConversationCursor.ConversationOperation; 73ca87de41285bde382a894b6cb2d13c112c5d7a2fmindypimport com.android.mail.browse.ConversationItemViewModel; 748812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport com.android.mail.browse.ConversationMessage; 75bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrookimport com.android.mail.browse.ConversationPagerController; 767c9f6acdf2b992fecaf0b3ad0afe9ec30ec86f33Marc Blankimport com.android.mail.browse.SelectedConversationsActionMenu; 77991f453c8905ec683458f8b4ea0e2737832425d9Andy Huangimport com.android.mail.browse.SyncErrorDialogFragment; 7830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Caoimport com.android.mail.browse.UndoCallback; 799b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereiraimport com.android.mail.compose.ComposeActivity; 80177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwalimport com.android.mail.content.CursorCreator; 81177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwalimport com.android.mail.content.ObjectCursor; 82177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwalimport com.android.mail.content.ObjectCursorLoader; 831ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwalimport com.android.mail.providers.Account; 849b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereiraimport com.android.mail.providers.Conversation; 85839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huangimport com.android.mail.providers.ConversationInfo; 864a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwalimport com.android.mail.providers.Folder; 877a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwalimport com.android.mail.providers.FolderWatcher; 88c2074c4442eacf5604dd3cecd06b363e8fc574dePaul Westbrookimport com.android.mail.providers.MailAppProvider; 89dac00547ce8d44a964e4510315168ee413e55a75Mindy Pereiraimport com.android.mail.providers.Settings; 90e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport com.android.mail.providers.SuggestionsProvider; 9180aeac5356b5a14a5ef2aff8f0f72a464c9a3cb4Vikram Aggarwalimport com.android.mail.providers.UIProvider; 923cb28b5e1598f74dedbdb87b187d9bd7e132ff0fMindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities; 932388c5d208acd4e4e658aaacbbc5f080ee8e9f7cPaul Westbrookimport com.android.mail.providers.UIProvider.AccountCursorExtraKeys; 940d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedyimport com.android.mail.providers.UIProvider.AutoAdvance; 95c9d59184da271d5a6974edb709e3b39a5a970fa7Mindy Pereiraimport com.android.mail.providers.UIProvider.ConversationColumns; 965109c516b5cac279b4f99271953a27dd9a4828d8Paul Westbrookimport com.android.mail.providers.UIProvider.ConversationOperations; 9754452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwalimport com.android.mail.providers.UIProvider.FolderCapabilities; 98a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedyimport com.android.mail.providers.UIProvider.FolderType; 99c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sappersteinimport com.android.mail.ui.ActionableToastBar.ActionClickedListener; 100839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huangimport com.android.mail.utils.ContentProviderTask; 101144bfe739b93afdee0a1700a34806b0b287e5887Andy Huangimport com.android.mail.utils.DrawIdler; 102b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag; 1035cb0c3e684150d6d8ed4d9df4fb73a7606086aaaMindy Pereiraimport com.android.mail.utils.LogUtils; 10461f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huangimport com.android.mail.utils.MailObservable; 105cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedyimport com.android.mail.utils.NotificationActionUtils; 106fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwalimport com.android.mail.utils.Utils; 10769a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwalimport com.android.mail.utils.VeiledAddressMatcher; 108ca08fc170ca3f04572af8999645d5fd9e0bdb725Paul Westbrookimport com.google.common.base.Objects; 10977eee625cd8c317c605acfd06cd3a7e22120a0fdPaul Westbrookimport com.google.common.collect.ImmutableList; 110acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereiraimport com.google.common.collect.Lists; 111167faa8584750e37781f22ad7e6d61003029f954Marc Blankimport com.google.common.collect.Sets; 1124a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal 113167faa8584750e37781f22ad7e6d61003029f954Marc Blankimport java.util.ArrayList; 1149e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huangimport java.util.Arrays; 115fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereiraimport java.util.Collection; 116839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huangimport java.util.Collections; 1178db7e407109532557718c6b8064792f2df7a073dMindy Pereiraimport java.util.HashMap; 118cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwalimport java.util.List; 11923b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrookimport java.util.Set; 120bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blankimport java.util.TimerTask; 12123b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 12223b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 1234a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal/** 124161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * This is an abstract implementation of the Activity Controller. This class 125161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * knows how to respond to menu items, state changes, layout changes, etc. It 126161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * weaves together the views and listeners, dispatching actions to the 127161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * respective underlying classes. 128161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * <p> 129161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * Even though this class is abstract, it should provide default implementations 130161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * for most, if not all the methods in the ActivityController interface. This 131161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * makes the task of the subclasses easier: OnePaneActivityController and 132161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * TwoPaneActivityController can be concise when the common functionality is in 133161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * AbstractActivityController. 134161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * </p> 135a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * <p> 136161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * In the Gmail codebase, this was called BaseActivityController 137161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * </p> 1384a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal */ 139ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sappersteinpublic abstract class AbstractActivityController implements ActivityController, 1405d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux EmptyFolderDialogFragment.EmptyFolderDialogFragmentListener, View.OnClickListener { 1411ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal // Keys for serialization of various information in Bundles. 142cabd3f227bf97159774e246ad278bb49d4aa2badVikram Aggarwal /** Tag for {@link #mAccount} */ 1436c51158ad3269f157424e6c7bd488425c98da08fVikram Aggarwal private static final String SAVED_ACCOUNT = "saved-account"; 144cabd3f227bf97159774e246ad278bb49d4aa2badVikram Aggarwal /** Tag for {@link #mFolder} */ 1455e478d2c4087b50764756b0edc95941cb6094f68Mindy Pereira private static final String SAVED_FOLDER = "saved-folder"; 146cabd3f227bf97159774e246ad278bb49d4aa2badVikram Aggarwal /** Tag for {@link #mCurrentConversation} */ 14726f23fc8cc0d49bc0bea1eeec4c0c4742928f693Mindy Pereira private static final String SAVED_CONVERSATION = "saved-conversation"; 148cabd3f227bf97159774e246ad278bb49d4aa2badVikram Aggarwal /** Tag for {@link #mSelectedSet} */ 149cabd3f227bf97159774e246ad278bb49d4aa2badVikram Aggarwal private static final String SAVED_SELECTED_SET = "saved-selected-set"; 150649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal /** Tag for {@link ActionableToastBar#getOperation()} */ 151d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira private static final String SAVED_TOAST_BAR_OP = "saved-toast-bar-op"; 152649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal /** Tag for {@link #mFolderListFolder} */ 153649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal private static final String SAVED_HIERARCHICAL_FOLDER = "saved-hierarchical-folder"; 154f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal /** Tag for {@link ConversationListContext#searchQuery} */ 155f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal private static final String SAVED_QUERY = "saved-query"; 1566cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal /** Tag for {@link #mDialogAction} */ 1576cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal private static final String SAVED_ACTION = "saved-action"; 158b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal /** Tag for {@link #mDialogFromSelectedSet} */ 159b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal private static final String SAVED_ACTION_FROM_SELECTED = "saved-action-from-selected"; 160a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal /** Tag for {@link #mDetachedConvUri} */ 161a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal private static final String SAVED_DETACHED_CONV_URI = "saved-detached-conv-uri"; 162ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang /** Key to store {@link #mInbox}. */ 163f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy private static final String SAVED_INBOX_KEY = "m-inbox"; 164f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy /** Key to store {@link #mConversationListScrollPositions} */ 165f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy private static final String SAVED_CONVERSATION_LIST_SCROLL_POSITIONS = 166f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy "saved-conversation-list-scroll-positions"; 1675cb0c3e684150d6d8ed4d9df4fb73a7606086aaaMindy Pereira 168ede2e52e725abc625ae963f979639ff8ecc40cf5Greg Bullock /** Tag used when loading a wait fragment */ 1696902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal protected static final String TAG_WAIT = "wait-fragment"; 1706902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal /** Tag used when loading a conversation list fragment. */ 171bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook public static final String TAG_CONVERSATION_LIST = "tag-conversation-list"; 172103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy /** Tag used when loading a custom fragment. */ 173103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy protected static final String TAG_CUSTOM_FRAGMENT = "tag-custom-fragment"; 1746902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal 175a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal /** Key to store an account in a bundle */ 176a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal private final String BUNDLE_ACCOUNT_KEY = "account"; 177a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal /** Key to store a folder in a bundle */ 178a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal private final String BUNDLE_FOLDER_KEY = "folder"; 1795bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein /** 1805bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein * Key to set a flag for the ConversationCursorLoader to ignore any 1815bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein * initial load limit that may be set by the Account. Instead, 1825bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein * perform a full load instead of the full-stage load. 1835bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein */ 1845bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein private final String BUNDLE_IGNORE_INITIAL_CONVERSATION_LIMIT_KEY = 1855bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein "ignore-initial-conversation-limit"; 186a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal 187d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal protected Account mAccount; 18812a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira protected Folder mFolder; 189ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang protected Folder mInbox; 19069b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal /** True when {@link #mFolder} is first shown to the user. */ 19169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal private boolean mFolderChanged = false; 1922d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein protected ActionBarController mActionBarController; 19310fcd645f703799326da326630b663df69f91508James Lemieux protected final MailActivity mActivity; 194a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal protected final Context mContext; 1956902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal private final FragmentManager mFragmentManager; 196ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal protected final RecentFolderList mRecentFolderList; 19780aeac5356b5a14a5ef2aff8f0f72a464c9a3cb4Vikram Aggarwal protected ConversationListContext mConvListContext; 1989b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira protected Conversation mCurrentConversation; 199a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal /** 200a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal * The hash of {@link #mCurrentConversation} in detached mode. 0 if we are not in detached mode. 201a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal */ 202a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal private Uri mDetachedConvUri; 203d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal 204f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy /** A map of {@link Folder} {@link Uri} to scroll position in the conversation list. */ 205f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy private final Bundle mConversationListScrollPositions = new Bundle(); 206f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy 2076ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook /** A {@link android.content.BroadcastReceiver} that suppresses new e-mail notifications. */ 2086ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook private SuppressNotificationReceiver mNewEmailReceiver = null; 2096ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook 21059f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal /** Handler for all our local runnables. */ 211fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira protected Handler mHandler = new Handler(); 212fa995b4bbccd0e650ef48878107ede5e53dd8309Mindy Pereira 213fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal /** 214161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * The current mode of the application. All changes in mode are initiated by 215161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * the activity controller. View mode changes are propagated to classes that 216161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * attach themselves as listeners of view mode changes. 217fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal */ 2181ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal protected final ViewMode mViewMode; 21980aeac5356b5a14a5ef2aff8f0f72a464c9a3cb4Vikram Aggarwal protected ContentResolver mResolver; 220c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal protected boolean mHaveAccountList = false; 221b7b33e07325fc6664d8ab803b141b87adaa2d013Mindy Pereira private AsyncRefreshTask mAsyncRefreshTask; 2225cb0c3e684150d6d8ed4d9df4fb73a7606086aaaMindy Pereira 2234e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang private boolean mDestroyed; 2244e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang 225bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal /** True if running on tablet */ 226bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal private final boolean mIsTablet; 227bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal 2281ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang /** 2291ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * Are we in a point in the Activity/Fragment lifecycle where it's safe to execute fragment 2301ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * transactions? (including back stack manipulation) 2311ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * <p> 2321ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * Per docs in {@link FragmentManager#beginTransaction()}, this flag starts out true, switches 2331ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * to false after {@link Activity#onSaveInstanceState}, and becomes true again in both onStart 2341ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * and onResume. 2351ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang */ 2361ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang private boolean mSafeToModifyFragments = true; 2371ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 23823b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook private final Set<Uri> mCurrentAccountUris = Sets.newHashSet(); 239967ede63e059810d9d4d425c50111d606014c893Mindy Pereira protected ConversationCursor mConversationListCursor; 24061f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private final DataSetObservable mConversationListObservable = new MailObservable("List"); 241bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 24259f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal /** Runnable that checks the logging level to enable/disable the logging service. */ 24359f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal private Runnable mLogServiceChecker = null; 244de60c9d0ad164a5daf358181a05bbd43edd5d5edVikram Aggarwal /** List of all accounts currently known to the controller. This is never null. */ 245de60c9d0ad164a5daf358181a05bbd43edd5d5edVikram Aggarwal private Account[] mAllAccounts = new Account[0]; 24659f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal 24777ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal private FolderWatcher mFolderWatcher; 24877ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal 2495bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein private boolean mIgnoreInitialConversationLimit; 2505bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein 2517c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu /** 2527c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu * Interface for actions that are deferred until after a load completes. This is for handling 2537c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu * user actions which affect cursors (e.g. marking messages read or unread) that happen before 2547c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu * that cursor is loaded. 2557c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu */ 2567c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu private interface LoadFinishedCallback { 2577c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu void onLoadFinished(); 2587c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } 2597c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu 2607c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu /** The deferred actions to execute when mConversationListCursor load completes. */ 2617c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu private final ArrayList<LoadFinishedCallback> mConversationListLoadFinishedCallbacks = 2627c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu new ArrayList<LoadFinishedCallback>(); 2637c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu 264bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank private RefreshTimerTask mConversationListRefreshTask; 265e1d1b07cdb0026097eb80f6c2912a16353aacec1Marc Blank 2667c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal /** Listeners that are interested in changes to the current account. */ 26761f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private final DataSetObservable mAccountObservers = new MailObservable("Account"); 26858cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal /** Listeners that are interested in changes to the recent folders. */ 26961f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private final DataSetObservable mRecentFolderObservers = new MailObservable("RecentFolder"); 27007dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal /** Listeners that are interested in changes to the list of all accounts. */ 27161f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private final DataSetObservable mAllAccountObservers = new MailObservable("AllAccounts"); 27250ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal /** Listeners that are interested in changes to the current folder. */ 27361f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private final DataSetObservable mFolderObservable = new MailObservable("CurrentFolder"); 27454022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler /** Listeners that are interested in changes to the Folder or Account selection */ 27554022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler private final DataSetObservable mFolderOrAccountObservers = 27654022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler new MailObservable("FolderOrAccount"); 27758cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal 278967ede63e059810d9d4d425c50111d606014c893Mindy Pereira /** 279967ede63e059810d9d4d425c50111d606014c893Mindy Pereira * Selected conversations, if any. 280967ede63e059810d9d4d425c50111d606014c893Mindy Pereira */ 2814556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang private final ConversationSelectionSet mSelectedSet = new ConversationSelectionSet(); 282dac00547ce8d44a964e4510315168ee413e55a75Mindy Pereira 283c7a070f90a47ea658c36185c65ba8dcc7f2b09b9Paul Westbrook private final int mFolderItemUpdateDelayMs; 284c7a070f90a47ea658c36185c65ba8dcc7f2b09b9Paul Westbrook 285135fd02e74ea8449b36c3dc44cd796e06a7e714dVikram Aggarwal /** Keeps track of selected and unselected conversations */ 286937c94f025ed55c19bd46c7c077fa3575ab6be52Paul Westbrook final protected ConversationPositionTracker mTracker; 287af1ee0c4b6258530d8da30bcdb2a9cb403f70d5eVikram Aggarwal 288e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal /** 289e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal * Action menu associated with the selected set. 290e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal */ 291e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal SelectedConversationsActionMenu mCabActionMenu; 2921a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux 2931a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux /** The compose button floating over the conversation/search lists */ 2941a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux protected View mFloatingComposeButton; 295c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein protected ActionableToastBar mToastBar; 296632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang protected ConversationPagerController mPagerController; 297ab4863650794e81f35a0fd9abc16a5564d7b102bMindy Pereira 298d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal // This is split out from the general loader dispatcher because its loader doesn't return a 299b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang // basic Cursor 300d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal /** Handles loader callbacks to create a convesation cursor. */ 301b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang private final ConversationListLoaderCallbacks mListCursorCallbacks = 302b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang new ConversationListLoaderCallbacks(); 303b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang 304177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal /** Object that listens to all LoaderCallbacks that result in {@link Folder} creation. */ 305177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private final FolderLoads mFolderCallbacks = new FolderLoads(); 306177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal /** Object that listens to all LoaderCallbacks that result in {@link Account} creation. */ 307177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private final AccountLoads mAccountCallbacks = new AccountLoads(); 308177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 30969a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal /** 31069a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * Matched addresses that must be shielded from users because they are temporary. Even though 31169a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * this is instantiated from settings, this matcher is valid for all accounts, and is expected 31269a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * to live past the life of an account. 31369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal */ 31469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal private final VeiledAddressMatcher mVeiledMatcher; 31569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 316b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook protected static final String LOG_TAG = LogTag.getLogTag(); 317d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal 318aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal // Loader constants: Accounts 319aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 320aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The list of accounts. This loader is started early in the application life-cycle since 321aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * the list of accounts is central to all other data the application needs: unread counts for 322aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * folders, critical UI settings like show/hide checkboxes, ... 323aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The loader is started when the application is created: both in 324aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * {@link #onCreate(Bundle)} and in {@link #onActivityResult(int, int, Intent)}. It is never 325aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * destroyed since the cursor is needed through the life of the application. When the list of 326aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * accounts changes, we notify {@link #mAllAccountObservers}. 327aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 328fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal private static final int LOADER_ACCOUNT_CURSOR = 0; 329aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal 330aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 331aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The current account. This loader is started when we have an account. The mail application 332aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * <b>needs</b> a valid account to function. As soon as we set {@link #mAccount}, 333aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * we start a loader to observe for changes on the current account. 334aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The loader is always restarted when an account is set in {@link #setAccount(Account)}. 335aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * When the current account object changes, we notify {@link #mAccountObservers}. 336aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * A possible performance improvement would be to listen purely on 337aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * {@link #LOADER_ACCOUNT_CURSOR}. The current account is guaranteed to be in the list, 338aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * and would avoid two updates when a single setting on the current account changes. 339aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 340004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps private static final int LOADER_ACCOUNT_UPDATE_CURSOR = 1; 341004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 342004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps // Loader constants: Conversations 343004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 344004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps /** The conversation cursor over the current conversation list. This loader provides 345004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * a cursor over conversation entries from a folder to display a conversation 346004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * list. 347004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * This loader is started when the user switches folders (in {@link #updateFolder(Folder)}, 348004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * or when the controller is told that a folder/account change is imminent 349004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * (in {@link #preloadConvList(Account, Folder)}. The loader is maintained for the life of 350004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * the current folder. When the user switches folders, the old loader is destroyed and a new 351004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * one is created. 352004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * 353004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * When the conversation list changes, we notify {@link #mConversationListObservable}. 354004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps */ 355004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps private static final int LOADER_CONVERSATION_LIST = 10; 356004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 357004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps // Loader constants: misc 358004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps /** 359004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps * The loader that determines whether the Warm welcome tour should be displayed for the user. 360004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps */ 361004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps public static final int LOADER_WELCOME_TOUR = 20; 362d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal 363944ef3b09d15d28f13cf63e3410850e246b1d54fGreg Bullock /** 364944ef3b09d15d28f13cf63e3410850e246b1d54fGreg Bullock * The load which loads accounts for the welcome tour. 365944ef3b09d15d28f13cf63e3410850e246b1d54fGreg Bullock */ 366944ef3b09d15d28f13cf63e3410850e246b1d54fGreg Bullock public static final int LOADER_WELCOME_TOUR_ACCOUNTS = 21; 367944ef3b09d15d28f13cf63e3410850e246b1d54fGreg Bullock 368aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal // Loader constants: Folders 369004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 370aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** The current folder. This loader watches for updates to the current folder in a manner 371aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * analogous to the {@link #LOADER_ACCOUNT_UPDATE_CURSOR}. Updates to the current folder 372aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * might be due to server-side changes (unread count), or local changes (sync window or sync 373aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * status change). 374aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The change of current folder calls {@link #updateFolder(Folder)}. 375aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * This is responsible for restarting a loader using the URI of the provided folder. When the 376aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * loader returns, the current folder is updated and consumers, if any, are notified. 377aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * When the current folder changes, we notify {@link #mFolderObservable} 378aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 379004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps private static final int LOADER_FOLDER_CURSOR = 30; 380004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 381aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 382aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The list of recent folders. Recent folders are shown in the DrawerFragment. The recent 383aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * folders are tied to the current account being viewed. When the account is changed, 384aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * we restart this loader to retrieve the recent accounts. Recents are pre-populated for 385aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * phones historically, when they were displayed in the spinner. On the tablet, 386aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * they showed in the {@link FolderListFragment} and were not-populated. The code to 387aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * pre-populate the recents is somewhat convoluted: when the loader returns a short list of 388aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * recent folders, it issues an update on the Recent Folder URI. The underlying provider then 389aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * does the appropriate thing to populate recent folders, and notify of a change on the cursor. 390aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * Recent folders are needed for the life of the current account. 391aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * When the recent folders change, we notify {@link #mRecentFolderObservers}. 392aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 393004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps private static final int LOADER_RECENT_FOLDERS = 31; 394aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 395aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The primary inbox for the current account. The mechanism to load the default inbox for the 396aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * current account is (sadly) different from loading other folders. The method 397aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * {@link #loadAccountInbox()} is called, and it restarts this loader. When the loader returns 398aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * a valid cursor, we create a folder, call {@link #onFolderChanged{Folder)} eventually 399aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * calling {@link #updateFolder(Folder)} which starts a loader {@link #LOADER_FOLDER_CURSOR} 400aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * over the current folder. 401aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * When we have a valid cursor, we destroy this loader, This convoluted flow is historical. 402aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 403004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps private static final int LOADER_ACCOUNT_INBOX = 32; 404004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 405aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 406aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The fake folder of search results for a term. When we search for a term, 407aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * a new activity is created with {@link Intent#ACTION_SEARCH}. For this new activity, 408aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * we start a loader which returns conversations that match the user-provided query. 409aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * We destroy the loader when we obtain a valid cursor since subsequent searches will create 410aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * a new activity. 411aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 412004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps private static final int LOADER_SEARCH = 33; 413aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 414aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * The initial folder at app start. When the application is launched from an intent that 415aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * specifies the initial folder (notifications/widgets/shortcuts), 416aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * then we extract the folder URI from the intent, but we cannot trust the folder object. Since 417aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * shortcuts and widgets persist past application update, they might have incorrect 418aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * information encoded in them. So, to obtain a {@link Folder} object from a {@link Uri}, 419aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * we need to start another loader. Upon obtaining a valid cursor, the loader is destroyed. 420aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * An additional complication arises if we have to view a specific conversation within this 421aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * folder. This is the case when launching the app from a single conversation notification 422aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * or tapping on a specific conversation in the widget. In these cases, the conversation is 423aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * saved in {@link #mConversationToShow} and is retrieved when the loader returns. 424aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 425004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps public static final int LOADER_FIRST_FOLDER = 34; 426de21e898901a86acdcf62ea46d358184bfd063b3Régis Décamps 427de21e898901a86acdcf62ea46d358184bfd063b3Régis Décamps /** 4287a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * Guaranteed to be the last loader ID used by the activity. Loaders are owned by Activity or 4297a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * fragments, and within an activity, loader IDs need to be unique. A hack to ensure that the 4307a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * {@link FolderWatcher} can create its folder loaders without clashing with the IDs of those 4317a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * of the {@link AbstractActivityController}. Currently, the {@link FolderWatcher} is the only 4327a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * other class that uses this activity's LoaderManager. If another class needs activity-level 4337a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * loaders, consider consolidating the loaders in a central location: a UI-less fragment 4347a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * perhaps. 4357a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal */ 436004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps public static final int LAST_LOADER_ID = 35; 437004b46f0fe9945d349c7a11126ed6aab0095c272Régis Décamps 4387c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy /** 4397c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy * Guaranteed to be the last loader ID used by the Fragment. Loaders are owned by Activity or 4407c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy * fragments, and within an activity, loader IDs need to be unique. Currently, 4412d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein * SectionedInboxTeaserView is the only class that uses the 4427c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy * {@link ConversationListFragment}'s LoaderManager. 4437c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy */ 4447c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy public static final int LAST_FRAGMENT_LOADER_ID = 1000; 4454a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal 4466aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal /** Code returned after an account has been added. */ 4472388c5d208acd4e4e658aaacbbc5f080ee8e9f7cPaul Westbrook private static final int ADD_ACCOUNT_REQUEST_CODE = 1; 4486aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal /** Code returned when the user has to enter the new password on an existing account. */ 449122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook private static final int REAUTHENTICATE_REQUEST_CODE = 2; 450371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon /** Code returned when the previous activity needs to navigate to a different folder 451371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon * or account */ 452371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon private static final int CHANGE_NAVIGATION_REQUEST_CODE = 3; 453371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon 454371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon public static final String EXTRA_FOLDER = "extra-folder"; 455371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon public static final String EXTRA_ACCOUNT = "extra-account"; 4562388c5d208acd4e4e658aaacbbc5f080ee8e9f7cPaul Westbrook 457e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal /** The pending destructive action to be carried out before swapping the conversation cursor.*/ 458e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal private DestructiveAction mPendingDestruction; 459c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein protected AsyncRefreshTask mFolderSyncTask; 460c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira private Folder mFolderListFolder; 4615390fcabb7baf683fc14bd68d8612913dac70a81mindyp private boolean mIsDragHappening; 462e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon private final int mShowUndoBarDelay; 4636f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp private boolean mRecentsDataUpdated; 464a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal /** A wait fragment we added, if any. */ 465a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal private WaitFragment mWaitFragment; 466f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal /** True if we have results from a search query */ 467f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal private boolean mHaveSearchResults = false; 4686cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal /** If a confirmation dialog is being show, the listener for the positive action. */ 4696cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal private OnClickListener mDialogListener; 4706cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal /** 4716cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal * If a confirmation dialog is being show, the resource of the action: R.id.delete, etc. This 4726cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal * is used to create a new {@link #mDialogListener} on orientation changes. 4736cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal */ 4746cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal private int mDialogAction = -1; 475b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal /** 476b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal * If a confirmation dialog is being shown, this is true if the dialog acts on the selected set 477b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal * and false if it acts on the currently selected conversation 478b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal */ 479b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal private boolean mDialogFromSelectedSet; 4806cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal 481177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal /** Which conversation to show, if started from widget/notification. */ 482177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private Conversation mConversationToShow = null; 483177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 484c94d07f4460d00db898237603de311d226707a96Andy Huang /** 485c94d07f4460d00db898237603de311d226707a96Andy Huang * A temporary reference to the pending destructive action that was deferred due to an 486c94d07f4460d00db898237603de311d226707a96Andy Huang * auto-advance transition in progress. 487c94d07f4460d00db898237603de311d226707a96Andy Huang * <p> 488c94d07f4460d00db898237603de311d226707a96Andy Huang * In detail: when auto-advance triggers a mode change, we must wait until the transition 489c94d07f4460d00db898237603de311d226707a96Andy Huang * completes before executing the destructive action to ensure a smooth mode change transition. 490c94d07f4460d00db898237603de311d226707a96Andy Huang * This member variable houses the pending destructive action work to be run upon completion. 491c94d07f4460d00db898237603de311d226707a96Andy Huang */ 492c94d07f4460d00db898237603de311d226707a96Andy Huang private Runnable mAutoAdvanceOp = null; 493c94d07f4460d00db898237603de311d226707a96Andy Huang 49412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang protected DrawerLayout mDrawerContainer; 49512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang protected View mDrawerPullout; 49612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang protected ActionBarDrawerToggle mDrawerToggle; 497f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang 49812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang protected ListView mListViewForAnimating; 49912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang protected boolean mHasNewAccountOrFolder; 500a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein private boolean mConversationListLoadFinishedIgnored; 50161f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private final MailDrawerListener mDrawerListener = new MailDrawerListener(); 5025747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein private boolean mHideMenuItems; 50312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 504144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang private final DrawIdler mDrawIdler = new DrawIdler(); 505144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang 50600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein public static final String SYNC_ERROR_DIALOG_FRAGMENT_TAG = "SyncErrorDialogFragment"; 507e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal 508cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy private final DataSetObserver mUndoNotificationObserver = new DataSetObserver() { 509cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy @Override 510cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy public void onChanged() { 511cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy super.onChanged(); 512cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy 513cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy if (mConversationListCursor != null) { 514cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy mConversationListCursor.handleNotificationActions(); 515cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy } 516cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy } 517cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy }; 518cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy 51953de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein private final HomeButtonListener mHomeButtonListener = new HomeButtonListener(); 52053de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein 521a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal public AbstractActivityController(MailActivity activity, ViewMode viewMode) { 522a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal mActivity = activity; 5236902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal mFragmentManager = mActivity.getFragmentManager(); 524a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal mViewMode = viewMode; 525a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal mContext = activity.getApplicationContext(); 526025eba8bfd4d0b5e248b6de0bda6f1129170fb41Vikram Aggarwal mRecentFolderList = new RecentFolderList(mContext); 527937c94f025ed55c19bd46c7c077fa3575ab6be52Paul Westbrook mTracker = new ConversationPositionTracker(this); 528967ede63e059810d9d4d425c50111d606014c893Mindy Pereira // Allow the fragment to observe changes to its own selection set. No other object is 529967ede63e059810d9d4d425c50111d606014c893Mindy Pereira // aware of the selected set. 530967ede63e059810d9d4d425c50111d606014c893Mindy Pereira mSelectedSet.addObserver(this); 531c7a070f90a47ea658c36185c65ba8dcc7f2b09b9Paul Westbrook 532bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal final Resources r = mContext.getResources(); 533bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal mFolderItemUpdateDelayMs = r.getInteger(R.integer.folder_item_refresh_delay_ms); 534bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal mShowUndoBarDelay = r.getInteger(R.integer.show_undo_bar_delay_ms); 53569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal mVeiledMatcher = VeiledAddressMatcher.newInstance(activity.getResources()); 536bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal mIsTablet = Utils.useTabletUI(r); 537a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mConversationListLoadFinishedIgnored = false; 5384a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal } 5394a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal 5404a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal @Override 541e9a81035bcef5a372fa13a992f8553eb60e6aaf0Vikram Aggarwal public Account getCurrentAccount() { 542e9a81035bcef5a372fa13a992f8553eb60e6aaf0Vikram Aggarwal return mAccount; 5434a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal } 5444a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal 5454a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal @Override 5461ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public ConversationListContext getCurrentListContext() { 547e9a81035bcef5a372fa13a992f8553eb60e6aaf0Vikram Aggarwal return mConvListContext; 5484a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal } 5494a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal 550a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 551ef7c992d8cb462be6da34d42965cf185f3bb1b22Vikram Aggarwal public final ConversationCursor getConversationListCursor() { 552967ede63e059810d9d4d425c50111d606014c893Mindy Pereira return mConversationListCursor; 553967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 554967ede63e059810d9d4d425c50111d606014c893Mindy Pereira 5556902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal /** 55634a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal * Check if the fragment is attached to an activity and has a root view. 557715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param in fragment to be checked 55834a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal * @return true if the fragment is valid, false otherwise 55934a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal */ 560715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private static boolean isValidFragment(Fragment in) { 561715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal return !(in == null || in.getActivity() == null || in.getView() == null); 56234a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal } 56334a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal 56434a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal /** 56549e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * Get the conversation list fragment for this activity. If the conversation list fragment is 56649e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * not attached, this method returns null. 567839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang * 56849e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * Caution! This method returns the {@link ConversationListFragment} after the fragment has been 56949e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * added, <b>and</b> after the {@link FragmentManager} has run through its queue to add the 57049e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * fragment. There is a non-trivial amount of time after the fragment is instantiated and before 57149e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * this call returns a non-null value, depending on the {@link FragmentManager}. If you 57249e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * need the fragment immediately after adding it, consider making the fragment an observer of 57349e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * the controller and perform the task immediately on {@link Fragment#onActivityCreated(Bundle)} 5746902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal */ 5756902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal protected ConversationListFragment getConversationListFragment() { 5766902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal final Fragment fragment = mFragmentManager.findFragmentByTag(TAG_CONVERSATION_LIST); 57734a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal if (isValidFragment(fragment)) { 57834a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal return (ConversationListFragment) fragment; 5799585d7810519b7e5475d9c7458e7a8a9c12fd024Andy Huang } 58034a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal return null; 5816902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal } 5826902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal 5836902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal /** 5846902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal * Returns the folder list fragment attached with this activity. If no such fragment is attached 5856902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal * this method returns null. 586839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang * 58749e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * Caution! This method returns the {@link FolderListFragment} after the fragment has been 58849e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * added, <b>and</b> after the {@link FragmentManager} has run through its queue to add the 58949e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * fragment. There is a non-trivial amount of time after the fragment is instantiated and before 59049e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * this call returns a non-null value, depending on the {@link FragmentManager}. If you 59149e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * need the fragment immediately after adding it, consider making the fragment an observer of 59249e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * the controller and perform the task immediately on {@link Fragment#onActivityCreated(Bundle)} 5936902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal */ 5946902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal protected FolderListFragment getFolderListFragment() { 59510fcd645f703799326da326630b663df69f91508James Lemieux final String drawerPulloutTag = mActivity.getString(R.string.drawer_pullout_tag); 59610fcd645f703799326da326630b663df69f91508James Lemieux final Fragment fragment = mFragmentManager.findFragmentByTag(drawerPulloutTag); 59734a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal if (isValidFragment(fragment)) { 59834a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal return (FolderListFragment) fragment; 5999585d7810519b7e5475d9c7458e7a8a9c12fd024Andy Huang } 60034a650154646f550435b7976d2ac6fc74c21234fVikram Aggarwal return null; 6016902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal } 6026902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal 6031ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal /** 604161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * Initialize the action bar. This is not visible to OnePaneController and 605161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * TwoPaneController so they cannot override this behavior. 6061ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal */ 607abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal private void initializeActionBar() { 60852882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein final ActionBar actionBar = mActivity.getSupportActionBar(); 6095895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang if (actionBar == null) { 6105895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang return; 611abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal } 6125895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang 61382faec7ee6cfc4e68fdfe7658d38dfeb5c9c1843Mindy Pereira final boolean isSearch = mActivity.getIntent() != null 61482faec7ee6cfc4e68fdfe7658d38dfeb5c9c1843Mindy Pereira && Intent.ACTION_SEARCH.equals(mActivity.getIntent().getAction()); 6152d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController = isSearch ? 6162d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein new SearchActionBarController(mContext) : 6172d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein new ActionBarController(mContext); 6182d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.initialize(mActivity, this, actionBar); 6191dd054f4e5581b69a52936c9d257fa91cb6daee7Rohan Shah 62012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // init the action bar to allow the 'up' affordance. 62112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // any configurations that disallow 'up' should do that later. 6222d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.setBackButton(); 623abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal } 624abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal 625abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal /** 626abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal * Attach the action bar to the activity. 627abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal */ 628abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal private void attachActionBar() { 62952882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein final ActionBar actionBar = mActivity.getSupportActionBar(); 630bd09150070b1aa25ebdd9af0a29e8bf9fbbf7af8Tony Mantler if (actionBar != null) { 6312d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein // Show a title 6322d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein final int mask = ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME; 633bc462cadc2dcd11d27e7810e437aeef1505f4cb2Vikram Aggarwal actionBar.setDisplayOptions(mask, mask); 6342d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.setViewModeController(mViewMode); 6351ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 636a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 637a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 638a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal /** 639161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * Returns whether the conversation list fragment is visible or not. 640161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * Different layouts will have their own notion on the visibility of 641161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * fragments, so this method needs to be overriden. 642161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * 643a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal */ 6441ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal protected abstract boolean isConversationListVisible(); 6451ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 646eb7d329e448eb42195f7c35b978035766b6f46e1Vikram Aggarwal /** 64734f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal * If required, starts wait mode for the current account. 64834f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal */ 64934f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal final void perhapsEnterWaitMode() { 65034f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal // If the account is not initialized, then show the wait fragment, since nothing can be 65134f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal // shown. 65234f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal if (mAccount.isAccountInitializationRequired()) { 65334f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal showWaitForInitialization(); 65434f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal return; 65534f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal } 65634f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal 65734f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal final boolean inWaitingMode = inWaitMode(); 65834f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal final boolean isSyncRequired = mAccount.isAccountSyncRequired(); 65934f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal if (isSyncRequired) { 66034f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal if (inWaitingMode) { 66134f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal // Update the WaitFragment's account object 66234f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal updateWaitMode(); 66334f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal } else { 66434f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal // Transition to waiting mode 66534f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal showWaitForInitialization(); 66634f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal } 66734f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal } else if (inWaitingMode) { 66834f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal // Dismiss waiting mode 66934f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal hideWaitForInitialization(); 67034f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal } 67134f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal } 67234f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal 673eb7d329e448eb42195f7c35b978035766b6f46e1Vikram Aggarwal @Override 6744cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein public void switchToDefaultInboxOrChangeAccount(Account account) { 6754cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein LogUtils.d(LOG_TAG, "AAC.switchToDefaultAccount(%s)", account); 676e764cfd130c4f92ae823fd1f361ab70439e8ec95Andy Huang if (mViewMode.isSearchMode()) { 677371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // We are in an activity on top of the main navigation activity. 678371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // We need to return to it with a result code that indicates it should navigate to 679371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // a different folder. 680371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon final Intent intent = new Intent(); 681371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon intent.putExtra(AbstractActivityController.EXTRA_ACCOUNT, account); 682371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon mActivity.setResult(Activity.RESULT_OK, intent); 683371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon mActivity.finish(); 684371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon return; 685371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon } 68666bc6ed16956963cb18660d15ea7e6adc6c62411Vikram Aggarwal final boolean firstLoad = mAccount == null; 687252684a1ddaf00119d8f2440e5d4cd93c77e5298Andrew Sapperstein final boolean switchToDefaultInbox = !firstLoad && account.uri.equals(mAccount.uri); 688d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal // If the active account has been clicked in the drawer, go to default inbox 689252684a1ddaf00119d8f2440e5d4cd93c77e5298Andrew Sapperstein if (switchToDefaultInbox) { 690252684a1ddaf00119d8f2440e5d4cd93c77e5298Andrew Sapperstein loadAccountInbox(); 691252684a1ddaf00119d8f2440e5d4cd93c77e5298Andrew Sapperstein return; 692252684a1ddaf00119d8f2440e5d4cd93c77e5298Andrew Sapperstein } 6934cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein changeAccount(account); 6944cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein } 6954cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein 6964cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein public void changeAccount(Account account) { 6974cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein LogUtils.d(LOG_TAG, "AAC.changeAccount(%s)", account); 6984cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein // Is the account or account settings different from the existing account? 6994cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein final boolean firstLoad = mAccount == null; 7004cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein final boolean accountChanged = firstLoad || !account.uri.equals(mAccount.uri); 7014cbb0da3cd701ee0c06237ded965648d68c663c8Andrew Sapperstein 702472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal // If nothing has changed, return early without wasting any more time. 703472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal if (!accountChanged && !account.settingsDiffer(mAccount)) { 704472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal return; 705472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal } 706472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal // We also don't want to do anything if the new account is null 707472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal if (account == null) { 7085fd8afd5c1b40580c069a5a97039ca0601208216Vikram Aggarwal LogUtils.e(LOG_TAG, "AAC.changeAccount(null) called."); 709472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal return; 710472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal } 71179b1156803585952a4851221dc9fa9974e606433Tony Mantler final String emailAddress = account.getEmailAddress(); 712472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal mHandler.post(new Runnable() { 713472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal @Override 714472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal public void run() { 71579b1156803585952a4851221dc9fa9974e606433Tony Mantler MailActivity.setNfcMessage(emailAddress); 716c6adce3cf6887c4c6dd5005724565702751843d0mindyp } 717472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal }); 718472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal if (accountChanged) { 719472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal commitDestructiveActions(false); 720472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal } 721761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang Analytics.getInstance().setCustomDimension(Analytics.CD_INDEX_ACCOUNT_TYPE, 72279b1156803585952a4851221dc9fa9974e606433Tony Mantler AnalyticsUtils.getAccountTypeForAccount(emailAddress)); 723472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal // Change the account here 724472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal setAccount(account); 725472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal // And carry out associated actions. 726472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal cancelRefreshTask(); 727472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal if (accountChanged) { 728472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal loadAccountInbox(); 729472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal } 730472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal // Check if we need to force setting up an account before proceeding. 731472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal if (mAccount != null && !Uri.EMPTY.equals(mAccount.settings.setupIntentUri)) { 732472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal // Launch the intent! 733472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal final Intent intent = new Intent(Intent.ACTION_EDIT); 734ec6e2516037e7172202e208b2015d7684a78eddbTony Mantler 735ec6e2516037e7172202e208b2015d7684a78eddbTony Mantler intent.setPackage(mContext.getPackageName()); 736472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal intent.setData(mAccount.settings.setupIntentUri); 737ec6e2516037e7172202e208b2015d7684a78eddbTony Mantler 738472e53693c6f6c1af335a2286f30e8dfbc2499e1Vikram Aggarwal mActivity.startActivity(intent); 73928d5f72e0ad0db75b6243ee8125bfe3aadbdcb85Mindy Pereira } 740a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 741a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 742e6340bc7f2bb9868e5014a101ea69b777d7b6750Vikram Aggarwal /** 7437c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal * Adds a listener interested in change in the current account. If a class is storing a 7447c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal * reference to the current account, it should listen on changes, so it can receive updates to 7457c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal * settings. Must happen in the UI thread. 7467d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal */ 7477c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal @Override 7487c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal public void registerAccountObserver(DataSetObserver obs) { 7497c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal mAccountObservers.registerObserver(obs); 7507d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal } 7517d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal 7527d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal /** 7537c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal * Removes a listener from receiving current account changes. 7547d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal * Must happen in the UI thread. 7557d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal */ 7567c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal @Override 7577c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal public void unregisterAccountObserver(DataSetObserver obs) { 7587c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal mAccountObservers.unregisterObserver(obs); 7597d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal } 7607d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal 7617c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal @Override 76207dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal public void registerAllAccountObserver(DataSetObserver observer) { 76307dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal mAllAccountObservers.registerObserver(observer); 76407dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal } 76507dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal 76607dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal @Override 76707dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal public void unregisterAllAccountObserver(DataSetObserver observer) { 76807dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal mAllAccountObservers.unregisterObserver(observer); 76907dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal } 77007dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal 77107dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal @Override 77207dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal public Account[] getAllAccounts() { 77307dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal return mAllAccounts; 77407dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal } 77507dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal 77607dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal @Override 7777c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal public Account getAccount() { 7787c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal return mAccount; 7797d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal } 7807d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal 7810f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah @Override 78254022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler public void registerFolderOrAccountChangedObserver(final DataSetObserver observer) { 78354022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler mFolderOrAccountObservers.registerObserver(observer); 7840f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah } 7850f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah 7860f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah @Override 78754022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler public void unregisterFolderOrAccountChangedObserver(final DataSetObserver observer) { 78854022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler mFolderOrAccountObservers.unregisterObserver(observer); 7890f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah } 7900f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah 7910f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah /** 79212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * If the drawer is open, the function locks the drawer to the closed, thereby sliding in 79312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * the drawer to the left edge, disabling events, and refreshing it once it's either closed 79412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * or put in an idle state. 7950f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah */ 7960f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah @Override 797a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal public void closeDrawer(final boolean hasNewFolderOrAccount, Account nextAccount, 798a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal Folder nextFolder) { 79912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (!isDrawerEnabled()) { 80054022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler if (hasNewFolderOrAccount) { 80154022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler mFolderOrAccountObservers.notifyChanged(); 80254022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler } 80312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang return; 80412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 80512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // If there are no new folders or accounts to switch to, just close the drawer 80612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (!hasNewFolderOrAccount) { 80712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.closeDrawers(); 80812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang return; 80912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 8102f9d394867be45302bb4323da7cacf193da38f39Vikram Aggarwal // Otherwise, start preloading the conversation list for the new folder. 8112f9d394867be45302bb4323da7cacf193da38f39Vikram Aggarwal if (nextFolder != null) { 8122f9d394867be45302bb4323da7cacf193da38f39Vikram Aggarwal preloadConvList(nextAccount, nextFolder); 8132f9d394867be45302bb4323da7cacf193da38f39Vikram Aggarwal } 8142f9d394867be45302bb4323da7cacf193da38f39Vikram Aggarwal // Remember if the conversation list view is animating 81512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang final ConversationListFragment conversationList = getConversationListFragment(); 81612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (conversationList != null) { 81712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mListViewForAnimating = conversationList.getListView(); 81812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } else { 81912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // There is no conversation list to animate, so just set it to null 82012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mListViewForAnimating = null; 82112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 82212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 82312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (mDrawerContainer.isDrawerOpen(mDrawerPullout)) { 82412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // Lets the drawer listener update the drawer contents and notify the FolderListFragment 82512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mHasNewAccountOrFolder = true; 82612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); 82712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } else { 82812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // Drawer is already closed, notify observers that is the case. 82954022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler if (hasNewFolderOrAccount) { 83054022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler mFolderOrAccountObservers.notifyChanged(); 83154022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler } 83212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 8330f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah } 8340f73d905c5e935a5280f8eb647cc924c2854b7deRohan Shah 835a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal /** 836aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * Load the conversation list early for the given folder. This happens when some UI element 837aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * (usually the drawer) instructs the controller that an account change or folder change is 838aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * imminent. While the UI element is animating, the controller can preload the conversation 839aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * list for the default inbox of the account provided here or to the folder provided here. 840aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * 841aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * @param nextAccount The account which the app will switch to shortly, possibly null. 842aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * @param nextFolder The folder which the app will switch to shortly, possibly null. 843a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal */ 844a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal protected void preloadConvList(Account nextAccount, Folder nextFolder) { 845a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal // Fire off the conversation list loader for this account already with a fake 846a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal // listener. 847e2be97a58fbae98b95e51735c6468d121e465355Paul Westbrook final Bundle args = new Bundle(2); 848a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal if (nextAccount != null) { 849a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal args.putParcelable(BUNDLE_ACCOUNT_KEY, nextAccount); 850a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal } else { 851a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal args.putParcelable(BUNDLE_ACCOUNT_KEY, mAccount); 852a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal } 853a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal if (nextFolder != null) { 854a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal args.putParcelable(BUNDLE_FOLDER_KEY, nextFolder); 8552dc850446320d6b56b89dda7fefc5113c6b7d8d1Vikram Aggarwal } else { 8562dc850446320d6b56b89dda7fefc5113c6b7d8d1Vikram Aggarwal LogUtils.e(LOG_TAG, new Error(), "AAC.preloadConvList(): Got an empty folder"); 857a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal } 858a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal mFolder = null; 859a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal final LoaderManager lm = mActivity.getLoaderManager(); 860a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal lm.destroyLoader(LOADER_CONVERSATION_LIST); 861a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal lm.initLoader(LOADER_CONVERSATION_LIST, args, mListCursorCallbacks); 862a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal } 863a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal 864aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal /** 865aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * Initiates the async request to create a fake search folder, which returns conversations that 866aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * match the query term provided by the user. Returns immediately. 867aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal * @param intent Intent that the app was started with. This intent contains the search query. 868aa941d7e107f7ce09838bd4daf295259d126dfa2Vikram Aggarwal */ 869e0828393e175c9293c86a7490225f324cbec5eefMindy Pereira private void fetchSearchFolder(Intent intent) { 870e2be97a58fbae98b95e51735c6468d121e465355Paul Westbrook final Bundle args = new Bundle(1); 871ab4863650794e81f35a0fd9abc16a5564d7b102bMindy Pereira args.putString(ConversationListContext.EXTRA_SEARCH_QUERY, intent 872e0828393e175c9293c86a7490225f324cbec5eefMindy Pereira .getStringExtra(ConversationListContext.EXTRA_SEARCH_QUERY)); 873177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getLoaderManager().restartLoader(LOADER_SEARCH, args, mFolderCallbacks); 874e0828393e175c9293c86a7490225f324cbec5eefMindy Pereira } 875e0828393e175c9293c86a7490225f324cbec5eefMindy Pereira 876a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 877ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang public void onFolderChanged(Folder folder, final boolean force) { 878f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang if (isDrawerEnabled()) { 879f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang /** If the folder doesn't exist, or its parent URI is empty, 880f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang * this is not a child folder */ 881f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang final boolean isTopLevel = Folder.isRoot(folder); 882f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang final int mode = mViewMode.getMode(); 883f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerToggle.setDrawerIndicatorEnabled( 884f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang getShouldShowDrawerIndicator(mode, isTopLevel)); 885f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); 886dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal 887f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerContainer.closeDrawers(); 888f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang } 8897dd0e1cec391fc2562795d6e6d9fc91ab36ca647Alice Yang 8907dd0e1cec391fc2562795d6e6d9fc91ab36ca647Alice Yang if (mFolder == null || !mFolder.equals(folder)) { 8917dd0e1cec391fc2562795d6e6d9fc91ab36ca647Alice Yang // We are actually changing the folder, so exit cab mode 8927dd0e1cec391fc2562795d6e6d9fc91ab36ca647Alice Yang exitCabMode(); 8937dd0e1cec391fc2562795d6e6d9fc91ab36ca647Alice Yang } 8947dd0e1cec391fc2562795d6e6d9fc91ab36ca647Alice Yang 895a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy final String query; 896a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy if (folder != null && folder.isType(FolderType.SEARCH)) { 897a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy query = mConvListContext.searchQuery; 898a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy } else { 899a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy query = null; 900a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy } 901a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy 902a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy changeFolder(folder, query, force); 903f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal } 904f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal 905f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal /** 906203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal * Sets the folder state without changing view mode and without creating a list fragment, if 907203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal * possible. 908715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param folder the folder whose list of conversations are to be shown 909715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param query the query string for a list of conversations matching a search 910203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal */ 911203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal private void setListContext(Folder folder, String query) { 912203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal updateFolder(folder); 913203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal if (query != null) { 914203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal mConvListContext = ConversationListContext.forSearchQuery(mAccount, mFolder, query); 915203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal } else { 916203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal mConvListContext = ConversationListContext.forFolder(mAccount, mFolder); 917203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal } 918203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal cancelRefreshTask(); 919203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal } 920203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal 921203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal /** 922f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal * Changes the folder to the value provided here. This causes the view mode to change. 923f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal * @param folder the folder to change to 924f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal * @param query if non-null, this represents the search string that the folder represents. 925ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang * @param force <code>true</code> to force a folder change, <code>false</code> to disallow 926ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang * changing to the current folder 927f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal */ 928ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang private void changeFolder(Folder folder, String query, final boolean force) { 929203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal if (!Objects.equal(mFolder, folder)) { 930203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal commitDestructiveActions(false); 931203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal } 932ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang if (folder != null && (!folder.equals(mFolder) || force) 933a1f99981919755e50f31fe300517d2fed752997eMindy Pereira || (mViewMode.getMode() != ViewMode.CONVERSATION_LIST)) { 934203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal setListContext(folder, query); 93528e0c34ad35925fc74633bec66344911f2de6a22Mindy Pereira showConversationList(mConvListContext); 93658ccd6952c0a5ed979e9cee1a3f6992b4040c732Vikram Aggarwal // Touch the current folder: it is different, and it has been accessed. 93758ccd6952c0a5ed979e9cee1a3f6992b4040c732Vikram Aggarwal mRecentFolderList.touchFolder(mFolder, mAccount); 93828e0c34ad35925fc74633bec66344911f2de6a22Mindy Pereira } 93993dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal resetActionBarIcon(); 940a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 941a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 94213c12a628bd4f1e52b9a4fc44a18b85bfdaeb88bMindy Pereira @Override 943505df5f59c92adbe8eaa734321c1d3f91be84a4aMindy Pereira public void onFolderSelected(Folder folder) { 944ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang onFolderChanged(folder, false /* force */); 94513c12a628bd4f1e52b9a4fc44a18b85bfdaeb88bMindy Pereira } 94613c12a628bd4f1e52b9a4fc44a18b85bfdaeb88bMindy Pereira 947792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal /** 94858cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal * Adds a listener interested in change in the recent folders. If a class is storing a 94958cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal * reference to the recent folders, it should listen on changes, so it can receive updates. 95058cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal * Must happen in the UI thread. 95158cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal */ 95258cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal @Override 95358cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal public void registerRecentFolderObserver(DataSetObserver obs) { 95458cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal mRecentFolderObservers.registerObserver(obs); 95558cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal } 95658cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal 95758cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal /** 95858cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal * Removes a listener from receiving recent folder changes. 95958cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal * Must happen in the UI thread. 96058cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal */ 96158cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal @Override 96258cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal public void unregisterRecentFolderObserver(DataSetObserver obs) { 96358cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal mRecentFolderObservers.unregisterObserver(obs); 96458cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal } 96558cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal 96658cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal @Override 96758cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal public RecentFolderList getRecentFolders() { 96858cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal return mRecentFolderList; 96958cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal } 97058cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal 971eb7d329e448eb42195f7c35b978035766b6f46e1Vikram Aggarwal @Override 972eb7d329e448eb42195f7c35b978035766b6f46e1Vikram Aggarwal public void loadAccountInbox() { 97377ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal boolean handled = false; 97477ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal if (mFolderWatcher != null) { 97577ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal final Folder inbox = mFolderWatcher.getDefaultInbox(mAccount); 97677ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal if (inbox != null) { 977ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang onFolderChanged(inbox, false /* force */); 97877ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal handled = true; 97977ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal } 98077ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal } 98177ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal if (!handled) { 9821bf20e01767d6864ef8ed196195cf7771dc2c45cPaul Westbrook LogUtils.d(LOG_TAG, "Starting a LOADER_ACCOUNT_INBOX for %s", mAccount); 98377ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal restartOptionalLoader(LOADER_ACCOUNT_INBOX, mFolderCallbacks, Bundle.EMPTY); 98477ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal } 9858cbf281d1676c21ced08c42da2aa9828cdadd87dVikram Aggarwal final int mode = mViewMode.getMode(); 9868cbf281d1676c21ced08c42da2aa9828cdadd87dVikram Aggarwal if (mode == ViewMode.UNKNOWN || mode == ViewMode.WAITING_FOR_ACCOUNT_INITIALIZATION) { 987e6459424b3e46d768865c908af1caa932f783095Andy Huang mViewMode.enterConversationListMode(); 988e6459424b3e46d768865c908af1caa932f783095Andy Huang } 989f6acdade010b2d0f49fd425b33e7f7b376286490Mindy Pereira } 990f6acdade010b2d0f49fd425b33e7f7b376286490Mindy Pereira 99177ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal @Override 99277ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal public void setFolderWatcher(FolderWatcher watcher) { 99377ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal mFolderWatcher = watcher; 99477ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal } 99577ee0ceaefaa9be699a20bfbe162f4c0ef83c6e1Vikram Aggarwal 99669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal /** 997d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal * Marks the {@link #mFolderChanged} value if the newFolder is different from the existing 998d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal * {@link #mFolder}. This should be called immediately <b>before</b> assigning newFolder to 999d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal * mFolder. 1000715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param newFolder the new folder we are switching to. 1001d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal */ 1002715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void setHasFolderChanged(final Folder newFolder) { 1003d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal // We should never try to assign a null folder. But in the rare event that we do, we should 1004d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal // only set the bit when we have a valid folder, and null is not valid. 1005d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal if (newFolder == null) { 1006d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal return; 1007d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal } 1008d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal // If the previous folder was null, or if the two folders represent different data, then we 1009d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal // consider that the folder has changed. 1010259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy if (mFolder == null || !newFolder.equals(mFolder)) { 1011d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal mFolderChanged = true; 1012d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal } 1013d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal } 1014d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal 1015d00229d30e3e24e0a40fb75e7500c15f5ff6138bVikram Aggarwal /** 101669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal * Sets the current folder if it is different from the object provided here. This method does 101769b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal * NOT notify the folder observers that a change has happened. Observers are notified when we 101869b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal * get an updated folder from the loaders, which will happen as a consequence of this method 101969b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal * (since this method starts/restarts the loaders). 102069b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal * @param folder The folder to assign 102169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal */ 102211e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira private void updateFolder(Folder folder) { 10231672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal if (folder == null || !folder.isInitialized()) { 10241672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal LogUtils.e(LOG_TAG, new Error(), "AAC.setFolder(%s): Bad input", folder); 10251672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal return; 10261672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal } 10271672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal if (folder.equals(mFolder)) { 10281672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal LogUtils.d(LOG_TAG, "AAC.setFolder(%s): Input matches mFolder", folder); 10291672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal return; 10301672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal } 10311672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal final boolean wasNull = mFolder == null; 10321672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal LogUtils.d(LOG_TAG, "AbstractActivityController.setFolder(%s)", folder.name); 10331672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal final LoaderManager lm = mActivity.getLoaderManager(); 10341672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // updateFolder is called from AAC.onLoadFinished() on folder changes. We need to 10351672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // ensure that the folder is different from the previous folder before marking the 10361672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // folder changed. 10371672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal setHasFolderChanged(folder); 10381672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal mFolder = folder; 10391672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal 10401672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // We do not need to notify folder observers yet. Instead we start the loaders and 10411672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // when the load finishes, we will get an updated folder. Then, we notify the 10421672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // folderObservers in onLoadFinished. 10432d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.setFolder(mFolder); 10441672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal 10451672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // Only when we switch from one folder to another do we want to restart the 10461672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // folder and conversation list loaders (to trigger onCreateLoader). 10471672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // The first time this runs when the activity is [re-]initialized, we want to re-use the 10481672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // previous loader's instance and data upon configuration change (e.g. rotation). 10491672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // If there was not already an instance of the loader, init it. 10501672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal if (lm.getLoader(LOADER_FOLDER_CURSOR) == null) { 1051177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal lm.initLoader(LOADER_FOLDER_CURSOR, Bundle.EMPTY, mFolderCallbacks); 10521672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal } else { 1053177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal lm.restartLoader(LOADER_FOLDER_CURSOR, Bundle.EMPTY, mFolderCallbacks); 10541672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal } 1055a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal if (!wasNull && lm.getLoader(LOADER_CONVERSATION_LIST) != null) { 1056a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal // If there was an existing folder AND we have changed 10571672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // folders, we want to restart the loader to get the information 10581672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal // for the newly selected folder 10591672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal lm.destroyLoader(LOADER_CONVERSATION_LIST); 10605cb0c3e684150d6d8ed4d9df4fb73a7606086aaaMindy Pereira } 1061e2be97a58fbae98b95e51735c6468d121e465355Paul Westbrook final Bundle args = new Bundle(2); 10622dc850446320d6b56b89dda7fefc5113c6b7d8d1Vikram Aggarwal args.putParcelable(BUNDLE_ACCOUNT_KEY, mAccount); 1063a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal args.putParcelable(BUNDLE_FOLDER_KEY, mFolder); 10645bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein args.putBoolean(BUNDLE_IGNORE_INITIAL_CONVERSATION_LIMIT_KEY, 10655bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein mIgnoreInitialConversationLimit); 10665bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein mIgnoreInitialConversationLimit = false; 1067a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal lm.initLoader(LOADER_CONVERSATION_LIST, args, mListCursorCallbacks); 10685cb0c3e684150d6d8ed4d9df4fb73a7606086aaaMindy Pereira } 10695cb0c3e684150d6d8ed4d9df4fb73a7606086aaaMindy Pereira 1070a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 1071090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang public Folder getFolder() { 1072090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang return mFolder; 1073090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 1074090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang 1075090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang @Override 1076c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira public Folder getHierarchyFolder() { 1077c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira return mFolderListFolder; 1078c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira } 1079c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira 1080c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira @Override 1081c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira public void setHierarchyFolder(Folder folder) { 1082c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira mFolderListFolder = folder; 108323aadfd1c83e08b6723d4cb9357b2908cc464a86Mindy Pereira } 108423aadfd1c83e08b6723d4cb9357b2908cc464a86Mindy Pereira 10856aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal /** 10866aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * The mail activity calls other activities for two specific reasons: 10876aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <ul> 10886aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>To add an account. And receives the result {@link #ADD_ACCOUNT_REQUEST_CODE}</li> 10896aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>To update the password on a current account. The result {@link 10906aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * #REAUTHENTICATE_REQUEST_CODE} is received.</li> 10916aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </ul> 10926aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * @param requestCode 10936aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * @param resultCode 10946aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * @param data 10956aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal */ 109623aadfd1c83e08b6723d4cb9357b2908cc464a86Mindy Pereira @Override 10971ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public void onActivityResult(int requestCode, int resultCode, Intent data) { 1098122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook switch (requestCode) { 1099122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook case ADD_ACCOUNT_REQUEST_CODE: 1100122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook // We were waiting for the user to create an account 1101122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook if (resultCode == Activity.RESULT_OK) { 1102122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook // restart the loader to get the updated list of accounts 1103177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, Bundle.EMPTY, 1104177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mAccountCallbacks); 1105122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook } else { 1106122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook // The user failed to create an account, just exit the app 1107122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook mActivity.finish(); 1108122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook } 1109122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook break; 1110122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook case REAUTHENTICATE_REQUEST_CODE: 1111122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook if (resultCode == Activity.RESULT_OK) { 1112122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook // The user successfully authenticated, attempt to refresh the list 1113122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook final Uri refreshUri = mFolder != null ? mFolder.refreshUri : null; 1114122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook if (refreshUri != null) { 1115122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook startAsyncRefreshTask(refreshUri); 1116122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook } 1117122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook } 1118122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook break; 1119371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon case CHANGE_NAVIGATION_REQUEST_CODE: 1120371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon if (resultCode == Activity.RESULT_OK && data != null) { 1121371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // We have have received a result that indicates we need to navigate to a 1122371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // different folder or account. This happens if someone navigates using the 1123371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // drawer on the search results activity. 1124371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon final Folder folder = data.getParcelableExtra(EXTRA_FOLDER); 1125371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon final Account account = data.getParcelableExtra(EXTRA_ACCOUNT); 1126371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon if (folder != null) { 1127371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon onFolderSelected(folder); 1128371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon mViewMode.enterConversationListMode(); 1129371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon } else if (account != null) { 1130371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon switchToDefaultInboxOrChangeAccount(account); 1131371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon mViewMode.enterConversationListMode(); 1132371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon } 1133371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon } 1134371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon break; 11352388c5d208acd4e4e658aaacbbc5f080ee8e9f7cPaul Westbrook } 1136a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 1137a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 113869b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal /** 113969b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal * Inform the conversation cursor that there has been a visibility change. 1140715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param visible true if the conversation list is visible, false otherwise. 114169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal */ 114269b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal protected synchronized void informCursorVisiblity(boolean visible) { 11439f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook if (mConversationListCursor != null) { 114469b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal Utils.setConversationCursorVisibility(mConversationListCursor, visible, mFolderChanged); 114569b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal // We have informed the cursor. Subsequent visibility changes should not tell it that 114669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal // the folder has changed. 114769b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal mFolderChanged = false; 11489f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook } 1149a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 1150a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 115169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal @Override 115269b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal public void onConversationListVisibilityChanged(boolean visible) { 115369b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal informCursorVisiblity(visible); 1154c94d07f4460d00db898237603de311d226707a96Andy Huang commitAutoAdvanceOperation(); 115532ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy 115632ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy // Notify special views 115732ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy final ConversationListFragment convListFragment = getConversationListFragment(); 115832ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy if (convListFragment != null && convListFragment.getAnimatedAdapter() != null) { 115932ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy convListFragment.getAnimatedAdapter().onConversationListVisibilityChanged(visible); 116032ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy } 116169b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal } 116269b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal 11631ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal /** 11647dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal * Called when a conversation is visible. Child classes must call the super class implementation 11657dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal * before performing local computation. 11661ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal */ 11671ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 11681ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public void onConversationVisibilityChanged(boolean visible) { 1169c94d07f4460d00db898237603de311d226707a96Andy Huang commitAutoAdvanceOperation(); 1170c94d07f4460d00db898237603de311d226707a96Andy Huang } 1171c94d07f4460d00db898237603de311d226707a96Andy Huang 1172c94d07f4460d00db898237603de311d226707a96Andy Huang /** 1173c94d07f4460d00db898237603de311d226707a96Andy Huang * Commits any pending destructive action that was earlier deferred by an auto-advance 1174c94d07f4460d00db898237603de311d226707a96Andy Huang * mode-change transition. 1175c94d07f4460d00db898237603de311d226707a96Andy Huang */ 1176c94d07f4460d00db898237603de311d226707a96Andy Huang private void commitAutoAdvanceOperation() { 1177c94d07f4460d00db898237603de311d226707a96Andy Huang if (mAutoAdvanceOp != null) { 1178c94d07f4460d00db898237603de311d226707a96Andy Huang mAutoAdvanceOp.run(); 1179c94d07f4460d00db898237603de311d226707a96Andy Huang mAutoAdvanceOp = null; 1180c94d07f4460d00db898237603de311d226707a96Andy Huang } 11811ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 11821ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 118359f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal /** 118459f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal * Initialize development time logging. This can potentially log a lot of PII, and we don't want 118559f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal * to turn it on for shipped versions. 118659f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal */ 118759f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal private void initializeDevLoggingService() { 118859f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal if (!MailLogService.DEBUG_ENABLED) { 118959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal return; 119059f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } 119159f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal // Check every 5 minutes. 119259f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal final int WAIT_TIME = 5 * 60 * 1000; 119359f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal // Start a runnable that periodically checks the log level and starts/stops the service. 119459f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mLogServiceChecker = new Runnable() { 119559f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal /** True if currently logging. */ 119659f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal private boolean mCurrentlyLogging = false; 119759f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal 119859f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal /** 119959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal * If the logging level has been changed since the previous run, start or stop the 120059f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal * service. 120159f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal */ 120259f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal private void startOrStopService() { 120359f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal // If the log level is already high, start the service. 120459f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal final Intent i = new Intent(mContext, MailLogService.class); 120559f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal final boolean loggingEnabled = MailLogService.isLoggingLevelHighEnough(); 120659f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal if (mCurrentlyLogging == loggingEnabled) { 120759f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal // No change since previous run, just return; 120859f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal return; 120959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } 121059f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal if (loggingEnabled) { 121159f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal LogUtils.e(LOG_TAG, "Starting MailLogService"); 121259f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mContext.startService(i); 121359f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } else { 121459f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal LogUtils.e(LOG_TAG, "Stopping MailLogService"); 121559f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mContext.stopService(i); 121659f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } 121759f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mCurrentlyLogging = loggingEnabled; 121859f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } 121959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal 122059f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal @Override 122159f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal public void run() { 122259f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal startOrStopService(); 122359f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mHandler.postDelayed(this, WAIT_TIME); 122459f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } 122559f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal }; 122659f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal // Start the runnable right away. 122759f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mHandler.post(mLogServiceChecker); 122859f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal } 122959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal 12306aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal /** 12316aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * The application can be started from the following entry points: 12326aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <ul> 12336aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Launcher: you tap on the Gmail icon in the launcher. This is what most users think of 12346aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * as “Starting the app”.</li> 12356aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Shortcut: Users can make a shortcut to take them directly to a label.</li> 12366aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Widget: Shows the contents of a synced label, and allows: 12376aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <ul> 12386aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Viewing the list (tapping on the title)</li> 12396aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Composing a new message (tapping on the new message icon in the title. This 12406aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * launches the {@link ComposeActivity}. 12416aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </li> 12426aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Viewing a single message (tapping on a list element)</li> 12436aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </ul> 12446aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * 12456aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </li> 12466aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Tapping on a notification: 12476aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <ul> 12486aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Shows message list if more than one message</li> 12496aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Shows the conversation if the notification is for a single message</li> 12506aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </ul> 12516aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </li> 12526aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>...and most importantly, the activity life cycle can tear down the application and 12536aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * restart it: 12546aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <ul> 12556aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Rotate the application: it is destroyed and recreated.</li> 12566aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Navigate away, and return from recent applications.</li> 12576aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </ul> 12586aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </li> 12596aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Add a new account: fires off an intent to add an account, 12606aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * and returns in {@link #onActivityResult(int, int, android.content.Intent)} .</li> 12616aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Re-authenticate your account: again returns in onActivityResult().</li> 12626aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * <li>Composing can happen from many entry points: third party applications fire off an 12636aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * intent to compose email, and launch directly into the {@link ComposeActivity} 12646aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * .</li> 12656aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * </ul> 12666aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * {@inheritDoc} 12676aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal */ 12681ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 1269d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal public boolean onCreate(Bundle savedState) { 1270abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal initializeActionBar(); 127159f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal initializeDevLoggingService(); 12721ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal // Allow shortcut keys to function for the ActionBar and menus. 12731ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal mActivity.setDefaultKeyMode(Activity.DEFAULT_KEYS_SHORTCUT); 127480aeac5356b5a14a5ef2aff8f0f72a464c9a3cb4Vikram Aggarwal mResolver = mActivity.getContentResolver(); 12756ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook mNewEmailReceiver = new SuppressNotificationReceiver(); 12767c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal mRecentFolderList.initialize(mActivity); 127769a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal mVeiledMatcher.initialize(this); 12786ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook 12791a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux mFloatingComposeButton = mActivity.findViewById(R.id.compose_button); 12801a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux mFloatingComposeButton.setOnClickListener(this); 12815d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux 1282f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang if (isDrawerEnabled()) { 1283f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerToggle = new ActionBarDrawerToggle(mActivity, mDrawerContainer, false, 1284f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close); 1285f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerContainer.setDrawerListener(mDrawerListener); 1286f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerContainer.setDrawerShadow( 1287f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mContext.getResources().getDrawable(R.drawable.drawer_shadow), Gravity.START); 128812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 1289f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerToggle.setDrawerIndicatorEnabled(isDrawerEnabled()); 1290f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang } else { 129152882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein final ActionBar ab = mActivity.getSupportActionBar(); 1292f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang ab.setHomeAsUpIndicator(R.drawable.ic_drawer); 1293f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang ab.setHomeActionContentDescription(R.string.drawer_open); 1294f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang ab.setDisplayHomeAsUpEnabled(true); 1295f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang } 129612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 1297161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira // All the individual UI components listen for ViewMode changes. This 1298b849dfbda3c917f078a5c09f03906886c27ecbecMindy Pereira // simplifies the amount of logic in the AbstractActivityController, but increases the 1299b849dfbda3c917f078a5c09f03906886c27ecbecMindy Pereira // possibility of timing-related bugs. 13001ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal mViewMode.addListener(this); 1301632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mPagerController = new ConversationPagerController(mActivity, this); 13029a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux mToastBar = findActionableToastBar(mActivity); 1303ada517849ada8a3c3a62d81c5163f392bc674eb7Vikram Aggarwal attachActionBar(); 13041ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 1305144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang mDrawIdler.setRootView(mActivity.getWindow().getDecorView()); 1306144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang 1307632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final Intent intent = mActivity.getIntent(); 13084fe0af81874976a1995191321e35c844b2229811Andy Huang 1309abd24d82e41fd4747945d3f124b4e3a57e5dc6e6Vikram Aggarwal // Immediately handle a clean launch with intent, and any state restoration 1310632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // that does not rely on restored fragments or loader data 1311632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // any state restoration that relies on those can be done later in 1312632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // onRestoreInstanceState, once fragments are up and loader data is re-delivered 1313632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (savedState != null) { 1314632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (savedState.containsKey(SAVED_ACCOUNT)) { 1315632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang setAccount((Account) savedState.getParcelable(SAVED_ACCOUNT)); 1316632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 1317632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (savedState.containsKey(SAVED_FOLDER)) { 13182bc8bc1f69faacaddab41ab61e1d2e8658f4181fAndy Huang final Folder folder = savedState.getParcelable(SAVED_FOLDER); 1319203dc00aff8e890000ee0c9587081e0968fdae8dVikram Aggarwal final String query = savedState.getString(SAVED_QUERY, null); 1320649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal setListContext(folder, query); 1321632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 13226cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal if (savedState.containsKey(SAVED_ACTION)) { 13236cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal mDialogAction = savedState.getInt(SAVED_ACTION); 13246cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal } 1325a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal mDialogFromSelectedSet = savedState.getBoolean(SAVED_ACTION_FROM_SELECTED, false); 1326649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal mViewMode.handleRestore(savedState); 1327632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } else if (intent != null) { 1328632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang handleIntent(intent); 1329632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 1330632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // Create the accounts loader; this loads the account switch spinner. 1331177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, Bundle.EMPTY, 1332177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mAccountCallbacks); 1333632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return true; 1334b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang } 1335b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang 13369a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux /** 13379a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux * @param activity the activity that has been inflated 13389a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux * @return the Actionable Toast Bar defined within the activity 13399a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux */ 13409a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux protected ActionableToastBar findActionableToastBar(MailActivity activity) { 13419a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux return (ActionableToastBar) activity.findViewById(R.id.toast_bar); 13429a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux } 13439a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux 1344b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang @Override 134557246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook public void onPostCreate(Bundle savedState) { 1346f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang if (!isDrawerEnabled()) { 1347f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang return; 1348f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang } 134912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang // Sync the toggle state after onRestoreInstanceState has occurred. 135012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerToggle.syncState(); 13515747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein 1352d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal mHideMenuItems = isDrawerEnabled() && mDrawerContainer.isDrawerOpen(mDrawerPullout); 135357246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook } 135457246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook 135557246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook @Override 135657246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook public void onConfigurationChanged(Configuration newConfig) { 1357f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang if (isDrawerEnabled()) { 1358f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang mDrawerToggle.onConfigurationChanged(newConfig); 1359f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang } 136012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 136112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 136212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang /** 13635d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux * This controller listens for clicks on items in the floating action bar. 13645d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux * 13655d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux * @param view the item that was clicked in the floating action bar 13665d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux */ 13675d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux @Override 13685d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux public void onClick(View view) { 136953de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein final int viewId = view.getId(); 137053de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein if (viewId == R.id.compose_button) { 137153de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein ComposeActivity.compose(mActivity.getActivityContext(), getAccount()); 137253de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein } else if (viewId == android.R.id.home) { 137353de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein // TODO: b/16627877 137453de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein onUpPressed(); 137553de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein } 13765d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux } 13775d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux 13785d79a913c8289de4ffc1b662b9bea967a7e65b0dJames Lemieux /** 137912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * If drawer is open/visible (even partially), close it. 138012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang */ 138112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang protected void closeDrawerIfOpen() { 138212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (!isDrawerEnabled()) { 138312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang return; 138412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 138512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if(mDrawerContainer.isDrawerOpen(mDrawerPullout)) { 138612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.closeDrawers(); 138712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 138857246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook } 138957246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook 139057246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook @Override 13911ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang public void onStart() { 13921ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang mSafeToModifyFragments = true; 1393cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy 1394cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy NotificationActionUtils.registerUndoNotificationObserver(mUndoNotificationObserver); 1395761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang 1396761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang if (mViewMode.getMode() != ViewMode.UNKNOWN) { 1397761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang Analytics.getInstance().sendView("MainActivity" + mViewMode.toString()); 1398761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang } 13991ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 14001ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 14011ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang @Override 140200179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein public void onRestart() { 1403177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final DialogFragment fragment = (DialogFragment) 140400179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein mFragmentManager.findFragmentByTag(SYNC_ERROR_DIALOG_FRAGMENT_TAG); 140500179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein if (fragment != null) { 140600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein fragment.dismiss(); 140700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 1408ea04f938bef8e2ec7c6f64067511f006681318fbmindyp // When the user places the app in the background by pressing "home", 1409ea04f938bef8e2ec7c6f64067511f006681318fbmindyp // dismiss the toast bar. However, since there is no way to determine if 1410ea04f938bef8e2ec7c6f64067511f006681318fbmindyp // home was pressed, just dismiss any existing toast bar when restarting 1411ea04f938bef8e2ec7c6f64067511f006681318fbmindyp // the app. 1412ea04f938bef8e2ec7c6f64067511f006681318fbmindyp if (mToastBar != null) { 1413f8ccdcfc26f362d9c20771e2295a0c0e8d1195f3Andrew Sapperstein mToastBar.hide(false, false /* actionClicked */); 1414ea04f938bef8e2ec7c6f64067511f006681318fbmindyp } 141500179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 141600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein 141700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein @Override 14181ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public Dialog onCreateDialog(int id, Bundle bundle) { 14191ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal return null; 14201ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 14211ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 1422a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 14234eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal public final boolean onCreateOptionsMenu(Menu menu) { 14240fa9efd6df21a92866908ab679a78b7a128bc28fAndrew Sapperstein if (mViewMode.isAdMode()) { 14250fa9efd6df21a92866908ab679a78b7a128bc28fAndrew Sapperstein return false; 14260fa9efd6df21a92866908ab679a78b7a128bc28fAndrew Sapperstein } 1427e5e917c10cbc4afd31358c0425954e2c27e0fb8eVikram Aggarwal final MenuInflater inflater = mActivity.getMenuInflater(); 14282d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein inflater.inflate(mActionBarController.getOptionsMenuId(), menu); 14292d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.onCreateOptionsMenu(menu); 143028d5f72e0ad0db75b6243ee8125bfe3aadbdcb85Mindy Pereira return true; 1431a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 1432a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 1433a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 14344eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal public final boolean onKeyDown(int keyCode, KeyEvent event) { 1435b9e1a353c6a173a2885642dbcc1939f3281f29f7Vikram Aggarwal return false; 14361ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 14371ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 143817a8e78d61bff414610e23f24889bab29955f54emindyp public abstract boolean doesActionChangeConversationListVisibility(int action); 143917a8e78d61bff414610e23f24889bab29955f54emindyp 144030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao /** 144130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * Helper function that determines if we should associate an undo callback with 144230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * the current menu action item 144330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * @param actionId the id of the action 144430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * @return the appropriate callback handler, or null if not applicable 144530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao */ 144630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao private UndoCallback getUndoCallbackForDestructiveActionsWithAutoAdvance( 144730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao int actionId, final Conversation conv) { 144830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // We associated the undoCallback if the user is going to perform an action on the current 144930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // conversation, causing the current conversation to be removed from view and replacing it 145030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // with another (via Auto Advance). The undoCallback will bring the removed conversation 145130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // back into the view if the action is undone. 145230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final Collection<Conversation> convCol = Conversation.listOf(conv); 145330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final boolean isApplicableForReshow = mAccount != null && 145430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mAccount.settings != null && 145530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mTracker != null && 145630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // ensure that we will show another conversation due to Auto Advance 145730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mTracker.getNextConversation( 145830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mAccount.settings.getAutoAdvanceSetting(), convCol) != null && 145930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // ensure that we are performing the action from conversation view 146030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao isCurrentConversationInView(convCol) && 146130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao // check for the appropriate destructive actions 146230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao doesActionRemoveCurrentConversationFromView(actionId); 146330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return (isApplicableForReshow) ? 146430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao new UndoCallback() { 146530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao @Override 146630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public void performUndoCallback() { 146730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao showConversation(conv); 146830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 146930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } : null; 147030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 147130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 147230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao /** 147330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * Check if the provided action will remove the active conversation from view 147430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * @param actionId the applied action 147530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * @return true if it will remove the conversation from view, false otherwise 147630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao */ 147730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao private boolean doesActionRemoveCurrentConversationFromView(int actionId) { 147830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return actionId == R.id.archive || 147930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao actionId == R.id.delete || 1480512821c11d89d49908f3cfdee0b582601f500f3dJin Cao actionId == R.id.discard_outbox || 148130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao actionId == R.id.remove_folder || 148230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao actionId == R.id.report_spam || 148330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao actionId == R.id.report_phishing || 148430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao actionId == R.id.move_to; 148530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 148630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 14871ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 148857246a4bf94e8b440c0597fa4a8e4f4e8a46532aPaul Westbrook public boolean onOptionsItemSelected(MenuItem item) { 1489761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang 149012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang /* 149112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * The action bar home/up action should open or close the drawer. 149212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * mDrawerToggle will take care of this. 149312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang */ 1494f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang if (isDrawerEnabled() && mDrawerToggle.onOptionsItemSelected(item)) { 1495042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang Analytics.getInstance().sendEvent(Analytics.EVENT_CATEGORY_MENU_ITEM, "drawer_toggle", 1496042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang null, 0); 149712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang return true; 149812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 149912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 15002b55549d4fbe25e91f673a0727fc89ff755d9327Andy Huang Analytics.getInstance().sendMenuItemEvent(Analytics.EVENT_CATEGORY_MENU_ITEM, 1501f8c59b0198bd3230ef669c5e258b86443e7ed682Andy Huang item.getItemId(), "action_bar/" + mViewMode.getModeString(), 0); 1502042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang 150354452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal final int id = item.getItemId(); 15047dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal LogUtils.d(LOG_TAG, "AbstractController.onOptionsItemSelected(%d) called.", id); 15059b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira boolean handled = true; 150684fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal /** This is NOT a batch action. */ 150784fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal final boolean isBatch = false; 1508ba68fdaf4f251eccba0832878a74bdaf6aa7469eMindy Pereira final Collection<Conversation> target = Conversation.listOf(mCurrentConversation); 1509112cd16335e1ca56c96d005aa3b5bb11508396dcVikram Aggarwal final Settings settings = (mAccount == null) ? null : mAccount.settings; 151084f7d32bdc79263004ed5241480988e02f8e618cmindyp // The user is choosing a new action; commit whatever they had been 151117a8e78d61bff414610e23f24889bab29955f54emindyp // doing before. Don't animate if we are launching a new screen. 151217a8e78d61bff414610e23f24889bab29955f54emindyp commitDestructiveActions(!doesActionChangeConversationListVisibility(id)); 151330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final UndoCallback undoCallback = getUndoCallbackForDestructiveActionsWithAutoAdvance( 151430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao id, mCurrentConversation); 151530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 15162b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (id == R.id.archive) { 15172b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy final boolean showDialog = (settings != null && settings.confirmArchive); 151830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao confirmAndDelete(id, target, showDialog, R.plurals.confirm_archive_conversation, undoCallback); 15192b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.remove_folder) { 15202b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy delete(R.id.remove_folder, target, 152130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao getDeferredRemoveFolder(target, mFolder, true, isBatch, true, undoCallback), 152230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao isBatch); 15232b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.delete) { 15242b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy final boolean showDialog = (settings != null && settings.confirmDelete); 152530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao confirmAndDelete(id, target, showDialog, R.plurals.confirm_delete_conversation, undoCallback); 15262b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.discard_drafts) { 1527121c8b877090e780b4a16d5a14507c3649e61d7fAndy Huang // drafts are lost forever, so always confirm 1528121c8b877090e780b4a16d5a14507c3649e61d7fAndy Huang confirmAndDelete(id, target, true /* showDialog */, 152930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao R.plurals.confirm_discard_drafts_conversation, undoCallback); 1530512821c11d89d49908f3cfdee0b582601f500f3dJin Cao } else if (id == R.id.discard_outbox) { 1531512821c11d89d49908f3cfdee0b582601f500f3dJin Cao // discard in outbox means we discard the failed message and save them in drafts 1532512821c11d89d49908f3cfdee0b582601f500f3dJin Cao delete(id, target, getDeferredAction(id, target, isBatch, undoCallback), isBatch); 15332b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.mark_important) { 15342b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy updateConversation(Conversation.listOf(mCurrentConversation), 15352b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy ConversationColumns.PRIORITY, UIProvider.ConversationPriority.HIGH); 15362b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.mark_not_important) { 15372b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mFolder != null && mFolder.isImportantOnly()) { 15382b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy delete(R.id.mark_not_important, target, 153930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao getDeferredAction(R.id.mark_not_important, target, isBatch, undoCallback), 154030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao isBatch); 15412b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else { 15422b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy updateConversation(Conversation.listOf(mCurrentConversation), 15432b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy ConversationColumns.PRIORITY, UIProvider.ConversationPriority.LOW); 1544ba68fdaf4f251eccba0832878a74bdaf6aa7469eMindy Pereira } 15452b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.mute) { 154630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao delete(R.id.mute, target, getDeferredAction(R.id.mute, target, isBatch, undoCallback), 154730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao isBatch); 15482b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.report_spam) { 15492b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy delete(R.id.report_spam, target, 155030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao getDeferredAction(R.id.report_spam, target, isBatch, undoCallback), isBatch); 15512b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.mark_not_spam) { 15522b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Currently, since spam messages are only shown in list with 15532b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // other spam messages, 15542b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // marking a message not as spam is a destructive action 15552b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy delete(R.id.mark_not_spam, target, 155630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao getDeferredAction(R.id.mark_not_spam, target, isBatch, undoCallback), isBatch); 15572b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.report_phishing) { 15582b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy delete(R.id.report_phishing, target, 155930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao getDeferredAction(R.id.report_phishing, target, isBatch, undoCallback), isBatch); 15602b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == android.R.id.home) { 15612b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy onUpPressed(); 15622b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.compose) { 15632b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy ComposeActivity.compose(mActivity.getActivityContext(), mAccount); 15642b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.refresh) { 15652b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy requestFolderRefresh(); 15662b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.settings) { 15672b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy Utils.showSettings(mActivity.getActivityContext(), mAccount); 15682b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.help_info_menu_item) { 1569a57da3c151ae174bc8621af79f3f09392ed90953Ray Chen mActivity.showHelp(mAccount, mViewMode.getMode()); 15706c570db71b8adc43d7dc2f31e6fa63cf50c1426eAndrew Sapperstein } else if (id == R.id.move_to || id == R.id.change_folders) { 15712a4be2459962700e1a38ba897de5d2f5913412f5Tony Mantler final FolderSelectionDialog dialog = FolderSelectionDialog.getInstance(mAccount, 15722b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy Conversation.listOf(mCurrentConversation), isBatch, mFolder, 15732b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy id == R.id.move_to); 15742b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (dialog != null) { 15752a4be2459962700e1a38ba897de5d2f5913412f5Tony Mantler dialog.show(mActivity.getFragmentManager(), null); 1576a8e4318bb9921e2ec6045c5f7187a4b78c55fe10Vikram Aggarwal } 15772b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.move_to_inbox) { 15782b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy new AsyncTask<Void, Void, Folder>() { 15792b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy @Override 15802b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy protected Folder doInBackground(final Void... params) { 15812b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Get the "move to" inbox 15822b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy return Utils.getFolder(mContext, mAccount.settings.moveToInbox, 15832b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy true /* allowHidden */); 1584a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp } 1585dd2ec688cf18e0ec132d936168ccaa3c43cdefb1Scott Kennedy 15862b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy @Override 15872b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy protected void onPostExecute(final Folder moveToInbox) { 15882b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy final List<FolderOperation> ops = Lists.newArrayListWithCapacity(1); 15892b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Add inbox 15902b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy ops.add(new FolderOperation(moveToInbox, true)); 15912b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy assignFolder(ops, Conversation.listOf(mCurrentConversation), true, 15922b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy true /* showUndo */, false /* isMoveTo */); 15932b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 15942b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy }.execute((Void[]) null); 15952b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.empty_trash) { 15962b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy showEmptyDialog(); 15972b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.empty_spam) { 15982b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy showEmptyDialog(); 15992b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else { 16002b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy handled = false; 160128d5f72e0ad0db75b6243ee8125bfe3aadbdcb85Mindy Pereira } 16029b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira return handled; 1603a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 1604a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 1605ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein /** 1606ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein * Opens an {@link EmptyFolderDialogFragment} for the current folder. 1607ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein */ 1608ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein private void showEmptyDialog() { 1609ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein if (mFolder != null) { 1610ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein final EmptyFolderDialogFragment fragment = 1611ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein EmptyFolderDialogFragment.newInstance(mFolder.totalCount, mFolder.type); 1612ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein fragment.setListener(this); 1613ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein fragment.show(mActivity.getFragmentManager(), EmptyFolderDialogFragment.FRAGMENT_TAG); 1614ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein } 1615ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein } 1616ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein 1617ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein @Override 1618ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein public void onFolderEmptied() { 1619ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein emptyFolder(); 1620ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein } 1621ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein 1622ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein /** 1623ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein * Performs the work of emptying the currently visible folder. 1624ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein */ 16257ee089ea2ef96e31504e88637b5f3b0969b3c7c1Scott Kennedy private void emptyFolder() { 16261d0f1f839023e405b24ffc6a670b5c26b36f24e0Yorke Lee if (mConversationListCursor != null) { 16271d0f1f839023e405b24ffc6a670b5c26b36f24e0Yorke Lee mConversationListCursor.emptyFolder(); 16281d0f1f839023e405b24ffc6a670b5c26b36f24e0Yorke Lee } 16297ee089ea2ef96e31504e88637b5f3b0969b3c7c1Scott Kennedy } 16307ee089ea2ef96e31504e88637b5f3b0969b3c7c1Scott Kennedy 1631ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein private void attachEmptyFolderDialogFragmentListener() { 1632ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein final EmptyFolderDialogFragment fragment = 1633ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein (EmptyFolderDialogFragment) mActivity.getFragmentManager() 1634ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein .findFragmentByTag(EmptyFolderDialogFragment.FRAGMENT_TAG); 1635ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein 1636ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein if (fragment != null) { 1637ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein fragment.setListener(this); 1638ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein } 1639ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein } 1640ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein 16418e65c6d2527c7539b689e0e8548c84f690badca5Rohan Shah /** 164212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * Toggles the drawer pullout. If it was open (Fully extended), the 164312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * drawer will be closed. Otherwise, the drawer will be opened. This should 164412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * only be called when used with a toggle item. Other cases should be handled 164512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * explicitly with just closeDrawers() or openDrawer(View drawerView); 16468e65c6d2527c7539b689e0e8548c84f690badca5Rohan Shah */ 1647d9eaca8676ad4c6c58122fd41be799872bfd9cdaTony Mantler protected void toggleDrawerState() { 164812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (!isDrawerEnabled()) { 164912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang return; 165012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 165112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if(mDrawerContainer.isDrawerOpen(mDrawerPullout)) { 165212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.closeDrawers(); 165312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } else { 165412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.openDrawer(mDrawerPullout); 165512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 16568e65c6d2527c7539b689e0e8548c84f690badca5Rohan Shah } 16578e65c6d2527c7539b689e0e8548c84f690badca5Rohan Shah 1658531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal @Override 1659c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang public final boolean onUpPressed() { 1660c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang return handleUpPress(); 1661c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang } 1662c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang 1663c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang @Override 1664c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang public final boolean onBackPressed() { 166512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (isDrawerEnabled() && mDrawerContainer.isDrawerVisible(mDrawerPullout)) { 166612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.closeDrawers(); 166712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang return true; 166812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 166912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 1670c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang return handleBackPress(); 1671c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang } 1672c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang 1673c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang protected abstract boolean handleBackPress(); 1674ede2e52e725abc625ae963f979639ff8ecc40cf5Greg Bullock 1675c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang protected abstract boolean handleUpPress(); 1676c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang 1677c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huang @Override 16786c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira public void updateConversation(Collection<Conversation> target, ContentValues values) { 16799e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateValues(target, values); 16806c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira refreshConversationList(); 16816c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira } 16826c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira 16836c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira @Override 1684531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal public void updateConversation(Collection <Conversation> target, String columnName, 1685531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal boolean value) { 16869e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateBoolean(target, columnName, value); 168775daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal refreshConversationList(); 168854452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal } 168954452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal 1690531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal @Override 16916c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira public void updateConversation(Collection <Conversation> target, String columnName, 16926c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira int value) { 16939e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateInt(target, columnName, value); 169475daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal refreshConversationList(); 1695c9d59184da271d5a6974edb709e3b39a5a970fa7Mindy Pereira } 1696c9d59184da271d5a6974edb709e3b39a5a970fa7Mindy Pereira 1697531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal @Override 1698531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal public void updateConversation(Collection <Conversation> target, String columnName, 1699531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal String value) { 17009e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateString(target, columnName, value); 170175daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal refreshConversationList(); 170254452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal } 170354452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal 1704839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang @Override 17057c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu public void markConversationMessagesUnread(final Conversation conv, 17067c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu final Set<Uri> unreadMessageUris, final byte[] originalConversationInfo) { 17078f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang // The only caller of this method is the conversation view, from where marking unread should 17088f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang // *always* take you back to list mode. 17098f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang showConversation(null); 17108f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang 1711839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // locally mark conversation unread (the provider is supposed to propagate message unread 1712839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // to conversation unread) 1713839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang conv.read = false; 17141faf93d79a00acb0fe607495c39f87d53a05889bPaul Westbrook if (mConversationListCursor == null) { 171581230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, "markConversationMessagesUnread(id=%d), deferring", conv.id); 17167c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu 17177c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu mConversationListLoadFinishedCallbacks.add(new LoadFinishedCallback() { 17187c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu @Override 17197c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu public void onLoadFinished() { 17207c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu doMarkConversationMessagesUnread(conv, unreadMessageUris, 17217c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu originalConversationInfo); 17227c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } 17237c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu }); 17247c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } else { 172581230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, "markConversationMessagesUnread(id=%d), performing", conv.id); 17267c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu doMarkConversationMessagesUnread(conv, unreadMessageUris, originalConversationInfo); 17271faf93d79a00acb0fe607495c39f87d53a05889bPaul Westbrook } 17287c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } 17291faf93d79a00acb0fe607495c39f87d53a05889bPaul Westbrook 17307c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu private void doMarkConversationMessagesUnread(Conversation conv, Set<Uri> unreadMessageUris, 17317c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu byte[] originalConversationInfo) { 173281230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal // Only do a granular 'mark unread' if a subset of messages are unread 173328e31e2417d775b343919cf6018f85871e40a294Andy Huang final int unreadCount = (unreadMessageUris == null) ? 0 : unreadMessageUris.size(); 17340972e0793cc321670391d063348aecb5031b2677Mindy Pereira final int numMessages = conv.getNumMessages(); 17350972e0793cc321670391d063348aecb5031b2677Mindy Pereira final boolean subsetIsUnread = (numMessages > 1 && unreadCount > 0 17360972e0793cc321670391d063348aecb5031b2677Mindy Pereira && unreadCount < numMessages); 173728e31e2417d775b343919cf6018f85871e40a294Andy Huang 17389e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huang LogUtils.d(LOG_TAG, "markConversationMessagesUnread(conv=%s)" 173981230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal + ", numMessages=%d, unreadCount=%d, subsetIsUnread=%b", 17409e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huang conv, numMessages, unreadCount, subsetIsUnread); 174128e31e2417d775b343919cf6018f85871e40a294Andy Huang if (!subsetIsUnread) { 174266bc2aaf76bb0dfa4fc38f8fcbaaf9e413e321ddVikram Aggarwal // Conversations are neither marked read, nor viewed, and we don't want to show 174366bc2aaf76bb0dfa4fc38f8fcbaaf9e413e321ddVikram Aggarwal // the next conversation. 174481230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, ". . doing full mark unread"); 1745caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy markConversationsRead(Collections.singletonList(conv), false, false, false); 1746839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } else { 174781230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) { 174881230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal final ConversationInfo info = ConversationInfo.fromBlob(originalConversationInfo); 174981230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, ". . doing subset mark unread, originalConversationInfo = %s", 175081230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal info); 175181230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal } 1752daa06aba887e8e3748453f45ae52c1e571fe9f2eAndy Huang mConversationListCursor.setConversationColumn(conv.uri, ConversationColumns.READ, 0); 1753839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 175481230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal // Locally update conversation's conversationInfo to revert to original version 175528e31e2417d775b343919cf6018f85871e40a294Andy Huang if (originalConversationInfo != null) { 175628e31e2417d775b343919cf6018f85871e40a294Andy Huang mConversationListCursor.setConversationColumn(conv.uri, 175728e31e2417d775b343919cf6018f85871e40a294Andy Huang ConversationColumns.CONVERSATION_INFO, originalConversationInfo); 175828e31e2417d775b343919cf6018f85871e40a294Andy Huang } 1759839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 1760839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // applyBatch with each CPO as an UPDATE op on each affected message uri 1761839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang final ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 1762839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang String authority = null; 1763839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang for (Uri messageUri : unreadMessageUris) { 1764839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang if (authority == null) { 1765839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang authority = messageUri.getAuthority(); 1766839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1767839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang ops.add(ContentProviderOperation.newUpdate(messageUri) 1768839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang .withValue(UIProvider.MessageColumns.READ, 0) 1769839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang .build()); 177081230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, ". . Adding op: read=0, uri=%s", messageUri); 1771839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 177281230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, ". . operations = %s", ops); 1773839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang new ContentProviderTask() { 1774839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang @Override 1775839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang protected void onPostExecute(Result result) { 1776d9895b65e074a2cd68ad2aaa87d7b49f05bacdbeVikram Aggarwal if (result.exception != null) { 1777d9895b65e074a2cd68ad2aaa87d7b49f05bacdbeVikram Aggarwal LogUtils.e(LOG_TAG, result.exception, "ContentProviderTask() ERROR."); 1778d9895b65e074a2cd68ad2aaa87d7b49f05bacdbeVikram Aggarwal } else { 17799e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huang LogUtils.d(LOG_TAG, "ContentProviderTask(): success %s", 17809e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huang Arrays.toString(result.results)); 1781d9895b65e074a2cd68ad2aaa87d7b49f05bacdbeVikram Aggarwal } 1782839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1783839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang }.run(mResolver, authority, ops); 1784839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1785839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1786839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 1787839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang @Override 17887c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu public void markConversationsRead(final Collection<Conversation> targets, final boolean read, 17897c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu final boolean viewed) { 1790919d01a1144dc14f114860949ff4af79a9165ec7Scott Kennedy LogUtils.d(LOG_TAG, "markConversationsRead(targets=%s)", targets.toArray()); 1791919d01a1144dc14f114860949ff4af79a9165ec7Scott Kennedy 17927c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu if (mConversationListCursor == null) { 179381230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) { 179481230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.d(LOG_TAG, "markConversationsRead(targets=%s), deferring", 179581230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal targets.toArray()); 179681230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal } 17977c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu mConversationListLoadFinishedCallbacks.add(new LoadFinishedCallback() { 17987c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu @Override 17997c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu public void onLoadFinished() { 1800caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy markConversationsRead(targets, read, viewed, true); 18017c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } 18027c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu }); 18037c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } else { 18047c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu // We want to show the next conversation if we are marking unread. 1805caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy markConversationsRead(targets, read, viewed, true); 18067c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } 18078f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang } 18088f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang 18090d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy private void markConversationsRead(final Collection<Conversation> targets, final boolean read, 1810caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy final boolean markViewed, final boolean showNext) { 18117c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu LogUtils.d(LOG_TAG, "performing markConversationsRead"); 1812cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal // Auto-advance if requested and the current conversation is being marked unread 18138f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang if (showNext && !read) { 18140d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy final Runnable operation = new Runnable() { 18150d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy @Override 18160d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy public void run() { 1817caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy markConversationsRead(targets, read, markViewed, showNext); 18180d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy } 18190d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy }; 18200d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 1821caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy if (!showNextConversation(targets, operation)) { 18220d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy // This method will be called again if the user selects an autoadvance option 18230d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy return; 18240d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy } 18258f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang } 18260d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 1827cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal final int size = targets.size(); 1828cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal final List<ConversationOperation> opList = new ArrayList<ConversationOperation>(size); 1829cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal for (final Conversation target : targets) { 1830e2be97a58fbae98b95e51735c6468d121e465355Paul Westbrook final ContentValues value = new ContentValues(4); 1831cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal value.put(ConversationColumns.READ, read); 18325109c516b5cac279b4f99271953a27dd9a4828d8Paul Westbrook 1833d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy // We never want to mark unseen here, but we do want to mark it seen 1834d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy if (read || markViewed) { 1835d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy value.put(ConversationColumns.SEEN, Boolean.TRUE); 1836d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy } 1837d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy 18385109c516b5cac279b4f99271953a27dd9a4828d8Paul Westbrook // The mark read/unread/viewed operations do not show an undo bar 18395109c516b5cac279b4f99271953a27dd9a4828d8Paul Westbrook value.put(ConversationOperations.Parameters.SUPPRESS_UNDO, true); 184066bc2aaf76bb0dfa4fc38f8fcbaaf9e413e321ddVikram Aggarwal if (markViewed) { 1841cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal value.put(ConversationColumns.VIEWED, true); 184266bc2aaf76bb0dfa4fc38f8fcbaaf9e413e321ddVikram Aggarwal } 1843192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal final ConversationInfo info = target.conversationInfo; 1844edd6c1a2807d2ade930dfd4622707298dc470d64Tony Mantler final boolean changed = info.markRead(read); 1845edd6c1a2807d2ade930dfd4622707298dc470d64Tony Mantler if (changed) { 1846edd6c1a2807d2ade930dfd4622707298dc470d64Tony Mantler value.put(ConversationColumns.CONVERSATION_INFO, info.toBlob()); 1847839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1848cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal opList.add(mConversationListCursor.getOperationForConversation( 1849cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal target, ConversationOperation.UPDATE, value)); 1850cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal // Update the local conversation objects so they immediately change state. 1851cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal target.read = read; 1852cd5c5eeae167885ffa2959c200233fea2f39c5f7Andy Huang if (markViewed) { 1853cc754b102ed65df9d637b4e0a03e645214ea3cccVikram Aggarwal target.markViewed(); 1854cd5c5eeae167885ffa2959c200233fea2f39c5f7Andy Huang } 1855839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 18569e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateBulkValues(opList); 1857839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1858839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 18598f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang /** 18608f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang * Auto-advance to a different conversation if the currently visible conversation in 18618f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang * conversation mode is affected (deleted, marked unread, etc.). 18628f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang * 18630d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * <p>Does nothing if outside of conversation mode.</p> 18648f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang * 18658f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang * @param target the set of conversations being deleted/marked unread 18668f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang */ 18679365a826b46b0e274df88e92534f7d871eef2aa2mindyp @Override 18680d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy public void showNextConversation(final Collection<Conversation> target) { 1869caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy showNextConversation(target, null); 18700d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy } 18710d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 18720d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy /** 187330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * Helper function to determine if the provided set of conversations is in view 187430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * @param target set of conversations that we are interested in 187530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao * @return true if they are in view, false otherwise 187630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao */ 187730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao private boolean isCurrentConversationInView(final Collection<Conversation> target) { 187830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final int viewMode = mViewMode.getMode(); 187930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return (viewMode == ViewMode.CONVERSATION 188030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao || viewMode == ViewMode.SEARCH_RESULTS_CONVERSATION) 188130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao && Conversation.contains(target, mCurrentConversation); 188230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 188330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 188430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao /** 18850d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * Auto-advance to a different conversation if the currently visible conversation in 18860d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * conversation mode is affected (deleted, marked unread, etc.). 18870d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * 18880d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * <p>Does nothing if outside of conversation mode.</p> 1889c94d07f4460d00db898237603de311d226707a96Andy Huang * <p> 1890c94d07f4460d00db898237603de311d226707a96Andy Huang * Clients may pass an operation to execute on the target that this method will run after 1891c94d07f4460d00db898237603de311d226707a96Andy Huang * auto-advance is complete. The operation, if provided, may run immediately, or it may run 1892c94d07f4460d00db898237603de311d226707a96Andy Huang * later, or not at all. Reasons it may run later include: 1893c94d07f4460d00db898237603de311d226707a96Andy Huang * <ul> 1894c94d07f4460d00db898237603de311d226707a96Andy Huang * <li>the auto-advance setting is uninitialized and we need to wait for the user to set it</li> 1895c94d07f4460d00db898237603de311d226707a96Andy Huang * <li>auto-advance in this configuration requires a mode change, and we need to wait for the 1896c94d07f4460d00db898237603de311d226707a96Andy Huang * mode change transition to finish</li> 1897c94d07f4460d00db898237603de311d226707a96Andy Huang * </ul> 1898c94d07f4460d00db898237603de311d226707a96Andy Huang * <p>If the current conversation is not in the target collection, this method will do nothing, 1899c94d07f4460d00db898237603de311d226707a96Andy Huang * and will not execute the operation. 19000d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * 19010d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy * @param target the set of conversations being deleted/marked unread 1902c94d07f4460d00db898237603de311d226707a96Andy Huang * @param operation (optional) the operation to execute after advancing 1903c94d07f4460d00db898237603de311d226707a96Andy Huang * @return <code>false</code> if this method handled or will execute the operation, 1904c94d07f4460d00db898237603de311d226707a96Andy Huang * <code>true</code> otherwise. 19050d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy */ 19060d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy private boolean showNextConversation(final Collection<Conversation> target, 1907caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy final Runnable operation) { 190830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao if (isCurrentConversationInView(target)) { 19090d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy final int autoAdvanceSetting = mAccount.settings.getAutoAdvanceSetting(); 19100d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 191193e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler // If we don't have one set, but we're here, just take the default 191293e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler final int autoAdvance = (autoAdvanceSetting == AutoAdvance.UNSET) ? 191393e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler AutoAdvance.DEFAULT : autoAdvanceSetting; 19140d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 191593e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler final Conversation next = mTracker.getNextConversation(autoAdvance, target); 191693e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler LogUtils.d(LOG_TAG, "showNextConversation: showing %s next.", next); 191793e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler // Set mAutoAdvanceOp *before* showConversation() to ensure that it runs when the 191893e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler // transition doesn't run (i.e. it "completes" immediately). 191993e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler mAutoAdvanceOp = operation; 192093e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler showConversation(next); 192193e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler return (mAutoAdvanceOp == null); 19220d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy } 19230d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 192493e6457cf4391f1aff025808b536135b5bdbfe39Tony Mantler return true; 19258f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang } 19268f6b006357bf6c76e62fca899f594b2c674e8152Andy Huang 1927839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang @Override 1928839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang public void starMessage(ConversationMessage msg, boolean starred) { 1929839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang if (msg.starred == starred) { 1930839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang return; 1931839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1932839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 1933839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang msg.starred = starred; 1934839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 1935839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // locally propagate the change to the owning conversation 1936839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // (figure the provider will properly propagate the change when it commits it) 1937839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // 1938839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // when unstarring, only propagate the change if this was the only message starred 1939839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang final boolean conversationStarred = starred || msg.isConversationStarred(); 1940cd12e82dead8a920b060340c037d51b144966a73Andy Huang final Conversation conv = msg.getConversation(); 1941cd12e82dead8a920b060340c037d51b144966a73Andy Huang if (conversationStarred != conv.starred) { 1942cd12e82dead8a920b060340c037d51b144966a73Andy Huang conv.starred = conversationStarred; 1943cd12e82dead8a920b060340c037d51b144966a73Andy Huang mConversationListCursor.setConversationColumn(conv.uri, 1944839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang ConversationColumns.STARRED, conversationStarred); 1945839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1946839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 1947839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang final ContentValues values = new ContentValues(1); 1948839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang values.put(UIProvider.MessageColumns.STARRED, starred ? 1 : 0); 1949839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 1950839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang new ContentProviderTask.UpdateTask() { 1951839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang @Override 1952839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang protected void onPostExecute(Result result) { 1953839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang // TODO: handle errors? 1954839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1955839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang }.run(mResolver, msg.uri, values, null /* selection*/, null /* selectionArgs */); 1956839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang } 1957839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang 195812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang @Override 1959486e63e5bc7a88455e6fcb83d9cb251df203f727Alice Yang public void requestFolderRefresh() { 196037dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang if (mFolder == null) { 196137dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang return; 196237dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang } 196337dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang final ConversationListFragment convList = getConversationListFragment(); 196437dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang if (convList == null) { 196537dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang // This could happen if this account is in initial sync (user 196637dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang // is seeing the "your mail will appear shortly" message) 196737dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang return; 196837dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang } 196937dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang convList.showSyncStatusBar(); 19700d74a662f6e96b5a21e37978eb6e3b46545e3cbfAlice Yang 197137dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang if (mAsyncRefreshTask != null) { 197237dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang mAsyncRefreshTask.cancel(true); 197328e0c34ad35925fc74633bec66344911f2de6a22Mindy Pereira } 197437dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang mAsyncRefreshTask = new AsyncRefreshTask(mContext, mFolder.refreshUri); 197537dda440aaa245cef2d21d17babe951e1d449c4aAlice Yang mAsyncRefreshTask.execute(); 197628e0c34ad35925fc74633bec66344911f2de6a22Mindy Pereira } 197728e0c34ad35925fc74633bec66344911f2de6a22Mindy Pereira 1978fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira /** 1979fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira * Confirm (based on user's settings) and delete a conversation from the conversation list and 1980fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira * from the database. 1981b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal * @param actionId the ID of the menu item that caused the delete: R.id.delete, R.id.archive... 19823d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal * @param target the conversations to act upon 19833d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal * @param showDialog true if a confirmation dialog is to be shown, false otherwise. 19843d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal * @param confirmResource the resource ID of the string that is shown in the confirmation dialog 1985fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira */ 1986b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal private void confirmAndDelete(int actionId, final Collection<Conversation> target, 198730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao boolean showDialog, int confirmResource, UndoCallback undoCallback) { 198884fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal final boolean isBatch = false; 1989fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira if (showDialog) { 199030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao makeDialogListener(actionId, isBatch, undoCallback); 19913d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal final CharSequence message = Utils.formatPlural(mContext, confirmResource, 19923d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal target.size()); 1993b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal final ConfirmDialogFragment c = ConfirmDialogFragment.newInstance(message); 1994b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal c.displayDialog(mActivity.getFragmentManager()); 1995fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } else { 199630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao delete(0, target, getDeferredAction(actionId, target, isBatch, undoCallback), isBatch); 1997fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } 1998fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } 1999fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira 20004f4782bcc53e13b30f1fd417beb1a6c04a54faedVikram Aggarwal @Override 20010d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy public void delete(final int actionId, final Collection<Conversation> target, 2002caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy final DestructiveAction action, final boolean isBatch) { 200384f7d32bdc79263004ed5241480988e02f8e618cmindyp // Order of events is critical! The Conversation View Fragment must be 200484f7d32bdc79263004ed5241480988e02f8e618cmindyp // notified of the next conversation with showConversation(next) *before* the 200584f7d32bdc79263004ed5241480988e02f8e618cmindyp // conversation list 2006192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal // fragment has a chance to delete the conversation, animating it away. 2007192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal 200884f7d32bdc79263004ed5241480988e02f8e618cmindyp // Update the conversation fragment if the current conversation is 200984f7d32bdc79263004ed5241480988e02f8e618cmindyp // deleted. 20100d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy final Runnable operation = new Runnable() { 20110d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy @Override 20120d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy public void run() { 2013caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy delete(actionId, target, action, isBatch); 20140d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy } 20150d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy }; 20160d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy 2017caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy if (!showNextConversation(target, operation)) { 20180d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy // This method will be called again if the user selects an autoadvance option 20190d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy return; 20200d0f8b061faae060529af4da339eed2d728ef1bdScott Kennedy } 2021ab1b5b6d16800ff675116cdab33cf26ab3514732Vikram Aggarwal // If the conversation is in the selected set, remove it from the set. 202284fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal // Batch selections are cleared in the end of the action, so not done for batch actions. 202384fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal if (!isBatch) { 202484fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal for (final Conversation conv : target) { 202584fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal if (mSelectedSet.contains(conv)) { 202697ae7847b3a0eac8327b5f6300c854d1c9a19c3eVikram Aggarwal mSelectedSet.toggle(conv); 202784fe99431df3b989dff9b363562f09fd2757b63cVikram Aggarwal } 2028ab1b5b6d16800ff675116cdab33cf26ab3514732Vikram Aggarwal } 2029ab1b5b6d16800ff675116cdab33cf26ab3514732Vikram Aggarwal } 2030192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal // The conversation list deletes and performs the action if it exists. 2031192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal final ConversationListFragment convListFragment = getConversationListFragment(); 2032192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal if (convListFragment != null) { 2033193e05a8c38b87c400ac594b53b54eb211d35602Alice Yang LogUtils.i(LOG_TAG, "AAC.requestDelete: ListFragment is handling delete."); 2034669947bf67a3d0eed377b18099bb873604ad5009Vikram Aggarwal convListFragment.requestDelete(actionId, target, action); 2035192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal return; 2036192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal } 203784f7d32bdc79263004ed5241480988e02f8e618cmindyp // No visible UI element handled it on our behalf. Perform the action 203884f7d32bdc79263004ed5241480988e02f8e618cmindyp // ourself. 2039193e05a8c38b87c400ac594b53b54eb211d35602Alice Yang LogUtils.i(LOG_TAG, "ACC.requestDelete: performing remove action ourselves"); 2040d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal action.performAction(); 2041d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal } 2042d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal 2043d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal /** 2044d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal * Requests that the action be performed and the UI state is updated to reflect the new change. 2045715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param action the action to be performed, specified as a menu id: R.id.archive, ... 2046d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal */ 2047715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void requestUpdate(final DestructiveAction action) { 2048d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal action.performAction(); 2049d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal refreshConversationList(); 205075daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal } 20516fbc87affe46f6d49c584a307ec836e68163c182Vikram Aggarwal 20526fbc87affe46f6d49c584a307ec836e68163c182Vikram Aggarwal @Override 20531ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public void onPrepareDialog(int id, Dialog dialog, Bundle bundle) { 20541ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal // TODO(viki): Auto-generated method stub 20551ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 20561ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 20571ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 20581ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public boolean onPrepareOptionsMenu(Menu menu) { 20592d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein return mActionBarController.onPrepareOptionsMenu(menu); 2060a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 2061a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 206268f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira @Override 206368f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira public void onPause() { 2064c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal mHaveAccountList = false; 20656ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook enableNotifications(); 206694e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook } 206794e440d7fb9bb54ba4b22e348a2e22f3cf8e0167Paul Westbrook 2068a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 20691ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public void onResume() { 20706ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // Register the receiver that will prevent the status receiver from 20716ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // displaying its notification icon as long as we're running. 20726ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // The SupressNotificationReceiver will block the broadcast if we're looking at the folder 20736ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // that the notification was received for. 20746ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook disableNotifications(); 20751ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 20761ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang mSafeToModifyFragments = true; 2077ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein 2078ed5b52da9d2dd676c72a7137f6b85d9841fe6eecAndrew Sapperstein attachEmptyFolderDialogFragmentListener(); 207923e3313977d35d5caf152baf6cb27c9cc2d8ab91Andrew Sapperstein 208023e3313977d35d5caf152baf6cb27c9cc2d8ab91Andrew Sapperstein // Invalidating the options menu so that when we make changes in settings, 208123e3313977d35d5caf152baf6cb27c9cc2d8ab91Andrew Sapperstein // the changes will always be updated in the action bar/options menu/ 208223e3313977d35d5caf152baf6cb27c9cc2d8ab91Andrew Sapperstein mActivity.invalidateOptionsMenu(); 20831ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 20841ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 20851ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 2086a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal public void onSaveInstanceState(Bundle outState) { 2087649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal mViewMode.handleSaveInstanceState(outState); 20886c51158ad3269f157424e6c7bd488425c98da08fVikram Aggarwal if (mAccount != null) { 20896c51158ad3269f157424e6c7bd488425c98da08fVikram Aggarwal outState.putParcelable(SAVED_ACCOUNT, mAccount); 20906c51158ad3269f157424e6c7bd488425c98da08fVikram Aggarwal } 20915e478d2c4087b50764756b0edc95941cb6094f68Mindy Pereira if (mFolder != null) { 20925e478d2c4087b50764756b0edc95941cb6094f68Mindy Pereira outState.putParcelable(SAVED_FOLDER, mFolder); 20938b15263097bd9ce1a28db981b6a85261e6cb6886Vikram Aggarwal } 2094f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal // If this is a search activity, let's store the search query term as well. 2095f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal if (ConversationListContext.isSearchResult(mConvListContext)) { 2096f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal outState.putString(SAVED_QUERY, mConvListContext.searchQuery); 2097f3341405c97ff6d27a0d5fa37f6031e1c395d161Vikram Aggarwal } 209849e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal if (mCurrentConversation != null && mViewMode.isConversationMode()) { 209926f23fc8cc0d49bc0bea1eeec4c0c4742928f693Mindy Pereira outState.putParcelable(SAVED_CONVERSATION, mCurrentConversation); 210026f23fc8cc0d49bc0bea1eeec4c0c4742928f693Mindy Pereira } 21014556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang if (!mSelectedSet.isEmpty()) { 2102cabd3f227bf97159774e246ad278bb49d4aa2badVikram Aggarwal outState.putParcelable(SAVED_SELECTED_SET, mSelectedSet); 21034556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang } 2104d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira if (mToastBar.getVisibility() == View.VISIBLE) { 2105d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira outState.putParcelable(SAVED_TOAST_BAR_OP, mToastBar.getOperation()); 2106d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira } 2107649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal final ConversationListFragment convListFragment = getConversationListFragment(); 2108d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira if (convListFragment != null) { 2109649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal convListFragment.getAnimatedAdapter().onSaveInstanceState(outState); 2110d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira } 2111b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal // If there is a dialog being shown, save the state so we can create a listener for it. 21126cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal if (mDialogAction != -1) { 21136cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal outState.putInt(SAVED_ACTION, mDialogAction); 2114b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal outState.putBoolean(SAVED_ACTION_FROM_SELECTED, mDialogFromSelectedSet); 21156cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal } 2116a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal if (mDetachedConvUri != null) { 2117a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal outState.putParcelable(SAVED_DETACHED_CONV_URI, mDetachedConvUri); 2118a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 21195747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein 2120b10212ef23a4e2317fc43c62dff9ad177b5bcf2cScott Kennedy outState.putParcelable(SAVED_HIERARCHICAL_FOLDER, mFolderListFolder); 21215747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein mSafeToModifyFragments = false; 2122ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 2123ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang outState.putParcelable(SAVED_INBOX_KEY, mInbox); 2124f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy 2125f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy outState.putBundle(SAVED_CONVERSATION_LIST_SCROLL_POSITIONS, 2126f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy mConversationListScrollPositions); 21271ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 21281ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 21291ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang /** 21301ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * @see #mSafeToModifyFragments 21311ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang */ 21321ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang protected boolean safeToModifyFragments() { 21331ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang return mSafeToModifyFragments; 2134a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 2135a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 2136a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 2137313ac13095a386be366bd25f8106fbb34b4a7098Andy Huang public void executeSearch(String query) { 2138779dd6012a6c5b4d71255085059e57d94eab1a3fJin Cao AnalyticsTimer.getInstance().trackStart(AnalyticsTimer.SEARCH_TO_LIST); 213968f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira Intent intent = new Intent(); 214068f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira intent.setAction(Intent.ACTION_SEARCH); 214168f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira intent.putExtra(ConversationListContext.EXTRA_SEARCH_QUERY, query); 214268f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira intent.putExtra(Utils.EXTRA_ACCOUNT, mAccount); 214368f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira intent.setComponent(mActivity.getComponentName()); 21442d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.collapseSearch(); 2145371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // Call startActivityForResult here so we can tell if we have navigated to a different folder 2146371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon // or account from search results. 2147371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon mActivity.startActivityForResult(intent, CHANGE_NAVIGATION_REQUEST_CODE); 2148a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 2149a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 2150a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 21511ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public void onStop() { 2152cb85aeaf327e2c6a326457b5a395b4d6cdb70d63Scott Kennedy NotificationActionUtils.unregisterUndoNotificationObserver(mUndoNotificationObserver); 2153a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 2154a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 2155632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 2156632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void onDestroy() { 2157b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang // stop listening to the cursor on e.g. configuration changes 2158b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang if (mConversationListCursor != null) { 2159b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang mConversationListCursor.removeListener(this); 2160b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang } 2161144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang mDrawIdler.setListener(null); 2162144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang mDrawIdler.setRootView(null); 2163632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // unregister the ViewPager's observer on the conversation cursor 2164632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mPagerController.onDestroy(); 21652d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.onDestroy(); 21667c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal mRecentFolderList.destroy(); 21674e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang mDestroyed = true; 216859f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mHandler.removeCallbacks(mLogServiceChecker); 216959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal mLogServiceChecker = null; 2170632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2171632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2172fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal /** 217393dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal * Set the Action Bar icon according to the mode. The Action Bar icon can contain a back button 217493dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal * or not. The individual controller is responsible for changing the icon based on the mode. 217593dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal */ 217693dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal protected abstract void resetActionBarIcon(); 217793dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal 217893dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal /** 2179161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * {@inheritDoc} Subclasses must override this to listen to mode changes 2180161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * from the ViewMode. Subclasses <b>must</b> call the parent's 2181161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * onViewModeChanged since the parent will handle common state changes. 2182fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal */ 2183a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 2184fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal public void onViewModeChanged(int newMode) { 21851a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux // The floating action compose button is only visible in the conversation/search lists 21861a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux final int composeVisible = ViewMode.isListMode(newMode) ? View.VISIBLE : View.GONE; 21871a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux mFloatingComposeButton.setVisibility(composeVisible); 21881a1e9754cce66296ae730f2c483f55fcf1a24359James Lemieux 218949e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal // When we step away from the conversation mode, we don't have a current conversation 219049e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal // anymore. Let's blank it out so clients calling getCurrentConversation are not misled. 219149e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal if (!ViewMode.isConversationMode(newMode)) { 219249e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal setCurrentConversation(null); 219349e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal } 21946c570db71b8adc43d7dc2f31e6fa63cf50c1426eAndrew Sapperstein 219593dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal // If the viewmode is not set, preserve existing icon. 219693dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal if (newMode != ViewMode.UNKNOWN) { 219793dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal resetActionBarIcon(); 219893dc202420c3bf8adf4d9e8ae18c8e30e3cb1959Vikram Aggarwal } 219912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 220012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (isDrawerEnabled()) { 2201dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal /** If the folder doesn't exist, or its parent URI is empty, 2202dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal * this is not a child folder */ 22039695e0046f79bd2d7166a411d6feff4cf0fb2539Jin Cao final boolean isTopLevel = Folder.isRoot(mFolder); 2204dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal mDrawerToggle.setDrawerIndicatorEnabled( 2205dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal getShouldShowDrawerIndicator(newMode, isTopLevel)); 2206371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); 220712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang closeDrawerIfOpen(); 220812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 2209a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 2210a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 2211dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal /** 2212dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal * Returns true if the drawer icon is shown 2213dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal * @param viewMode the current view mode 2214dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal * @param isTopLevel true if the current folder is not a child 2215dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal * @return whether the drawer indicator is shown 2216dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal */ 221781b5fa063cb17ac7caf5622e83462151d03e0ecdScott Kennedy private boolean getShouldShowDrawerIndicator(final int viewMode, 2218dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal final boolean isTopLevel) { 2219dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal // If search list/conv mode: disable indicator 2220dfbc6985e44c05e37fd8addce65a063ff57a3dc1Vikram Aggarwal // Indicator is enabled either in conversation list or folder list mode. 222181b5fa063cb17ac7caf5622e83462151d03e0ecdScott Kennedy return isDrawerEnabled() && !ViewMode.isSearchMode(viewMode) 2222aded57845c51f128fc5dbd8e992697823775ce5aScott Kennedy && (viewMode == ViewMode.CONVERSATION_LIST && isTopLevel); 22238a72b8590d9166ada55f69eeb083d2b8c5c915c9Scott Kennedy } 22248a72b8590d9166ada55f69eeb083d2b8c5c915c9Scott Kennedy 22253825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang public void disablePagerUpdates() { 22263825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang mPagerController.stopListening(); 22273825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang } 22283825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang 22294e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang public boolean isDestroyed() { 22304e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang return mDestroyed; 22314e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang } 22324e0158f03fd8f430e88394e8b99e1b65ed01838aAndy Huang 223354f120f6ada40c7191811dfff99b151e9e192c78mindyp @Override 223454f120f6ada40c7191811dfff99b151e9e192c78mindyp public void commitDestructiveActions(boolean animate) { 2235c6adce3cf6887c4c6dd5005724565702751843d0mindyp ConversationListFragment fragment = getConversationListFragment(); 22361e2573bbba613fb700e8fa01c58c9382c0027b5eMindy Pereira if (fragment != null) { 2237c6adce3cf6887c4c6dd5005724565702751843d0mindyp fragment.commitDestructiveActions(animate); 22381e2573bbba613fb700e8fa01c58c9382c0027b5eMindy Pereira } 22391e2573bbba613fb700e8fa01c58c9382c0027b5eMindy Pereira } 22401e2573bbba613fb700e8fa01c58c9382c0027b5eMindy Pereira 2241a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal @Override 22421ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal public void onWindowFocusChanged(boolean hasFocus) { 224369b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal final ConversationListFragment convList = getConversationListFragment(); 22446422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal // hasFocus already ensures that the window is in focus, so we don't need to call 22456422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal // AAC.isFragmentVisible(convList) here. 22469f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook if (hasFocus && convList != null && convList.isVisible()) { 22479f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook // The conversation list is visible. 224869b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal informCursorVisiblity(true); 22499f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook } 2250a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 2251a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 2252ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal /** 2253ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal * Set the account, and carry out all the account-related changes that rely on this. 2254715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param account new account to set to. 2255ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal */ 225675181e846462659d1c9b919d0f1250e34647a280Mindy Pereira private void setAccount(Account account) { 2257b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang if (account == null) { 2258b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang LogUtils.w(LOG_TAG, new Error(), 2259b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang "AAC ignoring null (presumably invalid) account restoration"); 2260b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang return; 2261b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang } 2262b114841b6f2a91d92b8d0af4ec05ce81a5ba5599Andy Huang LogUtils.d(LOG_TAG, "AbstractActivityController.setAccount(): account = %s", account.uri); 226391e8737780f631a65633434447b0da864beb5baeVikram Aggarwal mAccount = account; 2264ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal // Only change AAC state here. Do *not* modify any other object's state. The object 2265ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal // should listen on account changes. 2266177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal restartOptionalLoader(LOADER_RECENT_FOLDERS, mFolderCallbacks, Bundle.EMPTY); 2267ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal mActivity.invalidateOptionsMenu(); 2268ca716f160fa033728fd4e60bcd13a4dc8693ee20Vikram Aggarwal disableNotificationsOnAccountChange(mAccount); 2269177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal restartOptionalLoader(LOADER_ACCOUNT_UPDATE_CURSOR, mAccountCallbacks, Bundle.EMPTY); 22702fe343f37226123e7cd5741d40be606dcf4edaabVikram Aggarwal // The Mail instance can be null during test runs. 22712fe343f37226123e7cd5741d40be606dcf4edaabVikram Aggarwal final MailAppProvider instance = MailAppProvider.getInstance(); 22722fe343f37226123e7cd5741d40be606dcf4edaabVikram Aggarwal if (instance != null) { 22732fe343f37226123e7cd5741d40be606dcf4edaabVikram Aggarwal instance.setLastViewedAccount(mAccount.uri.toString()); 22742fe343f37226123e7cd5741d40be606dcf4edaabVikram Aggarwal } 227591e8737780f631a65633434447b0da864beb5baeVikram Aggarwal if (account.settings == null) { 227691e8737780f631a65633434447b0da864beb5baeVikram Aggarwal LogUtils.w(LOG_TAG, new Error(), "AAC ignoring account with null settings."); 227791e8737780f631a65633434447b0da864beb5baeVikram Aggarwal return; 227891e8737780f631a65633434447b0da864beb5baeVikram Aggarwal } 22797c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal mAccountObservers.notifyChanged(); 228034f7b236154528e8632d1306f1250d52427b1036Vikram Aggarwal perhapsEnterWaitMode(); 228175181e846462659d1c9b919d0f1250e34647a280Mindy Pereira } 228275181e846462659d1c9b919d0f1250e34647a280Mindy Pereira 22831ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal /** 2284161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * Restore the state from the previous bundle. Subclasses should call this 2285161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * method from the parent class, since it performs important UI 2286161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * initialization. 2287161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * 2288715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param savedState previous state 22891ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal */ 2290632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 2291632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void onRestoreInstanceState(Bundle savedState) { 2292a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal mDetachedConvUri = savedState.getParcelable(SAVED_DETACHED_CONV_URI); 2293632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (savedState.containsKey(SAVED_CONVERSATION)) { 2294632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // Open the conversation. 22952bc8bc1f69faacaddab41ab61e1d2e8658f4181fAndy Huang final Conversation conversation = savedState.getParcelable(SAVED_CONVERSATION); 2296534e4a2175233b78a47bf0cd31ab8e4fc005ca71Paul Westbrook if (conversation != null && conversation.position < 0) { 2297534e4a2175233b78a47bf0cd31ab8e4fc005ca71Paul Westbrook // Set the position to 0 on this conversation, as we don't know where it is 2298534e4a2175233b78a47bf0cd31ab8e4fc005ca71Paul Westbrook // in the list 2299534e4a2175233b78a47bf0cd31ab8e4fc005ca71Paul Westbrook conversation.position = 0; 2300534e4a2175233b78a47bf0cd31ab8e4fc005ca71Paul Westbrook } 2301ed4fdf001005b0d17a1f3150366e8ba2dc0204a4Andy Huang showConversation(conversation); 2302632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2303632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2304d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira if (savedState.containsKey(SAVED_TOAST_BAR_OP)) { 23052bc8bc1f69faacaddab41ab61e1d2e8658f4181fAndy Huang ToastBarOperation op = savedState.getParcelable(SAVED_TOAST_BAR_OP); 2306d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira if (op != null) { 2307d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira if (op.getType() == ToastBarOperation.UNDO) { 2308d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira onUndoAvailable(op); 23099d7519d18e8ddbcdd59b37eec7c85210fca0e8c2Andrew Sapperstein } else if (op.getType() == ToastBarOperation.ERROR) { 23109d7519d18e8ddbcdd59b37eec7c85210fca0e8c2Andrew Sapperstein onError(mFolder, true); 2311d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira } 2312d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira } 2313d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira } 2314b10212ef23a4e2317fc43c62dff9ad177b5bcf2cScott Kennedy mFolderListFolder = savedState.getParcelable(SAVED_HIERARCHICAL_FOLDER); 2315649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal final ConversationListFragment convListFragment = getConversationListFragment(); 2316d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira if (convListFragment != null) { 2317649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal convListFragment.getAnimatedAdapter().onRestoreInstanceState(savedState); 2318d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira } 2319b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal /* 2320632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Restore the state of selected conversations. This needs to be done after the correct mode 2321632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * is set and the action bar is fully initialized. If not, several key pieces of state 2322632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * information will be missing, and the split views may not be initialized correctly. 2323632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang */ 2324632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang restoreSelectedConversations(savedState); 2325b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal // Order is important!!! 2326b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal // The dialog listener needs to happen *after* the selected set is restored. 2327b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal 2328b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal // If there has been an orientation change, and we need to recreate the listener for the 2329b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal // confirm dialog fragment (delete/archive/...), then do it here. 2330b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal if (mDialogAction != -1) { 233130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao makeDialogListener(mDialogAction, mDialogFromSelectedSet, 233230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao getUndoCallbackForDestructiveActionsWithAutoAdvance( 233330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mDialogAction, mCurrentConversation)); 2334b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal } 2335ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 2336ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang mInbox = savedState.getParcelable(SAVED_INBOX_KEY); 2337f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy 2338f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy mConversationListScrollPositions.clear(); 2339f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy mConversationListScrollPositions.putAll( 2340f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy savedState.getBundle(SAVED_CONVERSATION_LIST_SCROLL_POSITIONS)); 2341632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2342632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2343649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal /** 2344649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal * Handle an intent to open the app. This method is called only when there is no saved state, 2345649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal * so we need to set state that wasn't set before. It is correct to change the viewmode here 2346649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal * since it has not been previously set. 23476aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * 23486aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * This method is called for a subset of the reasons mentioned in 23496aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * {@link #onCreate(android.os.Bundle)}. Notably, this is called when launching the app from 23506aca689261cf43e16534e320dc4a34cadf31c41bVikram Aggarwal * notifications, widgets, and shortcuts. 2351715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param intent intent passed to the activity. 2352649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal */ 2353632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private void handleIntent(Intent intent) { 2354e6459424b3e46d768865c908af1caa932f783095Andy Huang LogUtils.d(LOG_TAG, "IN AAC.handleIntent. action=%s", intent.getAction()); 2355632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (Intent.ACTION_VIEW.equals(intent.getAction())) { 2356632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (intent.hasExtra(Utils.EXTRA_ACCOUNT)) { 235726a20758413f0f8629ea71a0943304e3ae740165Tony Mantler setAccount(Account.newInstance(intent.getStringExtra(Utils.EXTRA_ACCOUNT))); 2358632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2359b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang if (mAccount == null) { 2360b9ca979fb93cc14246b449a2c02dc615c9e0cdd9Andy Huang return; 23615e478d2c4087b50764756b0edc95941cb6094f68Mindy Pereira } 23621a249e094e961f463ff392390d591a1d37106e69Vikram Aggarwal final boolean isConversationMode = intent.hasExtra(Utils.EXTRA_CONVERSATION); 23634fe0af81874976a1995191321e35c844b2229811Andy Huang 23644fe0af81874976a1995191321e35c844b2229811Andy Huang if (intent.getBooleanExtra(Utils.EXTRA_FROM_NOTIFICATION, false)) { 23654fe0af81874976a1995191321e35c844b2229811Andy Huang Analytics.getInstance().setCustomDimension(Analytics.CD_INDEX_ACCOUNT_TYPE, 236679b1156803585952a4851221dc9fa9974e606433Tony Mantler AnalyticsUtils.getAccountTypeForAccount(mAccount.getEmailAddress())); 23674fe0af81874976a1995191321e35c844b2229811Andy Huang Analytics.getInstance().sendEvent("notification_click", 23684fe0af81874976a1995191321e35c844b2229811Andy Huang isConversationMode ? "conversation" : "conversation_list", null, 0); 23694fe0af81874976a1995191321e35c844b2229811Andy Huang } 23704fe0af81874976a1995191321e35c844b2229811Andy Huang 2371649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal if (isConversationMode && mViewMode.getMode() == ViewMode.UNKNOWN) { 23721a249e094e961f463ff392390d591a1d37106e69Vikram Aggarwal mViewMode.enterConversationMode(); 23731a249e094e961f463ff392390d591a1d37106e69Vikram Aggarwal } else { 23741a249e094e961f463ff392390d591a1d37106e69Vikram Aggarwal mViewMode.enterConversationListMode(); 23751a249e094e961f463ff392390d591a1d37106e69Vikram Aggarwal } 2376177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Put the folder and conversation, and ask the loader to create this folder. 2377177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Bundle args = new Bundle(); 237848cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy 237948cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy final Uri folderUri; 238048cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy if (intent.hasExtra(Utils.EXTRA_FOLDER_URI)) { 23815bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein folderUri = intent.getParcelableExtra(Utils.EXTRA_FOLDER_URI); 238248cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy } else if (intent.hasExtra(Utils.EXTRA_FOLDER)) { 238348cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy final Folder folder = 238448cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy Folder.fromString(intent.getStringExtra(Utils.EXTRA_FOLDER)); 2385259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy folderUri = folder.folderUri.fullUri; 238648cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy } else { 238772727efe0bac563c72c208737c381296c35f94a9Scott Kennedy final Bundle extras = intent.getExtras(); 238872727efe0bac563c72c208737c381296c35f94a9Scott Kennedy LogUtils.d(LOG_TAG, "Couldn't find a folder URI in the extras: %s", 238972727efe0bac563c72c208737c381296c35f94a9Scott Kennedy extras == null ? "null" : extras.toString()); 239048cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy folderUri = mAccount.settings.defaultInbox; 239148cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy } 239248cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy 23935bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein // Check if we should load all conversations instead of using 23945bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein // the default behavior which loads an initial subset. 23955bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein mIgnoreInitialConversationLimit = 23965bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein intent.getBooleanExtra(Utils.EXTRA_IGNORE_INITIAL_CONVERSATION_LIMIT, false); 23975bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein 239860593354f1126b9687d09c3b11a852a3459f7118Scott Kennedy args.putParcelable(Utils.EXTRA_FOLDER_URI, folderUri); 2399177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal args.putParcelable(Utils.EXTRA_CONVERSATION, 2400177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal intent.getParcelableExtra(Utils.EXTRA_CONVERSATION)); 2401177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal restartOptionalLoader(LOADER_FIRST_FOLDER, mFolderCallbacks, args); 2402632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } else if (Intent.ACTION_SEARCH.equals(intent.getAction())) { 2403632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (intent.hasExtra(Utils.EXTRA_ACCOUNT)) { 2404f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal mHaveSearchResults = false; 2405632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // Save this search query for future suggestions. 2406632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final String query = intent.getStringExtra(SearchManager.QUERY); 2407632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final String authority = mContext.getString(R.string.suggestions_authority); 24082b703c6c71a369485efc8ade26d449d25669ceecVikram Aggarwal final SearchRecentSuggestions suggestions = new SearchRecentSuggestions( 2409632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mContext, authority, SuggestionsProvider.MODE); 2410632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang suggestions.saveRecentQuery(query, null); 2411f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal setAccount((Account) intent.getParcelableExtra(Utils.EXTRA_ACCOUNT)); 2412f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal fetchSearchFolder(intent); 2413f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal if (shouldEnterSearchConvMode()) { 2414ac2548293e93c14b1d14e6de53328c561ba1cca6Mindy Pereira mViewMode.enterSearchResultsConversationMode(); 2415ac2548293e93c14b1d14e6de53328c561ba1cca6Mindy Pereira } else { 2416ac2548293e93c14b1d14e6de53328c561ba1cca6Mindy Pereira mViewMode.enterSearchResultsListMode(); 2417ac2548293e93c14b1d14e6de53328c561ba1cca6Mindy Pereira } 2418632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } else { 2419632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.e(LOG_TAG, "Missing account extra from search intent. Finishing"); 2420632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mActivity.finish(); 24212d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 24221ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 2423632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (mAccount != null) { 2424177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal restartOptionalLoader(LOADER_ACCOUNT_UPDATE_CURSOR, mAccountCallbacks, Bundle.EMPTY); 2425b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy } 2426b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy } 2427b39aaf53a555c1046ef31b3fecf15d086acca013Scott Kennedy 24284556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang /** 2429f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal * Returns true if we should enter conversation mode with search. 2430f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal */ 2431f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal protected final boolean shouldEnterSearchConvMode() { 2432f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal return mHaveSearchResults && Utils.showTwoPaneSearchResults(mActivity.getActivityContext()); 2433f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal } 2434f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal 2435f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal /** 24364556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang * Copy any selected conversations stored in the saved bundle into our selection set, 24374556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang * triggering {@link ConversationSetObserver} callbacks as our selection set changes. 24384556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang * 24394556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang */ 2440715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void restoreSelectedConversations(Bundle savedState) { 2441967ede63e059810d9d4d425c50111d606014c893Mindy Pereira if (savedState == null) { 24424556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang mSelectedSet.clear(); 2443967ede63e059810d9d4d425c50111d606014c893Mindy Pereira return; 2444967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 2445cabd3f227bf97159774e246ad278bb49d4aa2badVikram Aggarwal final ConversationSelectionSet selectedSet = savedState.getParcelable(SAVED_SELECTED_SET); 24464556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang if (selectedSet == null || selectedSet.isEmpty()) { 24474556a44bef944b90e140d2ba67cc723e0ad5da3aAndy Huang mSelectedSet.clear(); 2448967ede63e059810d9d4d425c50111d606014c893Mindy Pereira return; 2449967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 2450632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2451632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // putAll will take care of calling our registered onSetPopulated method 2452cabd3f227bf97159774e246ad278bb49d4aa2badVikram Aggarwal mSelectedSet.putAll(selectedSet); 2453967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 2454967ede63e059810d9d4d425c50111d606014c893Mindy Pereira 2455ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal /** 245649e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * Show the conversation provided in the arguments. It is safe to pass a null conversation 245749e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * object, which is a signal to back out of conversation view mode. 245849e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal * Child classes must call super.showConversation() <b>before</b> their own implementations. 245959f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal * @param conversation the conversation to be shown, or null if we want to back out to list 246059f741f60e389818a9a56b1fba46eea1c372690dVikram Aggarwal * mode. 2461177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal * onLoadFinished(Loader, Cursor) on any callback. 2462ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal */ 246330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao protected void showConversation(Conversation conversation) { 2464d23f6d1cd1dd8248cba755bf91c5355a31fbb885Jin Cao showConversation(conversation, true /* markAsRead */); 2465d23f6d1cd1dd8248cba755bf91c5355a31fbb885Jin Cao } 2466d23f6d1cd1dd8248cba755bf91c5355a31fbb885Jin Cao 2467d23f6d1cd1dd8248cba755bf91c5355a31fbb885Jin Cao protected void showConversation(Conversation conversation, boolean markAsRead) { 2468243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang if (conversation != null) { 2469243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang Utils.sConvLoadTimer.start(); 2470243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang } 2471243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang 247254e925ec6eb14bf711af563e8e40979f07f17a68Andy Huang MailLogService.log("AbstractActivityController", "showConversation(%s)", conversation); 2473c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal // Set the current conversation just in case it wasn't already set. 2474c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal setCurrentConversation(conversation); 2475ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal } 2476ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal 2477e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal /** 24782d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook * Children can override this method, but they must call super.showWaitForInitialization(). 24792d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook * {@inheritDoc} 24802d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook */ 24812d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook @Override 24822d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook public void showWaitForInitialization() { 24832d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook mViewMode.enterWaitingForInitializationMode(); 2484c96efcc4a2f65b11a9b2057320ca828ee80f32ffAndy Huang mWaitFragment = WaitFragment.newInstance(mAccount, true /* expectingMessages */); 24852d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 24862d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook 2487dd6a7ce32c4003bd0941e2f18fcf5b80b5cd43c5Vikram Aggarwal private void updateWaitMode() { 24882d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook final FragmentManager manager = mActivity.getFragmentManager(); 24892d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook final WaitFragment waitFragment = 24906902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal (WaitFragment)manager.findFragmentByTag(TAG_WAIT); 24912d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook if (waitFragment != null) { 24922d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook waitFragment.updateAccount(mAccount); 24932d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 24942d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 24952d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook 2496a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal /** 2497a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal * Remove the "Waiting for Initialization" fragment. Child classes are free to override this 2498a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal * method, though they must call the parent implementation <b>after</b> they do anything. 2499a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal */ 2500a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal protected void hideWaitForInitialization() { 2501a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal mWaitFragment = null; 2502a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal } 2503a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal 2504a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal /** 2505a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal * Use the instance variable and the wait fragment's tag to get the wait fragment. This is 2506a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal * far superior to using the value of mWaitFragment, which might be invalid or might refer 2507a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal * to a fragment after it has been destroyed. 2508715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @return a wait fragment that is already attached to the activity, if one exists 2509a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal */ 2510a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal protected final WaitFragment getWaitFragment() { 2511a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal final FragmentManager manager = mActivity.getFragmentManager(); 2512a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal final WaitFragment waitFrag = (WaitFragment) manager.findFragmentByTag(TAG_WAIT); 2513a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal if (waitFrag != null) { 2514a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal // The Fragment Manager knows better, so use its instance. 2515a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal mWaitFragment = waitFrag; 2516a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal } 2517a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal return mWaitFragment; 2518a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal } 2519dd6a7ce32c4003bd0941e2f18fcf5b80b5cd43c5Vikram Aggarwal 252048b2a6c5fe209f0603fdf85d35cf399f7f7d462eVikram Aggarwal /** 252148b2a6c5fe209f0603fdf85d35cf399f7f7d462eVikram Aggarwal * Returns true if we are waiting for the account to sync, and cannot show any folders or 252248b2a6c5fe209f0603fdf85d35cf399f7f7d462eVikram Aggarwal * conversation for the current account yet. 252348b2a6c5fe209f0603fdf85d35cf399f7f7d462eVikram Aggarwal */ 2524dd6a7ce32c4003bd0941e2f18fcf5b80b5cd43c5Vikram Aggarwal private boolean inWaitMode() { 2525a3f43d4c2423ab03bdae925042fe8440b7f70025Vikram Aggarwal final WaitFragment waitFragment = getWaitFragment(); 25262d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook if (waitFragment != null) { 25272d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook final Account fragmentAccount = waitFragment.getAccount(); 2528339004b1d81b34682ef56f6ea0b3b9fccc133753Paul Westbrook return fragmentAccount != null && fragmentAccount.uri.equals(mAccount.uri) && 25292d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook mViewMode.getMode() == ViewMode.WAITING_FOR_ACCOUNT_INITIALIZATION; 25302d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 25312d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook return false; 25322d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 25332d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook 25342d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook /** 2535e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal * Children can override this method, but they must call super.showConversationList(). 2536e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal * {@inheritDoc} 2537e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal */ 2538e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal @Override 2539e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal public void showConversationList(ConversationListContext listContext) { 2540e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal } 2541e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal 25421ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 25430b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao public void onConversationSelected(Conversation conversation, boolean inLoaderCallbacks) { 2544fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang final ConversationListFragment convListFragment = getConversationListFragment(); 2545fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang if (convListFragment != null && convListFragment.getAnimatedAdapter() != null) { 2546fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang convListFragment.getAnimatedAdapter().onConversationSelected(); 2547fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang } 2548aa55bc9cb210a46a950874f368baa07f041a4302mindyp // Only animate destructive actions if we are going to be showing the 2549aa55bc9cb210a46a950874f368baa07f041a4302mindyp // conversation list when we show the next conversation. 2550bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal commitDestructiveActions(mIsTablet); 255130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao showConversation(conversation); 25521ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 25531ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 25541ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang @Override 25552f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein public final void onCabModeEntered() { 25562f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein final ConversationListFragment convListFragment = getConversationListFragment(); 25572f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein if (convListFragment != null && convListFragment.getAnimatedAdapter() != null) { 25582f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein convListFragment.getAnimatedAdapter().onCabModeEntered(); 25592f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein } 25602f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein } 25612f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein 25622f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein @Override 2563cc139833bc5829ba70244519e9870de783c41848Scott Kennedy public final void onCabModeExited() { 2564cc139833bc5829ba70244519e9870de783c41848Scott Kennedy final ConversationListFragment convListFragment = getConversationListFragment(); 2565cc139833bc5829ba70244519e9870de783c41848Scott Kennedy if (convListFragment != null && convListFragment.getAnimatedAdapter() != null) { 2566cc139833bc5829ba70244519e9870de783c41848Scott Kennedy convListFragment.getAnimatedAdapter().onCabModeExited(); 2567cc139833bc5829ba70244519e9870de783c41848Scott Kennedy } 2568cc139833bc5829ba70244519e9870de783c41848Scott Kennedy } 2569cc139833bc5829ba70244519e9870de783c41848Scott Kennedy 2570cc139833bc5829ba70244519e9870de783c41848Scott Kennedy @Override 25711ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang public Conversation getCurrentConversation() { 25721ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang return mCurrentConversation; 25737d602884ed70d07a42f1adf999fdf51b258f23f9Vikram Aggarwal } 2574555140c7b7d5129fb2b17df66106cbd6eeef37a0Mindy Pereira 2575c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal /** 2576c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal * Set the current conversation. This is the conversation on which all actions are performed. 2577c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal * Do not modify mCurrentConversation except through this method, which makes it easy to 2578c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal * perform common actions associated with changing the current conversation. 2579715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param conversation new conversation to view. Passing null indicates that we are backing 2580715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * out to conversation list mode. 2581c67182dfb4884e92262a2365ecfcc5d254c7999cVikram Aggarwal */ 2582632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 2583632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void setCurrentConversation(Conversation conversation) { 2584a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // The controller should come out of detached mode if a new conversation is viewed, or if 258581230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal // we are going back to conversation list mode. 258681230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal if (mDetachedConvUri != null && (conversation == null 258781230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal || !mDetachedConvUri.equals(conversation.uri))) { 2588a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal clearDetachedMode(); 2589a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 2590a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal 2591a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // Must happen *before* setting mCurrentConversation because this sets 2592a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // conversation.position if a cursor is available. 25938883f228890572a8d85d06b1e0bf08c65bd42db4Andy Huang mTracker.initialize(conversation); 259417f373ecf6961112f77a7516ab1bbcb4fcdf2884Vikram Aggarwal mCurrentConversation = conversation; 25957d64612104fd861474a09994f13768360f92041dAndy Huang 25967d64612104fd861474a09994f13768360f92041dAndy Huang if (mCurrentConversation != null) { 25972d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.setCurrentConversation(mCurrentConversation); 2598f807ba7ac1011f7fd1e0d382dcc0518ba3529810Yorke Lee mActivity.invalidateOptionsMenu(); 25997d64612104fd861474a09994f13768360f92041dAndy Huang } 26005040f1a73e3c5684901d8a9e2e30a5d58286509fMindy Pereira } 26015040f1a73e3c5684901d8a9e2e30a5d58286509fMindy Pereira 2602a9b93f35035dc4badd0ac40f4016e1ff809b26b0Vikram Aggarwal /** 2603f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * {@link LoaderManager} currently has a bug in 2604f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * {@link LoaderManager#restartLoader(int, Bundle, android.app.LoaderManager.LoaderCallbacks)} 2605f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * where, if a previous onCreateLoader returned a null loader, this method will NPE. Work around 2606f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * this bug by destroying any loaders that may have been created as null (essentially because 2607f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * they are optional loads, and may not apply to a particular account). 2608f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * <p> 2609f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * A simple null check before restarting a loader will not work, because that would not 2610f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * give the controller a chance to invalidate UI corresponding the prior loader result. 2611f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * 2612f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang * @param id loader ID to safely restart 2613177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal * @param handler the LoaderCallback which will handle this loader ID. 2614177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal * @param args arguments, if any, to be passed to the loader. Use {@link Bundle#EMPTY} if no 2615177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal * arguments need to be specified. 2616f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang */ 2617177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private void restartOptionalLoader(int id, LoaderManager.LoaderCallbacks handler, Bundle args) { 2618f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang final LoaderManager lm = mActivity.getLoaderManager(); 2619f9a7348ff7eddd83527e1cf7badf3801d90c77c7Andy Huang lm.destroyLoader(id); 2620177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal lm.restartLoader(id, args, handler); 262194c94de8f36698be849da8f103387e7e4d744d42Vikram Aggarwal } 262294c94de8f36698be849da8f103387e7e4d744d42Vikram Aggarwal 2623632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 2624632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void registerConversationListObserver(DataSetObserver observer) { 2625632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mConversationListObservable.registerObserver(observer); 2626632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2627632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2628632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 2629632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void unregisterConversationListObserver(DataSetObserver observer) { 2630647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang try { 2631647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang mConversationListObservable.unregisterObserver(observer); 2632647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang } catch (IllegalStateException e) { 2633647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang // Log instead of crash 2634647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang LogUtils.e(LOG_TAG, e, "unregisterConversationListObserver called for an observer that " 2635647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang + "hasn't been registered"); 2636647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang } 2637632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2638632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2639090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang @Override 2640090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang public void registerFolderObserver(DataSetObserver observer) { 2641090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang mFolderObservable.registerObserver(observer); 2642090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 2643090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang 2644090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang @Override 2645090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang public void unregisterFolderObserver(DataSetObserver observer) { 2646647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang try { 2647647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang mFolderObservable.unregisterObserver(observer); 2648647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang } catch (IllegalStateException e) { 2649647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang // Log instead of crash 2650647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang LogUtils.e(LOG_TAG, e, "unregisterFolderObserver called for an observer that " 2651647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang + "hasn't been registered"); 2652647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang } 2653090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 2654090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang 26559d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang @Override 26569d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang public void registerConversationLoadedObserver(DataSetObserver observer) { 26579d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang mPagerController.registerConversationLoadedObserver(observer); 26589d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang } 26599d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang 26609d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang @Override 26619d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang public void unregisterConversationLoadedObserver(DataSetObserver observer) { 2662647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang try { 2663647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang mPagerController.unregisterConversationLoadedObserver(observer); 2664647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang } catch (IllegalStateException e) { 2665647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang // Log instead of crash 2666647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang LogUtils.e(LOG_TAG, e, "unregisterConversationLoadedObserver called for an observer " 2667647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang + "that hasn't been registered"); 2668647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang } 26699d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang } 26709d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang 26716006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal /** 2672c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal * Returns true if the number of accounts is different, or if the current account has 2673c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal * changed. This method is meant to filter frequent changes to the list of 2674c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal * accounts, and only return true if the new list is substantially different from the existing 2675c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal * list. Returning true is safe here, it leads to more work in creating the 2676c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal * same account list again. 2677715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param accountCursor the cursor which points to all the accounts. 2678715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @return true if the number of accounts is changed or current account missing from the list. 26796006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal */ 2680177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private boolean accountsUpdated(ObjectCursor<Account> accountCursor) { 268123b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook // Check to see if the current account hasn't been set, or the account cursor is empty 268223b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook if (mAccount == null || !accountCursor.moveToFirst()) { 26836c51158ad3269f157424e6c7bd488425c98da08fVikram Aggarwal return true; 268423b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } 268523b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 268623b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook // Check to see if the number of accounts are different, from the number we saw on the last 268723b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook // updated 268823b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook if (mCurrentAccountUris.size() != accountCursor.getCount()) { 268923b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook return true; 269023b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } 269123b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 269223b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook // Check to see if the account list is different or if the current account is not found in 269323b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook // the cursor. 269423b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook boolean foundCurrentAccount = false; 26957dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal do { 2696c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal final Account account = accountCursor.getModel(); 2697c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal if (!foundCurrentAccount && mAccount.uri.equals(account.uri)) { 2698c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal if (mAccount.settingsDiffer(account)) { 2699c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal // Settings changed, and we don't need to look any further. 2700c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal return true; 2701c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal } 270223b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook foundCurrentAccount = true; 270323b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } 27046006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // Is there a new account that we do not know about? 2705c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal if (!mCurrentAccountUris.contains(account.uri)) { 270623b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook return true; 270723b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } 27087dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal } while (accountCursor.moveToNext()); 270923b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 271023b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook // As long as we found the current account, the list hasn't been updated 271123b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook return !foundCurrentAccount; 27127dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal } 27137dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal 27147dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal /** 27156006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal * Updates accounts for the app. If the current account is missing, the first 27166006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal * account in the list is set to the current account (we <em>have</em> to choose something). 2717161f50d0fabdaa384a63ce69f595861c5e69795fMindy Pereira * 27186c51158ad3269f157424e6c7bd488425c98da08fVikram Aggarwal * @param accounts cursor into the AccountCache 27197dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal * @return true if the update was successful, false otherwise 27207dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal */ 2721177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private boolean updateAccounts(ObjectCursor<Account> accounts) { 27227dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal if (accounts == null || !accounts.moveToFirst()) { 27237dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal return false; 27247dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal } 272523b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 2726a9b93f35035dc4badd0ac40f4016e1ff809b26b0Vikram Aggarwal final Account[] allAccounts = Account.getAllAccounts(accounts); 27276006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // A match for the current account's URI in the list of accounts. 27286006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal Account currentFromList = null; 272923b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 2730636c1a1bf144e28a8a1ab022dfcfba83c7b1ca1bVikram Aggarwal // Save the uris for the accounts and find the current account in the updated cursor. 273123b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook mCurrentAccountUris.clear(); 2732636c1a1bf144e28a8a1ab022dfcfba83c7b1ca1bVikram Aggarwal for (final Account account : allAccounts) { 27336006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal LogUtils.d(LOG_TAG, "updateAccounts(%s)", account); 273423b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook mCurrentAccountUris.add(account.uri); 27356006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (mAccount != null && account.uri.equals(mAccount.uri)) { 27366006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal currentFromList = account; 27376006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal } 273823b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } 273923b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook 27406006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // 1. current account is already set and is in allAccounts: 27416006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // 1a. It has changed -> load the updated account. 27426006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // 2b. It is unchanged -> no-op 27430d647354209f4bf57cffa35f008e09853977b189Andy Huang // 2. current account is set and is not in allAccounts -> pick first (acct was deleted?) 27446006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // 3. saved preference has an account -> pick that one 27450d647354209f4bf57cffa35f008e09853977b189Andy Huang // 4. otherwise just pick first 27460d647354209f4bf57cffa35f008e09853977b189Andy Huang 27476006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal boolean accountChanged = false; 27486006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal /// Assume case 4, initialize to first account, and see if we can find anything better. 27496006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal Account newAccount = allAccounts[0]; 27506006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (currentFromList != null) { 27516006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // Case 1: Current account exists but has changed 27526006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (!currentFromList.equals(mAccount)) { 27536006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal newAccount = currentFromList; 27546006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal accountChanged = true; 27550d647354209f4bf57cffa35f008e09853977b189Andy Huang } 27566006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // Case 1b: else, current account is unchanged: nothing to do. 275723b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } else { 27586006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // Case 2: Current account is not in allAccounts, the account needs to change. 27596006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal accountChanged = true; 27606006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (mAccount == null) { 27616006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // Case 3: Check for last viewed account, and check if it exists in the list. 27626006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal final String lastAccountUri = MailAppProvider.getInstance().getLastViewedAccount(); 27636006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (lastAccountUri != null) { 27646006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal for (final Account account : allAccounts) { 27656006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (lastAccountUri.equals(account.uri.toString())) { 27666006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal newAccount = account; 27676006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal break; 27686006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal } 27690d647354209f4bf57cffa35f008e09853977b189Andy Huang } 27700d647354209f4bf57cffa35f008e09853977b189Andy Huang } 27710d647354209f4bf57cffa35f008e09853977b189Andy Huang } 277223b74b988a4f79a5dfc9e6f8c6e9d3b7d2a2ae27Paul Westbrook } 27736006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal if (accountChanged) { 27745fd8afd5c1b40580c069a5a97039ca0601208216Vikram Aggarwal changeAccount(newAccount); 27756006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal } 277607dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal 27776006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // Whether we have updated the current account or not, we need to update the list of 27786006991395131d7d1db4f883ff8c7a87498b6eecVikram Aggarwal // accounts in the ActionBar. 2779b905f0ea18ee0dc5774adb29c57cd7c122058c71Rohan Shah mAllAccounts = allAccounts; 278007dbaa6989ea5c63ecf79b5ce7ec3a6a18a1ff35Vikram Aggarwal mAllAccountObservers.notifyChanged(); 2781a9b93f35035dc4badd0ac40f4016e1ff809b26b0Vikram Aggarwal return (allAccounts.length > 0); 27827dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal } 27837dedb952c8bb9c7b50f25444a42047d903e5121bVikram Aggarwal 27846ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook private void disableNotifications() { 27856ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook mNewEmailReceiver.activate(mContext, this); 27866ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook } 27876ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook 27886ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook private void enableNotifications() { 27896ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook mNewEmailReceiver.deactivate(); 27906ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook } 27916ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook 27926ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook private void disableNotificationsOnAccountChange(Account account) { 27936ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // If the new mail suppression receiver is activated for a different account, we want to 27946ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // activate it for the new account. 27956ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook if (mNewEmailReceiver.activated() && 27966ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook !mNewEmailReceiver.notificationsDisabledForAccount(account)) { 27976ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook // Deactivate the current receiver, otherwise multiple receivers may be registered. 27986ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook mNewEmailReceiver.deactivate(); 27996ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook mNewEmailReceiver.activate(mContext, this); 28006ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook } 28016ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook } 28026ead20dd9643e6435d6c1111f99c520870812ea8Paul Westbrook 2803a9b93f35035dc4badd0ac40f4016e1ff809b26b0Vikram Aggarwal /** 2804c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal * Destructive actions on Conversations. This class should only be created by controllers, and 2805c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal * clients should only require {@link DestructiveAction}s, not specific implementations of the. 2806c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal * Only the controllers should know what kind of destructive actions are being created. 2807c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal */ 2808de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira public class ConversationAction implements DestructiveAction { 2809acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal /** 2810acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal * The action to be performed. This is specified as the resource ID of the menu item 2811acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal * corresponding to this action: R.id.delete, R.id.report_spam, etc. 2812acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal */ 28137f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal private final int mAction; 2814bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal /** The action will act upon these conversations */ 281577eee625cd8c317c605acfd06cd3a7e22120a0fdPaul Westbrook private final Collection<Conversation> mTarget; 28167f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal /** Whether this destructive action has already been performed */ 28177f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal private boolean mCompleted; 2818c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal /** Whether this is an action on the currently selected set. */ 2819c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal private final boolean mIsSelectedSet; 2820e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal 282130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao private UndoCallback mCallback; 282230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 2823fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira /** 2824715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * Create a listener object. 2825715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param action action is one of four constants: R.id.y_button (archive), 2826fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira * R.id.delete , R.id.mute, and R.id.report_spam. 2827bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal * @param target Conversation that we want to apply the action to. 2828c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal * @param isBatch whether the conversations are in the currently selected batch set. 2829c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal */ 2830c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal public ConversationAction(int action, Collection<Conversation> target, boolean isBatch) { 2831fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira mAction = action; 283277eee625cd8c317c605acfd06cd3a7e22120a0fdPaul Westbrook mTarget = ImmutableList.copyOf(target); 2833c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal mIsSelectedSet = isBatch; 2834fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } 2835fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira 283630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao @Override 283730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public void setUndoCallback(UndoCallback undoCallback) { 283830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mCallback = undoCallback; 283930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 284030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 2841acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal /** 2842acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal * The action common to child classes. This performs the action specified in the constructor 2843acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal * on the conversations given here. 2844acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal */ 2845bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal @Override 2846bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal public void performAction() { 28477f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal if (isPerformed()) { 28487f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal return; 28497f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal } 28503cb28b5e1598f74dedbdb87b187d9bd7e132ff0fMindy Pereira boolean undoEnabled = mAccount.supportsCapability(AccountCapabilities.UNDO); 28517dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal 28527dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal // Are we destroying the currently shown conversation? Show the next one. 28537dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)){ 28548742a614a238c5ae55d767461000d0a10d1da4d4Vikram Aggarwal LogUtils.d(LOG_TAG, "ConversationAction.performAction():" 28558742a614a238c5ae55d767461000d0a10d1da4d4Vikram Aggarwal + "\nmTarget=%s\nCurrent=%s", 28567dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal Conversation.toString(mTarget), mCurrentConversation); 28577dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal } 28587dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal 2859e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook if (mConversationListCursor == null) { 2860e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook LogUtils.e(LOG_TAG, "null ConversationCursor in ConversationAction.performAction():" 2861e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook + "\nmTarget=%s\nCurrent=%s", 2862e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook Conversation.toString(mTarget), mCurrentConversation); 2863e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook return; 2864e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook } 2865e1221d2807826e2ee272df81c271a0f444522890Paul Westbrook 28662b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mAction == R.id.archive) { 28672b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Archiving"); 286830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mConversationListCursor.archive(mTarget, mCallback); 28692b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.delete) { 28702b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Deleting"); 287130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mConversationListCursor.delete(mTarget, mCallback); 28722b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mFolder.supportsCapability(FolderCapabilities.DELETE_ACTION_FINAL)) { 28732b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy undoEnabled = false; 28742b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 28752b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.mute) { 28762b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Muting"); 28772b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mFolder.supportsCapability(FolderCapabilities.DESTRUCTIVE_MUTE)) { 28782b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy for (Conversation c : mTarget) { 28792b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy c.localDeleteOnUpdate = true; 2880bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal } 28812b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 288230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mConversationListCursor.mute(mTarget, mCallback); 28832b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.report_spam) { 28842b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Reporting spam"); 288530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mConversationListCursor.reportSpam(mTarget, mCallback); 28862b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.mark_not_spam) { 28872b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Marking not spam"); 288830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mConversationListCursor.reportNotSpam(mTarget, mCallback); 28892b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.report_phishing) { 28902b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Reporting phishing"); 289130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mConversationListCursor.reportPhishing(mTarget, mCallback); 28922b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.remove_star) { 28932b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Removing star"); 28942b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Star removal is destructive in the Starred folder. 28952b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mConversationListCursor.updateBoolean(mTarget, ConversationColumns.STARRED, 28962b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy false); 28972b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.mark_not_important) { 28982b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Marking not-important"); 28992b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Marking not important is destructive in a mailbox 29002b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // containing only important messages 29012b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mFolder != null && mFolder.isImportantOnly()) { 29022b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy for (Conversation conv : mTarget) { 29032b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy conv.localDeleteOnUpdate = true; 2904445be2114aed6b28cab53b488735d4bb812353a5Mindy Pereira } 29052b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 29062b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mConversationListCursor.updateInt(mTarget, ConversationColumns.PRIORITY, 29072b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy UIProvider.ConversationPriority.LOW); 29082b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mAction == R.id.discard_drafts) { 29092b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy LogUtils.d(LOG_TAG, "Discarding draft messages"); 29102b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Discarding draft messages is destructive in a "draft" mailbox 29112b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mFolder != null && mFolder.isDraft()) { 29122b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy for (Conversation conv : mTarget) { 29132b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy conv.localDeleteOnUpdate = true; 2914ef3625472596326b910a4445307d1a8eb8c9cc3fPaul Westbrook } 29152b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 29162b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mConversationListCursor.discardDrafts(mTarget); 29172b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // We don't support undoing discarding drafts 29182b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy undoEnabled = false; 2919512821c11d89d49908f3cfdee0b582601f500f3dJin Cao } else if (mAction == R.id.discard_outbox) { 2920512821c11d89d49908f3cfdee0b582601f500f3dJin Cao LogUtils.d(LOG_TAG, "Discarding failed messages in Outbox"); 2921512821c11d89d49908f3cfdee0b582601f500f3dJin Cao mConversationListCursor.moveFailedIntoDrafts(mTarget); 2922512821c11d89d49908f3cfdee0b582601f500f3dJin Cao undoEnabled = false; 29233d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal } 29243d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal if (undoEnabled) { 2925ead5039b6d606fcc39668a472f8973cbd0bef4e1mindyp mHandler.postDelayed(new Runnable() { 2926ead5039b6d606fcc39668a472f8973cbd0bef4e1mindyp @Override 2927ead5039b6d606fcc39668a472f8973cbd0bef4e1mindyp public void run() { 2928ead5039b6d606fcc39668a472f8973cbd0bef4e1mindyp onUndoAvailable(new ToastBarOperation(mTarget.size(), mAction, 29296a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy ToastBarOperation.UNDO, mIsSelectedSet, mFolder)); 2930ead5039b6d606fcc39668a472f8973cbd0bef4e1mindyp } 2931ead5039b6d606fcc39668a472f8973cbd0bef4e1mindyp }, mShowUndoBarDelay); 29323d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal } 2933bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal refreshConversationList(); 2934c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal if (mIsSelectedSet) { 2935c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal mSelectedSet.clear(); 2936c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal } 2937fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } 29387f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal 29397f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal /** 29407f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal * Returns true if this action has been performed, false otherwise. 2941839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang * 29427f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal */ 29437f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal private synchronized boolean isPerformed() { 29447f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal if (mCompleted) { 29457f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal return true; 29467f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal } 29477f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal mCompleted = true; 29487f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal return false; 29497f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal } 2950fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira } 2951e5f4dc0661dad02e2cb39ffa62ff2157147ac387Mindy Pereira 2952d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal // Called from the FolderSelectionDialog after a user is done selecting folders to assign the 2953d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal // conversations to. 2954e5f4dc0661dad02e2cb39ffa62ff2157147ac387Mindy Pereira @Override 29558db7e407109532557718c6b8064792f2df7a073dMindy Pereira public final void assignFolder(Collection<FolderOperation> folderOps, 29566a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy Collection<Conversation> target, boolean batch, boolean showUndo, 29576a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy final boolean isMoveTo) { 2958479753fdbb4d71558c4d2c8d9cc8c7eb803a7837Jin Cao // Actions are destructive only when the current folder can be un-assigned from and 29598db7e407109532557718c6b8064792f2df7a073dMindy Pereira // when the list of folders contains the current folder. 29608db7e407109532557718c6b8064792f2df7a073dMindy Pereira final boolean isDestructive = mFolder 2961479753fdbb4d71558c4d2c8d9cc8c7eb803a7837Jin Cao .supportsCapability(FolderCapabilities.ALLOWS_REMOVE_CONVERSATION) 29628db7e407109532557718c6b8064792f2df7a073dMindy Pereira && FolderOperation.isDestructive(folderOps, mFolder); 2963d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal LogUtils.d(LOG_TAG, "onFolderChangesCommit: isDestructive = %b", isDestructive); 2964d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal if (isDestructive) { 2965d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal for (final Conversation c : target) { 2966d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal c.localDeleteOnUpdate = true; 29676778f4663a790d3e9d4c6a2f43292eef43c1e0bdMindy Pereira } 2968e5f4dc0661dad02e2cb39ffa62ff2157147ac387Mindy Pereira } 2969c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp final DestructiveAction folderChange; 297030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final UndoCallback undoCallback = isMoveTo ? 297130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao getUndoCallbackForDestructiveActionsWithAutoAdvance(R.id.move_to, 297230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mCurrentConversation) 297330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao : null; 2974d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal // Update the UI elements depending no their visibility and availability 29753d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal // TODO(viki): Consolidate this into a single method requestDelete. 2976d503df4f0c31bbf842c6a1d3cba18df8c074bf67Vikram Aggarwal if (isDestructive) { 29776a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy /* 29786a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy * If this is a MOVE operation, we want the action folder to be the destination folder. 29796a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy * Otherwise, we want it to be the current folder. 29806a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy * 29816a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy * A set of folder operations is a move if there are exactly two operations: an add and 29826a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy * a remove. 29836a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy */ 29846a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy final Folder actionFolder; 29856a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy if (folderOps.size() != 2) { 29866a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy actionFolder = mFolder; 29876a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } else { 29886a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy Folder addedFolder = null; 29896a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy boolean hasRemove = false; 29906a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy for (final FolderOperation folderOperation : folderOps) { 29916a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy if (folderOperation.mAdd) { 29926a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy addedFolder = folderOperation.mFolder; 29936a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } else { 29946a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy hasRemove = true; 29956a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } 29966a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } 29976a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy 29986a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy if (hasRemove && addedFolder != null) { 29996a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy actionFolder = addedFolder; 30006a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } else { 30016a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy actionFolder = mFolder; 30026a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } 30036a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy } 30046a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy 3005c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp folderChange = getDeferredFolderChange(target, folderOps, isDestructive, 300630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao batch, showUndo, isMoveTo, actionFolder, undoCallback); 3007caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy delete(0, target, folderChange, batch); 30086902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal } else { 3009c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp folderChange = getFolderChange(target, folderOps, isDestructive, 301030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao batch, showUndo, false /* isMoveTo */, mFolder, undoCallback); 3011715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal requestUpdate(folderChange); 3012e5f4dc0661dad02e2cb39ffa62ff2157147ac387Mindy Pereira } 3013e5f4dc0661dad02e2cb39ffa62ff2157147ac387Mindy Pereira } 3014e5f4dc0661dad02e2cb39ffa62ff2157147ac387Mindy Pereira 3015967ede63e059810d9d4d425c50111d606014c893Mindy Pereira @Override 30163d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal public final void onRefreshRequired() { 30175390fcabb7baf683fc14bd68d8612913dac70a81mindyp if (isAnimating() || isDragging()) { 3018f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang final ConversationListFragment f = getConversationListFragment(); 3019f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang LogUtils.w(ConversationCursor.LOG_TAG, 3020f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang "onRefreshRequired: delay until animating done. cursor=%s adapter=%s", 3021f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang mConversationListCursor, (f != null) ? f.getAnimatedAdapter() : null); 302269e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira return; 302369e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira } 3024bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank // Refresh the query in the background 3025cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook if (mConversationListCursor.isRefreshRequired()) { 3026cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook mConversationListCursor.refresh(); 3027cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook } 3028bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3029bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 30305390fcabb7baf683fc14bd68d8612913dac70a81mindyp @Override 30315390fcabb7baf683fc14bd68d8612913dac70a81mindyp public void startDragMode() { 30325390fcabb7baf683fc14bd68d8612913dac70a81mindyp mIsDragHappening = true; 30335390fcabb7baf683fc14bd68d8612913dac70a81mindyp } 30345390fcabb7baf683fc14bd68d8612913dac70a81mindyp 30355390fcabb7baf683fc14bd68d8612913dac70a81mindyp @Override 30365390fcabb7baf683fc14bd68d8612913dac70a81mindyp public void stopDragMode() { 30375390fcabb7baf683fc14bd68d8612913dac70a81mindyp mIsDragHappening = false; 30385390fcabb7baf683fc14bd68d8612913dac70a81mindyp if (mConversationListCursor.isRefreshReady()) { 3039c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang LogUtils.i(ConversationCursor.LOG_TAG, "Stopped dragging: try sync"); 30405390fcabb7baf683fc14bd68d8612913dac70a81mindyp onRefreshReady(); 30415390fcabb7baf683fc14bd68d8612913dac70a81mindyp } 30425390fcabb7baf683fc14bd68d8612913dac70a81mindyp 30435390fcabb7baf683fc14bd68d8612913dac70a81mindyp if (mConversationListCursor.isRefreshRequired()) { 3044c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang LogUtils.i(ConversationCursor.LOG_TAG, "Stopped dragging: refresh"); 30455390fcabb7baf683fc14bd68d8612913dac70a81mindyp mConversationListCursor.refresh(); 30465390fcabb7baf683fc14bd68d8612913dac70a81mindyp } 30475390fcabb7baf683fc14bd68d8612913dac70a81mindyp } 30485390fcabb7baf683fc14bd68d8612913dac70a81mindyp 30495390fcabb7baf683fc14bd68d8612913dac70a81mindyp private boolean isDragging() { 30505390fcabb7baf683fc14bd68d8612913dac70a81mindyp return mIsDragHappening; 30515390fcabb7baf683fc14bd68d8612913dac70a81mindyp } 30525390fcabb7baf683fc14bd68d8612913dac70a81mindyp 30536f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp @Override 30546f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp public boolean isAnimating() { 305569e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira boolean isAnimating = false; 305669e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira ConversationListFragment convListFragment = getConversationListFragment(); 305769e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira if (convListFragment != null) { 305848ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang isAnimating = convListFragment.isAnimating(); 305969e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira } 306069e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira return isAnimating; 306169e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira } 306269e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira 3063bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank /** 3064bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank * Called when the {@link ConversationCursor} is changed or has new data in it. 3065bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank * <p> 3066bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank * {@inheritDoc} 3067bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank */ 3068bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank @Override 30693d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal public final void onRefreshReady() { 30705c1d8354ce98be2fc77d458bcc5c3346765046a0mindyp LogUtils.d(LOG_TAG, "Received refresh ready callback for folder %s", 30715c1d8354ce98be2fc77d458bcc5c3346765046a0mindyp mFolder != null ? mFolder.id : "-1"); 3072b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang 3073b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang if (mDestroyed) { 3074b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang LogUtils.i(LOG_TAG, "ignoring onRefreshReady on destroyed AAC"); 3075b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang return; 3076b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang } 3077b2ef9c18d1f68543d9c782e1952b70d3bbcd94d6Andy Huang 3078cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook if (!isAnimating()) { 3079bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank // Swap cursors 3080bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mConversationListCursor.sync(); 3081f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang } else { 3082f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang // (CLF guaranteed to be non-null due to check in isAnimating) 3083f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang LogUtils.w(LOG_TAG, 3084f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang "AAC.onRefreshReady suppressing sync() due to animation. cursor=%s aa=%s", 3085f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang mConversationListCursor, getConversationListFragment().getAnimatedAdapter()); 3086bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3087937c94f025ed55c19bd46c7c077fa3575ab6be52Paul Westbrook mTracker.onCursorUpdated(); 3088f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal perhapsShowFirstSearchResult(); 3089bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3090bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3091bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank @Override 30923d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal public final void onDataSetChanged() { 30939f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook updateConversationListFragment(); 3094632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mConversationListObservable.notifyChanged(); 3095a13b3742522987f768ef9a1a1cddd32ff8105f0ePaul Westbrook mSelectedSet.validateAgainstCursor(mConversationListCursor); 3096bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3097bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 30983d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal /** 30993d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal * If the Conversation List Fragment is visible, updates the fragment. 31003d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal */ 3101715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void updateConversationListFragment() { 3102bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank final ConversationListFragment convList = getConversationListFragment(); 3103bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank if (convList != null) { 310475daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal refreshConversationList(); 31056422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal if (isFragmentVisible(convList)) { 310669b5c304f9572f18c0fcb456d81cccf2e560c72fVikram Aggarwal informCursorVisiblity(true); 31079f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook } 3108bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3109bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3110bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3111bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank /** 3112bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank * This class handles throttled refresh of the conversation list 3113bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank */ 3114bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank static class RefreshTimerTask extends TimerTask { 3115bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank final Handler mHandler; 3116bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank final AbstractActivityController mController; 3117bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3118bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank RefreshTimerTask(AbstractActivityController controller, Handler handler) { 3119bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mHandler = handler; 3120bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mController = controller; 3121bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3122bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3123bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank @Override 3124bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank public void run() { 3125bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mHandler.post(new Runnable() { 3126bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank @Override 3127bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank public void run() { 3128bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank LogUtils.d(LOG_TAG, "Delay done... calling onRefreshRequired"); 3129bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mController.onRefreshRequired(); 3130bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank }}); 3131bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3132bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3133bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3134bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank /** 3135bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank * Cancel the refresh task, if it's running 3136bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank */ 3137bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank private void cancelRefreshTask () { 3138bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank if (mConversationListRefreshTask != null) { 3139bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mConversationListRefreshTask.cancel(); 3140bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank mConversationListRefreshTask = null; 3141bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3142bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3143bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3144bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank @Override 3145cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook public void onAnimationEnd(AnimatedAdapter animatedAdapter) { 3146f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang if (animatedAdapter != null) { 3147f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang LogUtils.i(LOG_TAG, "AAC.onAnimationEnd. cursor=%s adapter=%s", mConversationListCursor, 3148f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang animatedAdapter); 3149f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang } 3150026139c958c563266294b7788ed54f57345626b8Paul Westbrook if (mConversationListCursor == null) { 3151026139c958c563266294b7788ed54f57345626b8Paul Westbrook LogUtils.e(LOG_TAG, "null ConversationCursor in onAnimationEnd"); 3152026139c958c563266294b7788ed54f57345626b8Paul Westbrook return; 3153026139c958c563266294b7788ed54f57345626b8Paul Westbrook } 3154cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook if (mConversationListCursor.isRefreshReady()) { 3155c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang LogUtils.i(ConversationCursor.LOG_TAG, "Stopped animating: try sync"); 3156cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook onRefreshReady(); 3157bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3158bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3159cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook if (mConversationListCursor.isRefreshRequired()) { 3160c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang LogUtils.i(ConversationCursor.LOG_TAG, "Stopped animating: refresh"); 3161cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook mConversationListCursor.refresh(); 3162cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook } 31636f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp if (mRecentsDataUpdated) { 31646f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp mRecentsDataUpdated = false; 31656f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp mRecentFolderObservers.notifyChanged(); 31666f54e1b0e8beae2e624852f9f2f2b1b38745e3bemindyp } 3167bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank } 3168bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank 3169bf128ebfb9aa53d28118e7143d5674e506fedfefMarc Blank @Override 3170967ede63e059810d9d4d425c50111d606014c893Mindy Pereira public void onSetEmpty() { 31716cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal // There are no selected conversations. Ensure that the listener and its associated actions 31726cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal // are blanked out. 31736cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal setListener(null, -1); 3174967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 3175967ede63e059810d9d4d425c50111d606014c893Mindy Pereira 3176967ede63e059810d9d4d425c50111d606014c893Mindy Pereira @Override 3177967ede63e059810d9d4d425c50111d606014c893Mindy Pereira public void onSetPopulated(ConversationSelectionSet set) { 31787704d79def5e5f36a1cbe22fbbe6e9520503899cVikram Aggarwal mCabActionMenu = new SelectedConversationsActionMenu(mActivity, set, mFolder); 31795b9ed2b056e0757ccc26e51aba7d5ff12378baaaVikram Aggarwal if (mViewMode.isListMode() || (mIsTablet && mViewMode.isConversationMode())) { 31807704d79def5e5f36a1cbe22fbbe6e9520503899cVikram Aggarwal enableCabMode(); 31816902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal } 3182967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 3183967ede63e059810d9d4d425c50111d606014c893Mindy Pereira 3184967ede63e059810d9d4d425c50111d606014c893Mindy Pereira @Override 3185967ede63e059810d9d4d425c50111d606014c893Mindy Pereira public void onSetChanged(ConversationSelectionSet set) { 3186967ede63e059810d9d4d425c50111d606014c893Mindy Pereira // Do nothing. We don't care about changes to the set. 3187967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 3188967ede63e059810d9d4d425c50111d606014c893Mindy Pereira 3189967ede63e059810d9d4d425c50111d606014c893Mindy Pereira @Override 3190967ede63e059810d9d4d425c50111d606014c893Mindy Pereira public ConversationSelectionSet getSelectedSet() { 3191967ede63e059810d9d4d425c50111d606014c893Mindy Pereira return mSelectedSet; 3192967ede63e059810d9d4d425c50111d606014c893Mindy Pereira } 3193967ede63e059810d9d4d425c50111d606014c893Mindy Pereira 3194e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal /** 3195e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal * Disable the Contextual Action Bar (CAB). The selected set is not changed. 3196e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal */ 3197e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal protected void disableCabMode() { 31988937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira // Commit any previous destructive actions when entering/ exiting CAB mode. 3199c6adce3cf6887c4c6dd5005724565702751843d0mindyp commitDestructiveActions(true); 3200e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal if (mCabActionMenu != null) { 3201e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal mCabActionMenu.deactivate(); 3202e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal } 3203e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal } 3204e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal 3205e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal /** 3206e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal * Re-enable the CAB menu if required. The selection set is not changed. 3207e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal */ 3208e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal protected void enableCabMode() { 32093d6751ad5328d5a17fa637e3157974d776591b26Tony Mantler if (mCabActionMenu != null && 32103d6751ad5328d5a17fa637e3157974d776591b26Tony Mantler !(isDrawerEnabled() && mDrawerContainer.isDrawerOpen(mDrawerPullout))) { 3211e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal mCabActionMenu.activate(); 3212e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal } 3213e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal } 3214e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal 32154eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal /** 321643fab3224230c235db5be395f96096e1cac6b376Tony Mantler * Re-enable CAB mode only if we have an active selection 321743fab3224230c235db5be395f96096e1cac6b376Tony Mantler */ 321843fab3224230c235db5be395f96096e1cac6b376Tony Mantler protected void maybeEnableCabMode() { 321943fab3224230c235db5be395f96096e1cac6b376Tony Mantler if (!mSelectedSet.isEmpty()) { 3220a703d8a647a7272347c47bbb394b1a4c403106a5Tony Mantler if (mCabActionMenu != null) { 3221a703d8a647a7272347c47bbb394b1a4c403106a5Tony Mantler mCabActionMenu.activate(); 3222a703d8a647a7272347c47bbb394b1a4c403106a5Tony Mantler } 322343fab3224230c235db5be395f96096e1cac6b376Tony Mantler } 322443fab3224230c235db5be395f96096e1cac6b376Tony Mantler } 322543fab3224230c235db5be395f96096e1cac6b376Tony Mantler 322643fab3224230c235db5be395f96096e1cac6b376Tony Mantler /** 32274eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal * Unselect conversations and exit CAB mode. 32284eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal */ 32294eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal protected final void exitCabMode() { 32304eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal mSelectedSet.clear(); 32314eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal } 32324eb5271e0f0a48ea624e048eb69fbe86d6c62dc3Vikram Aggarwal 3233967ede63e059810d9d4d425c50111d606014c893Mindy Pereira @Override 3234fd0c2974af56ad244006faab2651e054974a4b7bMindy Pereira public void startSearch() { 323535f19d7c052ca8074b48b2ab9d8689a72dc369c5Vikram Aggarwal if (mAccount == null) { 323635f19d7c052ca8074b48b2ab9d8689a72dc369c5Vikram Aggarwal // We cannot search if there is no account. Drop the request to the floor. 323735f19d7c052ca8074b48b2ab9d8689a72dc369c5Vikram Aggarwal LogUtils.d(LOG_TAG, "AbstractActivityController.startSearch(): null account"); 323835f19d7c052ca8074b48b2ab9d8689a72dc369c5Vikram Aggarwal return; 323935f19d7c052ca8074b48b2ab9d8689a72dc369c5Vikram Aggarwal } 32403531d7ee9b36c9f9dd909be79ab899dd60cd71aeJames Lemieux if (mAccount.supportsSearch()) { 32412d86d1123c4183024222dd2eb60f7cbdc24953fdAndrew Sapperstein mActionBarController.expandSearch(); 3242fd0c2974af56ad244006faab2651e054974a4b7bMindy Pereira } else { 3243fd0c2974af56ad244006faab2651e054974a4b7bMindy Pereira Toast.makeText(mActivity.getActivityContext(), mActivity.getActivityContext() 3244a46c29980f2d81da3529b2f1dfddf7291c94a102Mindy Pereira .getString(R.string.search_unsupported), Toast.LENGTH_SHORT).show(); 3245fd0c2974af56ad244006faab2651e054974a4b7bMindy Pereira } 3246fd0c2974af56ad244006faab2651e054974a4b7bMindy Pereira } 3247acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira 32480dda573e51786dd907b2674baddbca20ffa5c725Vikram Aggarwal @Override 32490dda573e51786dd907b2674baddbca20ffa5c725Vikram Aggarwal public void exitSearchMode() { 32500dda573e51786dd907b2674baddbca20ffa5c725Vikram Aggarwal if (mViewMode.getMode() == ViewMode.SEARCH_RESULTS_LIST) { 32510dda573e51786dd907b2674baddbca20ffa5c725Vikram Aggarwal mActivity.finish(); 32520dda573e51786dd907b2674baddbca20ffa5c725Vikram Aggarwal } 32530dda573e51786dd907b2674baddbca20ffa5c725Vikram Aggarwal } 32540dda573e51786dd907b2674baddbca20ffa5c725Vikram Aggarwal 3255acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira /** 3256acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira * Supports dragging conversations to a folder. 3257acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira */ 3258acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira @Override 3259acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira public boolean supportsDrag(DragEvent event, Folder folder) { 3260acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira return (folder != null 3261acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira && event != null 3262acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira && event.getClipDescription() != null 3263acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira && folder.supportsCapability 3264acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira (UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES) 3265259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy && !mFolder.equals(folder)); 3266acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira } 3267acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira 3268acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira /** 32696c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira * Handles dropping conversations to a folder. 3270acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira */ 3271acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira @Override 3272acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira public void handleDrop(DragEvent event, final Folder folder) { 3273acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira if (!supportsDrag(event, folder)) { 3274acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira return; 3275acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira } 32768c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy if (folder.isType(UIProvider.FolderType.STARRED)) { 3277ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp // Moving a conversation to the starred folder adds the star and 3278ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp // removes the current label 3279ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp handleDropInStarred(folder); 3280ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp return; 3281ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 32828c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy if (mFolder.isType(UIProvider.FolderType.STARRED)) { 3283ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp handleDragFromStarred(folder); 3284ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp return; 3285ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 3286a8492633481c1724d2f6d418594faf6e982d3dc9mindyp final ArrayList<FolderOperation> dragDropOperations = new ArrayList<FolderOperation>(); 3287ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp final Collection<Conversation> conversations = mSelectedSet.values(); 3288a8492633481c1724d2f6d418594faf6e982d3dc9mindyp // Add the drop target folder. 3289a8492633481c1724d2f6d418594faf6e982d3dc9mindyp dragDropOperations.add(new FolderOperation(folder, true)); 3290a8492633481c1724d2f6d418594faf6e982d3dc9mindyp // Remove the current folder unless the user is viewing "all". 3291a8492633481c1724d2f6d418594faf6e982d3dc9mindyp // That operation should just add the new folder. 3292a8492633481c1724d2f6d418594faf6e982d3dc9mindyp boolean isDestructive = !mFolder.isViewAll() 3293a8492633481c1724d2f6d418594faf6e982d3dc9mindyp && mFolder.supportsCapability 3294a8492633481c1724d2f6d418594faf6e982d3dc9mindyp (UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES); 3295a8492633481c1724d2f6d418594faf6e982d3dc9mindyp if (isDestructive) { 3296a8492633481c1724d2f6d418594faf6e982d3dc9mindyp dragDropOperations.add(new FolderOperation(mFolder, false)); 3297a8492633481c1724d2f6d418594faf6e982d3dc9mindyp } 32988db7e407109532557718c6b8064792f2df7a073dMindy Pereira // Drag and drop is destructive: we remove conversations from the 32998db7e407109532557718c6b8064792f2df7a073dMindy Pereira // current folder. 33006a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy final DestructiveAction action = 33016a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy getFolderChange(conversations, dragDropOperations, isDestructive, 330230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao true /* isBatch */, true /* showUndo */, true /* isMoveTo */, folder, 330330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao null /* undoCallback */); 3304a8492633481c1724d2f6d418594faf6e982d3dc9mindyp if (isDestructive) { 3305caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy delete(0, conversations, action, true); 3306a8492633481c1724d2f6d418594faf6e982d3dc9mindyp } else { 3307a8492633481c1724d2f6d418594faf6e982d3dc9mindyp action.performAction(); 3308a8492633481c1724d2f6d418594faf6e982d3dc9mindyp } 3309acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira } 33100963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira 3311ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp private void handleDragFromStarred(Folder folder) { 3312ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp final Collection<Conversation> conversations = mSelectedSet.values(); 3313ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp // The conversation list deletes and performs the action if it exists. 3314ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp final ConversationListFragment convListFragment = getConversationListFragment(); 3315ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp // There should always be a convlistfragment, or the user could not have 3316ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp // dragged/ dropped conversations. 3317ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp if (convListFragment != null) { 3318ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp LogUtils.d(LOG_TAG, "AAC.requestDelete: ListFragment is handling delete."); 3319ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp ArrayList<ConversationOperation> ops = new ArrayList<ConversationOperation>(); 3320cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp ArrayList<Uri> folderUris; 3321cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp ArrayList<Boolean> adds; 3322ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp for (Conversation target : conversations) { 3323cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp folderUris = new ArrayList<Uri>(); 3324cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp adds = new ArrayList<Boolean>(); 3325259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy folderUris.add(folder.folderUri.fullUri); 3326cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp adds.add(Boolean.TRUE); 332726746eb4acb159f3ce0d411c10d85a1de3e958a0Paul Westbrook final HashMap<Uri, Folder> targetFolders = 332826746eb4acb159f3ce0d411c10d85a1de3e958a0Paul Westbrook Folder.hashMapForFolders(target.getRawFolders()); 3329259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy targetFolders.put(folder.folderUri.fullUri, folder); 333026746eb4acb159f3ce0d411c10d85a1de3e958a0Paul Westbrook ops.add(mConversationListCursor.getConversationFolderOperation(target, 333126746eb4acb159f3ce0d411c10d85a1de3e958a0Paul Westbrook folderUris, adds, targetFolders.values())); 3332ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 3333ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp if (mConversationListCursor != null) { 33349e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateBulkValues(ops); 3335ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 3336ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp refreshConversationList(); 3337ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp mSelectedSet.clear(); 3338ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 3339ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 3340ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp 3341ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp private void handleDropInStarred(Folder folder) { 3342ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp final Collection<Conversation> conversations = mSelectedSet.values(); 3343ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp // The conversation list deletes and performs the action if it exists. 3344ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp final ConversationListFragment convListFragment = getConversationListFragment(); 3345ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp // There should always be a convlistfragment, or the user could not have 3346ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp // dragged/ dropped conversations. 3347ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp if (convListFragment != null) { 3348ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp LogUtils.d(LOG_TAG, "AAC.requestDelete: ListFragment is handling delete."); 33496c570db71b8adc43d7dc2f31e6fa63cf50c1426eAndrew Sapperstein convListFragment.requestDelete(R.id.change_folders, conversations, 33505cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp new DroppedInStarredAction(conversations, mFolder, folder)); 3351ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 3352ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 3353ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp 3354ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp // When dragging conversations to the starred folder, remove from the 3355ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp // original folder and add a star 3356ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp private class DroppedInStarredAction implements DestructiveAction { 3357e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon private final Collection<Conversation> mConversations; 3358e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon private final Folder mInitialFolder; 3359e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon private final Folder mStarred; 3360ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp 33615cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp public DroppedInStarredAction(Collection<Conversation> conversations, Folder initialFolder, 33625cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp Folder starredFolder) { 3363ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp mConversations = conversations; 33645cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp mInitialFolder = initialFolder; 33655cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp mStarred = starredFolder; 3366ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 3367ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp 3368ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp @Override 336930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public void setUndoCallback(UndoCallback undoCallback) { 337030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return; // currently not applicable 337130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 337230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 337330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao @Override 3374ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp public void performAction() { 3375ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp ToastBarOperation undoOp = new ToastBarOperation(mConversations.size(), 33766c570db71b8adc43d7dc2f31e6fa63cf50c1426eAndrew Sapperstein R.id.change_folders, ToastBarOperation.UNDO, true /* batch */, mInitialFolder); 3377ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp onUndoAvailable(undoOp); 3378ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp ArrayList<ConversationOperation> ops = new ArrayList<ConversationOperation>(); 3379ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp ContentValues values = new ContentValues(); 3380cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp ArrayList<Uri> folderUris; 3381cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp ArrayList<Boolean> adds; 33825cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp ConversationOperation operation; 3383ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp for (Conversation target : mConversations) { 3384cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp folderUris = new ArrayList<Uri>(); 3385cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp adds = new ArrayList<Boolean>(); 3386259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy folderUris.add(mStarred.folderUri.fullUri); 33875cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp adds.add(Boolean.TRUE); 3388259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy folderUris.add(mInitialFolder.folderUri.fullUri); 3389cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp adds.add(Boolean.FALSE); 33905cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp final HashMap<Uri, Folder> targetFolders = 33915cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp Folder.hashMapForFolders(target.getRawFolders()); 3392259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy targetFolders.put(mStarred.folderUri.fullUri, mStarred); 3393259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy targetFolders.remove(mInitialFolder.folderUri.fullUri); 33945cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp values.put(ConversationColumns.STARRED, true); 33955cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp operation = mConversationListCursor.getConversationFolderOperation(target, 33965cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp folderUris, adds, targetFolders.values(), values); 33975cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp ops.add(operation); 3398ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 3399ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp if (mConversationListCursor != null) { 34009e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateBulkValues(ops); 3401ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 3402ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp refreshConversationList(); 3403ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp mSelectedSet.clear(); 3404ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 3405ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp } 3406ae7e6a0786a2d890b77c783d7ac39a90523b8154mindyp 34070963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira @Override 34080963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira public void onTouchEvent(MotionEvent event) { 34090963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira if (event.getAction() == MotionEvent.ACTION_DOWN) { 3410c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein if (mToastBar != null && !mToastBar.isEventInToastBar(event)) { 34119a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux // if the toast bar is still animating, ignore this attempt to hide it 34129a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux if (mToastBar.isAnimating()) { 34139a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux return; 34149a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux } 34159a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux 34169a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux // if the toast bar has not been seen long enough, ignore this attempt to hide it 34179a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux if (mToastBar.cannotBeHidden()) { 34189a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux return; 34199a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux } 34209a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux 34219a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux // hide the toast bar 34229a11011dc42ea3c8934c90455b17bd77a0a5ee17James Lemieux mToastBar.hide(true /* animated */, false /* actionClicked */); 34230963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira } 34240963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira } 34250963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira } 3426b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang 3427632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 34283b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy public void onConversationSeen() { 34293b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy mPagerController.onConversationSeen(); 3430632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 3431632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 34329d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang @Override 34339d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang public boolean isInitialConversationLoading() { 34349d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang return mPagerController.isInitialConversationLoading(); 34359d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang } 34369d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang 34376422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal /** 34386422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal * Check if the fragment given here is visible. Checking {@link Fragment#isVisible()} is 34396422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal * insufficient because that doesn't check if the window is currently in focus or not. 34406422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal */ 3441715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private boolean isFragmentVisible(Fragment in) { 34426422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal return in != null && in.isVisible() && mActivity.hasWindowFocus(); 34436422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal } 34446422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal 3445d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal /** 3446d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal * This class handles callbacks that create a {@link ConversationCursor}. 3447d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal */ 3448b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang private class ConversationListLoaderCallbacks implements 3449b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang LoaderManager.LoaderCallbacks<ConversationCursor> { 3450b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang 3451b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang @Override 3452b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang public Loader<ConversationCursor> onCreateLoader(int id, Bundle args) { 3453a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal final Account account = args.getParcelable(BUNDLE_ACCOUNT_KEY); 3454a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal final Folder folder = args.getParcelable(BUNDLE_FOLDER_KEY); 34555bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein final boolean ignoreInitialConversationLimit = 34565bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein args.getBoolean(BUNDLE_IGNORE_INITIAL_CONVERSATION_LIMIT_KEY, false); 3457a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal if (account == null || folder == null) { 3458a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal return null; 3459a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal } 34605bb4d053519be10324752f323bcf73f13b9a2604Andrew Sapperstein return new ConversationCursorLoader(mActivity, account, 3461f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang folder.conversationListUri, folder.getTypeDescription(), 3462f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang ignoreInitialConversationLimit); 3463b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang } 3464b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang 3465b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang @Override 3466b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang public void onLoadFinished(Loader<ConversationCursor> loader, ConversationCursor data) { 3467144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang LogUtils.d(LOG_TAG, 3468144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang "IN AAC.ConversationCursor.onLoadFinished, data=%s loader=%s this=%s", 3469144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang data, loader, this); 3470a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein if (isDrawerEnabled() && mDrawerListener.getDrawerState() != DrawerLayout.STATE_IDLE) { 3471a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal LogUtils.d(LOG_TAG, "ConversationListLoaderCallbacks.onLoadFinished: ignoring."); 3472a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mConversationListLoadFinishedIgnored = true; 3473a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal return; 3474a1b59dcb4a8aaef821aa2f5c996f715ef130c985Vikram Aggarwal } 3475e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal // Clear our all pending destructive actions before swapping the conversation cursor 3476e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal destroyPending(null); 3477b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang mConversationListCursor = data; 3478bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook mConversationListCursor.addListener(AbstractActivityController.this); 3479144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang mDrawIdler.setListener(mConversationListCursor); 3480937c94f025ed55c19bd46c7c077fa3575ab6be52Paul Westbrook mTracker.onCursorUpdated(); 3481e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang mConversationListObservable.notifyChanged(); 34827c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu // Handle actions that were deferred until after the conversation list was loaded. 34837c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu for (LoadFinishedCallback callback : mConversationListLoadFinishedCallbacks) { 34847c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu callback.onLoadFinished(); 34857c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu } 34867c909c76deb748e6aca82e885a9fbaee52adeb9cYu Ping Hu mConversationListLoadFinishedCallbacks.clear(); 34879f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook 348817f373ecf6961112f77a7516ab1bbcb4fcdf2884Vikram Aggarwal final ConversationListFragment convList = getConversationListFragment(); 34896422b8d051c93b4f34580c551254fc50c9efa4dbVikram Aggarwal if (isFragmentVisible(convList)) { 349017f373ecf6961112f77a7516ab1bbcb4fcdf2884Vikram Aggarwal // The conversation list is already listening to list changes and gets notified 349117f373ecf6961112f77a7516ab1bbcb4fcdf2884Vikram Aggarwal // in the mConversationListObservable.notifyChanged() line above. We only need to 349217f373ecf6961112f77a7516ab1bbcb4fcdf2884Vikram Aggarwal // check and inform the cursor of the change in visibility here. 349317f373ecf6961112f77a7516ab1bbcb4fcdf2884Vikram Aggarwal informCursorVisiblity(true); 3494b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang } 3495f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal perhapsShowFirstSearchResult(); 3496b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang } 3497b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang 3498b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang @Override 3499b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang public void onLoaderReset(Loader<ConversationCursor> loader) { 3500144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang LogUtils.d(LOG_TAG, 3501144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang "IN AAC.ConversationCursor.onLoaderReset, data=%s loader=%s this=%s", 3502144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang mConversationListCursor, loader, this); 35039a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook 35049a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook if (mConversationListCursor != null) { 35059a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook // Unregister the listener 35069a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook mConversationListCursor.removeListener(AbstractActivityController.this); 3507144bfe739b93afdee0a1700a34806b0b287e5887Andy Huang mDrawIdler.setListener(null); 35089a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook mConversationListCursor = null; 35099a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook 35109a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook // Inform anyone who is interested about the change 35119a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook mTracker.onCursorUpdated(); 35129a70e919125d63971604e6dd3de8bc998e9c86daPaul Westbrook mConversationListObservable.notifyChanged(); 3513b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang } 3514b1c34dc418e31ae0bfe1b73b6642ed42f5dad67bAndy Huang } 3515bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook } 3516bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook 3517e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal /** 3518177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal * Class to perform {@link LoaderManager.LoaderCallbacks} for creating {@link Folder} objects. 3519177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal */ 3520177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private class FolderLoads implements LoaderManager.LoaderCallbacks<ObjectCursor<Folder>> { 3521177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3522177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal public Loader<ObjectCursor<Folder>> onCreateLoader(int id, Bundle args) { 3523177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final String[] everything = UIProvider.FOLDERS_PROJECTION; 3524177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal switch (id) { 3525177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_FOLDER_CURSOR: 3526177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_FOLDER_CURSOR created"); 3527177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final ObjectCursorLoader<Folder> loader = new 3528177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal ObjectCursorLoader<Folder>( 3529259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy mContext, mFolder.folderUri.fullUri, everything, Folder.FACTORY); 3530177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal loader.setUpdateThrottle(mFolderItemUpdateDelayMs); 3531177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return loader; 3532177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_RECENT_FOLDERS: 3533177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_RECENT_FOLDERS created"); 3534f2632b979d7f17a548c34cccae94b2a0046cee32Yu Ping Hu if (mAccount != null && mAccount.recentFolderListUri != null 3535f2632b979d7f17a548c34cccae94b2a0046cee32Yu Ping Hu && !mAccount.recentFolderListUri.equals(Uri.EMPTY)) { 3536177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return new ObjectCursorLoader<Folder>(mContext, 3537177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mAccount.recentFolderListUri, everything, Folder.FACTORY); 3538177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3539177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3540177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_ACCOUNT_INBOX: 3541177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_ACCOUNT_INBOX created"); 3542177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Uri defaultInbox = Settings.getDefaultInboxUri(mAccount.settings); 3543177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Uri inboxUri = defaultInbox.equals(Uri.EMPTY) ? 3544177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mAccount.folderListUri : defaultInbox; 3545177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "Loading the default inbox: %s", inboxUri); 3546177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (inboxUri != null) { 3547177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return new ObjectCursorLoader<Folder>(mContext, inboxUri, 3548177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal everything, Folder.FACTORY); 3549177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3550177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3551177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_SEARCH: 3552177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_SEARCH created"); 3553177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return Folder.forSearchResults(mAccount, 3554177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal args.getString(ConversationListContext.EXTRA_SEARCH_QUERY), 35551a864cce6321f46031d6cd43e205278d0f219f92Jin Cao // We can just use current time as a unique identifier for this search 35561a864cce6321f46031d6cd43e205278d0f219f92Jin Cao Long.toString(SystemClock.uptimeMillis()), 3557177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getActivityContext()); 3558177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_FIRST_FOLDER: 3559177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_FIRST_FOLDER created"); 3560177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Uri folderUri = args.getParcelable(Utils.EXTRA_FOLDER_URI); 3561177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mConversationToShow = args.getParcelable(Utils.EXTRA_CONVERSATION); 3562177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (mConversationToShow != null && mConversationToShow.position < 0){ 3563177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mConversationToShow.position = 0; 3564177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3565177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return new ObjectCursorLoader<Folder>(mContext, folderUri, 3566177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal everything, Folder.FACTORY); 3567177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal default: 3568177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.wtf(LOG_TAG, "FolderLoads.onCreateLoader(%d) for invalid id", id); 3569177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return null; 3570177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3571177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return null; 3572177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3573177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3574177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3575177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal public void onLoadFinished(Loader<ObjectCursor<Folder>> loader, ObjectCursor<Folder> data) { 3576177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data == null) { 3577177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.e(LOG_TAG, "Received null cursor from loader id: %d", loader.getId()); 3578177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3579177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal switch (loader.getId()) { 3580177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_FOLDER_CURSOR: 3581177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data != null && data.moveToFirst()) { 3582177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Folder folder = data.getModel(); 3583177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal setHasFolderChanged(folder); 3584177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mFolder = folder; 3585177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mFolderObservable.notifyChanged(); 3586177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } else { 3587177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "Unable to get the folder %s", 358826a20758413f0f8629ea71a0943304e3ae740165Tony Mantler mFolder != null ? mFolder.name : ""); 3589177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3590177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3591177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_RECENT_FOLDERS: 3592177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Few recent folders and we are running on a phone? Populate the default 3593177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // recents. The number of default recent folders is at least 2: every provider 3594177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // has at least two folders, and the recent folder count never decreases. 3595177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Having a single recent folder is an erroneous case, and we can gracefully 3596177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // recover by populating default recents. The default recents will not stomp on 3597177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // the existing value: it will be shown in addition to the default folders: 3598177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // the max number of recent folders is more than 1+num(defaultRecents). 3599177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data != null && data.getCount() <= 1 && !mIsTablet) { 3600177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final class PopulateDefault extends AsyncTask<Uri, Void, Void> { 3601177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3602177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal protected Void doInBackground(Uri... uri) { 3603177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Asking for an update on the URI and ignore the result. 3604177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final ContentResolver resolver = mContext.getContentResolver(); 3605177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal resolver.update(uri[0], null, null, null); 3606177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return null; 3607177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3608177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3609177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Uri uri = mAccount.defaultRecentFolderListUri; 3610177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.v(LOG_TAG, "Default recents at %s", uri); 3611177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal new PopulateDefault().execute(uri); 3612177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3613177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3614177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.v(LOG_TAG, "Reading recent folders from the cursor."); 3615177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mRecentFolderList.loadFromUiProvider(data); 3616177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (isAnimating()) { 3617177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mRecentsDataUpdated = true; 3618177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } else { 3619177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mRecentFolderObservers.notifyChanged(); 3620177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3621177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3622177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_ACCOUNT_INBOX: 3623177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data != null && !data.isClosed() && data.moveToFirst()) { 3624177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Folder inbox = data.getModel(); 3625ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang onFolderChanged(inbox, false /* force */); 3626177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Just want to get the inbox, don't care about updates to it 3627177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // as this will be tracked by the folder change listener. 3628177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getLoaderManager().destroyLoader(LOADER_ACCOUNT_INBOX); 3629177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } else { 3630177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "Unable to get the account inbox for account %s", 363126a20758413f0f8629ea71a0943304e3ae740165Tony Mantler mAccount != null ? mAccount.getEmailAddress() : ""); 3632177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3633177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3634177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_SEARCH: 3635177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data != null && data.getCount() > 0) { 3636177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal data.moveToFirst(); 3637177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Folder search = data.getModel(); 3638177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal updateFolder(search); 3639177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mConvListContext = ConversationListContext.forSearchQuery(mAccount, mFolder, 3640177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getIntent() 3641177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal .getStringExtra(UIProvider.SearchQueryParameters.QUERY)); 3642177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal showConversationList(mConvListContext); 3643177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.invalidateOptionsMenu(); 3644177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mHaveSearchResults = search.totalCount > 0; 3645177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getLoaderManager().destroyLoader(LOADER_SEARCH); 3646177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } else { 3647177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.e(LOG_TAG, "Null/empty cursor returned by LOADER_SEARCH loader"); 3648177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3649177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3650177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_FIRST_FOLDER: 3651177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data == null || data.getCount() <=0 || !data.moveToFirst()) { 3652177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return; 3653177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3654177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Folder folder = data.getModel(); 3655177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal boolean handled = false; 3656177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (folder != null) { 3657ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang onFolderChanged(folder, false /* force */); 3658177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal handled = true; 3659177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3660177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (mConversationToShow != null) { 3661177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Open the conversation. 3662177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal showConversation(mConversationToShow); 3663177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal handled = true; 3664177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3665177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (!handled) { 3666177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // We have an account, but nothing else: load the default inbox. 3667177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal loadAccountInbox(); 3668177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3669177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mConversationToShow = null; 3670177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // And don't run this anymore. 3671177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.getLoaderManager().destroyLoader(LOADER_FIRST_FOLDER); 3672177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3673177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3674177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3675177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3676177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3677177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal public void onLoaderReset(Loader<ObjectCursor<Folder>> loader) { 3678177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3679177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3680177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3681177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal /** 3682177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal * Class to perform {@link LoaderManager.LoaderCallbacks} for creating {@link Account} objects. 3683177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal */ 3684177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal private class AccountLoads implements LoaderManager.LoaderCallbacks<ObjectCursor<Account>> { 3685177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final String[] mProjection = UIProvider.ACCOUNTS_PROJECTION; 3686177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final CursorCreator<Account> mFactory = Account.FACTORY; 3687177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3688177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3689177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal public Loader<ObjectCursor<Account>> onCreateLoader(int id, Bundle args) { 3690177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal switch (id) { 3691177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_ACCOUNT_CURSOR: 3692177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_ACCOUNT_CURSOR created"); 3693177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return new ObjectCursorLoader<Account>(mContext, 3694177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal MailAppProvider.getAccountsUri(), mProjection, mFactory); 3695177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_ACCOUNT_UPDATE_CURSOR: 3696177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "LOADER_ACCOUNT_UPDATE_CURSOR created"); 3697177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return new ObjectCursorLoader<Account>(mContext, mAccount.uri, mProjection, 3698177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mFactory); 3699177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal default: 3700177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.wtf(LOG_TAG, "Got an id (%d) that I cannot create!", id); 3701177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3702177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3703177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal return null; 3704177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3705177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3706177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3707177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal public void onLoadFinished(Loader<ObjectCursor<Account>> loader, 3708177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal ObjectCursor<Account> data) { 3709177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data == null) { 3710177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.e(LOG_TAG, "Received null cursor from loader id: %d", loader.getId()); 3711177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3712177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal switch (loader.getId()) { 3713177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_ACCOUNT_CURSOR: 3714d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal // We have received an update on the list of accounts. 3715177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data == null) { 3716177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Nothing useful to do if we have no valid data. 3717177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3718177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3719761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang final long count = data.getCount(); 3720761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang if (count == 0) { 3721177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // If an empty cursor is returned, the MailAppProvider is indicating that 3722177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // no accounts have been specified. We want to navigate to the 3723177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // "add account" activity that will handle the intent returned by the 3724177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // MailAppProvider 3725177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3726177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // If the MailAppProvider believes that all accounts have been loaded, 3727177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // and the account list is still empty, we want to prompt the user to add 3728177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // an account. 3729177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Bundle extras = data.getExtras(); 3730177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final boolean accountsLoaded = 3731177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal extras.getInt(AccountCursorExtraKeys.ACCOUNTS_LOADED) != 0; 3732177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3733177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (accountsLoaded) { 3734177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Intent noAccountIntent = MailAppProvider.getNoAccountIntent 3735177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal (mContext); 3736177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (noAccountIntent != null) { 3737177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mActivity.startActivityForResult(noAccountIntent, 3738177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal ADD_ACCOUNT_REQUEST_CODE); 3739177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3740177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3741177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } else { 3742177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final boolean accountListUpdated = accountsUpdated(data); 3743c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal if (!mHaveAccountList || accountListUpdated) { 3744c04cf7e8a7be800902c59ac6d771449d04f1bca9Vikram Aggarwal mHaveAccountList = updateAccounts(data); 3745177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3746761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang Analytics.getInstance().setCustomDimension(Analytics.CD_INDEX_ACCOUNT_COUNT, 3747761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang Long.toString(count)); 3748177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3749177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3750177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal case LOADER_ACCOUNT_UPDATE_CURSOR: 3751177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // We have received an update for current account. 3752177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (data != null && data.moveToFirst()) { 3753177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Account updatedAccount = data.getModel(); 3754d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal // Make sure that this is an update for the current account 3755177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (updatedAccount.uri.equals(mAccount.uri)) { 3756177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal final Settings previousSettings = mAccount.settings; 3757177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3758177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Update the controller's reference to the current account 3759177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mAccount = updatedAccount; 3760177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.d(LOG_TAG, "AbstractActivityController.onLoadFinished(): " 3761177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal + "mAccount = %s", mAccount.uri); 3762177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3763177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // Only notify about a settings change if something differs 3764177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal if (!Objects.equal(mAccount.settings, previousSettings)) { 3765177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal mAccountObservers.notifyChanged(); 3766177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3767177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal perhapsEnterWaitMode(); 376862e1496cb42c21b5348ebe795cd2fabd7574d3e1Régis Décamps perhapsStartWelcomeTour(); 3769177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } else { 3770177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal LogUtils.e(LOG_TAG, "Got update for account: %s with current account:" 3771177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal + " %s", updatedAccount.uri, mAccount.uri); 3772177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // We need to restart the loader, so the correct account information 3773177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal // will be returned. 3774177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal restartOptionalLoader(LOADER_ACCOUNT_UPDATE_CURSOR, this, Bundle.EMPTY); 3775177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3776177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3777177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal break; 3778177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3779177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3780177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3781177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal @Override 3782177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal public void onLoaderReset(Loader<ObjectCursor<Account>> loader) { 3783d70fe49cabf896e87574bcb2e57e8a32608537beVikram Aggarwal // Do nothing. In onLoadFinished() we copy the relevant data from the cursor. 3784177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3785177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal } 3786177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal 3787177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal /** 378862e1496cb42c21b5348ebe795cd2fabd7574d3e1Régis Décamps * Loads the preference that tells whether the welcome tour should be displayed, 378962e1496cb42c21b5348ebe795cd2fabd7574d3e1Régis Décamps * and calls the callback with this value. 379062e1496cb42c21b5348ebe795cd2fabd7574d3e1Régis Décamps * For this to function, the account must have been synced. 379162e1496cb42c21b5348ebe795cd2fabd7574d3e1Régis Décamps */ 379262e1496cb42c21b5348ebe795cd2fabd7574d3e1Régis Décamps private void perhapsStartWelcomeTour() { 3793550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook new AsyncTask<Void, Void, Boolean>() { 3794550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook @Override 3795550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook protected Boolean doInBackground(Void... params) { 3796550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook if (mActivity.wasLatestWelcomeTourShownOnDeviceForAllAccounts()) { 3797550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook // No need to go through the WelcomeStateLoader machinery. 3798550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook return false; 3799550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook } 3800550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook return true; 3801550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook } 3802f318bc3cb806774a07421a413a918aa6afb8792fRégis Décamps 3803550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook @Override 3804550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook protected void onPostExecute(Boolean result) { 3805550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook if (result) { 3806550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook if (mAccount != null && mAccount.isAccountReady()) { 3807550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook LoaderManager.LoaderCallbacks<?> welcomeLoaderCallbacks = 3808550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook mActivity.getWelcomeCallbacks(); 3809550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook if (welcomeLoaderCallbacks != null) { 3810550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook // The callback is responsible for showing the tour when appropriate. 3811550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook mActivity.getLoaderManager().initLoader(LOADER_WELCOME_TOUR_ACCOUNTS, 3812550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook Bundle.EMPTY, welcomeLoaderCallbacks); 3813550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook } 3814550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook } 3815550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook } 381662e1496cb42c21b5348ebe795cd2fabd7574d3e1Régis Décamps } 3817550f15f6ab58abe8dca08ac8a0032b8e8930093dPaul Westbrook }.execute(); 381862e1496cb42c21b5348ebe795cd2fabd7574d3e1Régis Décamps } 381962e1496cb42c21b5348ebe795cd2fabd7574d3e1Régis Décamps 382062e1496cb42c21b5348ebe795cd2fabd7574d3e1Régis Décamps /** 3821f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal * Updates controller state based on search results and shows first conversation if required. 3822f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal */ 3823715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void perhapsShowFirstSearchResult() { 3824d27009ac6644a85ebcd1c705f40d2b5e9fd03573mindyp if (mCurrentConversation == null) { 3825d27009ac6644a85ebcd1c705f40d2b5e9fd03573mindyp // Shown for search results in two-pane mode only. 3826d27009ac6644a85ebcd1c705f40d2b5e9fd03573mindyp mHaveSearchResults = Intent.ACTION_SEARCH.equals(mActivity.getIntent().getAction()) 3827d27009ac6644a85ebcd1c705f40d2b5e9fd03573mindyp && mConversationListCursor.getCount() > 0; 3828d27009ac6644a85ebcd1c705f40d2b5e9fd03573mindyp if (!shouldShowFirstConversation()) { 3829d27009ac6644a85ebcd1c705f40d2b5e9fd03573mindyp return; 3830d27009ac6644a85ebcd1c705f40d2b5e9fd03573mindyp } 3831d27009ac6644a85ebcd1c705f40d2b5e9fd03573mindyp mConversationListCursor.moveToPosition(0); 3832d27009ac6644a85ebcd1c705f40d2b5e9fd03573mindyp final Conversation conv = new Conversation(mConversationListCursor); 3833d27009ac6644a85ebcd1c705f40d2b5e9fd03573mindyp conv.position = 0; 3834d27009ac6644a85ebcd1c705f40d2b5e9fd03573mindyp onConversationSelected(conv, true /* checkSafeToModifyFragments */); 3835f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal } 3836f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal } 3837f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal 3838f0ef23054a2311f898955178ff53a2f29ca425c9Vikram Aggarwal /** 3839e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal * Destroy the pending {@link DestructiveAction} till now and assign the given action as the 3840e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal * next destructive action.. 3841e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal * @param nextAction the next destructive action to be performed. This can be null. 3842e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal */ 3843715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void destroyPending(DestructiveAction nextAction) { 3844e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal // If there is a pending action, perform that first. 3845e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal if (mPendingDestruction != null) { 3846e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal mPendingDestruction.performAction(); 3847e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal } 3848e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal mPendingDestruction = nextAction; 3849e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal } 3850e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal 3851e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal /** 3852e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal * Register a destructive action with the controller. This performs the previous destructive 3853acaa3c0aa2335e0a635601e09c955388d698dfdaVikram Aggarwal * action as a side effect. This method is final because we don't want the child classes to 38543d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal * embellish this method any more. 3855715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param action the action to register. 3856e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal */ 3857715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private void registerDestructiveAction(DestructiveAction action) { 3858e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal // TODO(viki): This is not a good idea. The best solution is for clients to request a 3859e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal // destructive action from the controller and for the controller to own the action. This is 3860e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal // a half-way solution while refactoring DestructiveAction. 3861e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal destroyPending(action); 3862e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal } 3863e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal 3864531488ed848766708252a5fdc01c4ecf0fd167d1Vikram Aggarwal @Override 386530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public final DestructiveAction getBatchAction(int action, UndoCallback undoCallback) { 3866c41139509b1eb6dfc9bdae88ccc7d16eac85e2cfVikram Aggarwal final DestructiveAction da = new ConversationAction(action, mSelectedSet.values(), true); 386730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao da.setUndoCallback(undoCallback); 3868e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal registerDestructiveAction(da); 3869e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal return da; 3870e8a85328eadff76fcd78141f1343bde0a1cd27e7Vikram Aggarwal } 387141e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal 3872de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira @Override 387330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public final DestructiveAction getDeferredBatchAction(int action, UndoCallback undoCallback) { 387430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return getDeferredAction(action, mSelectedSet.values(), true, undoCallback); 3875f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp } 3876f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp 3877f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp /** 3878f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * Get a destructive action for a menu action. This is a temporary method, 3879f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * to control the profusion of {@link DestructiveAction} classes that are 3880f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * created. Please do not copy this paradigm. 3881f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * @param action the resource ID of the menu action: R.id.delete, for 3882f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * example 3883f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * @param target the conversations to act upon. 3884f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp * @return a {@link DestructiveAction} that performs the specified action. 3885f0656a1ed2aaf07ee738505faa80b0723c8d217fmindyp */ 3886715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal private DestructiveAction getDeferredAction(int action, Collection<Conversation> target, 388730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao boolean batch, UndoCallback callback) { 388830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao ConversationAction cAction = new ConversationAction(action, target, batch); 388930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao cAction.setUndoCallback(callback); 389030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return cAction; 3891de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira } 3892de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira 3893bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal /** 3894bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal * Class to change the folders that are assigned to a set of conversations. This is destructive 3895bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal * because the user can remove the current folder from the conversation, in which case it has 3896bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal * to be animated away from the current folder. 3897bc67bb1211654e69b1233e0f8759771873ca773eVikram Aggarwal */ 389841e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal private class FolderDestruction implements DestructiveAction { 389977eee625cd8c317c605acfd06cd3a7e22120a0fdPaul Westbrook private final Collection<Conversation> mTarget; 39008db7e407109532557718c6b8064792f2df7a073dMindy Pereira private final ArrayList<FolderOperation> mFolderOps = new ArrayList<FolderOperation>(); 390141e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal private final boolean mIsDestructive; 39027f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal /** Whether this destructive action has already been performed */ 39037f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal private boolean mCompleted; 3904e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon private final boolean mIsSelectedSet; 3905e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon private final boolean mShowUndo; 3906e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon private final int mAction; 39076a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy private final Folder mActionFolder; 390841e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal 390930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao private UndoCallback mUndoCallback; 391030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 391141e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal /** 391241e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal * Create a new folder destruction object to act on the given conversations. 3913715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param target conversations to act upon. 39146a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy * @param actionFolder the {@link Folder} being acted upon, used for displaying the undo bar 391541e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal */ 39167f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal private FolderDestruction(final Collection<Conversation> target, 39178db7e407109532557718c6b8064792f2df7a073dMindy Pereira final Collection<FolderOperation> folders, boolean isDestructive, boolean isBatch, 39186a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy boolean showUndo, int action, final Folder actionFolder) { 391977eee625cd8c317c605acfd06cd3a7e22120a0fdPaul Westbrook mTarget = ImmutableList.copyOf(target); 39208db7e407109532557718c6b8064792f2df7a073dMindy Pereira mFolderOps.addAll(folders); 392141e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal mIsDestructive = isDestructive; 3922f3a455644f0899a01fff4782811fcff473f9aff0Mindy Pereira mIsSelectedSet = isBatch; 392306642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira mShowUndo = showUndo; 392401f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira mAction = action; 39256a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy mActionFolder = actionFolder; 392641e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal } 392741e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal 392841e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal @Override 392930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public void setUndoCallback(UndoCallback undoCallback) { 393030c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao mUndoCallback = undoCallback; 393130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao } 393230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao 393330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao @Override 393441e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal public void performAction() { 39357f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal if (isPerformed()) { 39367f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal return; 39377f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal } 393806642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira if (mIsDestructive && mShowUndo) { 3939cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp ToastBarOperation undoOp = new ToastBarOperation(mTarget.size(), mAction, 39406a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy ToastBarOperation.UNDO, mIsSelectedSet, mActionFolder); 394141e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal onUndoAvailable(undoOp); 394241e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal } 39438db7e407109532557718c6b8064792f2df7a073dMindy Pereira // For each conversation, for each operation, add/ remove the 39448db7e407109532557718c6b8064792f2df7a073dMindy Pereira // appropriate folders. 3945cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp ArrayList<ConversationOperation> ops = new ArrayList<ConversationOperation>(); 3946cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp ArrayList<Uri> folderUris; 3947cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp ArrayList<Boolean> adds; 39488db7e407109532557718c6b8064792f2df7a073dMindy Pereira for (Conversation target : mTarget) { 3949cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp HashMap<Uri, Folder> targetFolders = Folder.hashMapForFolders(target 3950cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp .getRawFolders()); 3951cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp folderUris = new ArrayList<Uri>(); 3952cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp adds = new ArrayList<Boolean>(); 395301f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira if (mIsDestructive) { 395401f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira target.localDeleteOnUpdate = true; 395501f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira } 39568db7e407109532557718c6b8064792f2df7a073dMindy Pereira for (FolderOperation op : mFolderOps) { 3957259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy folderUris.add(op.mFolder.folderUri.fullUri); 3958cb0b30ee1d5cfcc267bc7de1e6ad78ed766c1e50mindyp adds.add(op.mAdd ? Boolean.TRUE : Boolean.FALSE); 39598db7e407109532557718c6b8064792f2df7a073dMindy Pereira if (op.mAdd) { 3960259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy targetFolders.put(op.mFolder.folderUri.fullUri, op.mFolder); 39618db7e407109532557718c6b8064792f2df7a073dMindy Pereira } else { 3962259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy targetFolders.remove(op.mFolder.folderUri.fullUri); 39638db7e407109532557718c6b8064792f2df7a073dMindy Pereira } 39648db7e407109532557718c6b8064792f2df7a073dMindy Pereira } 396526746eb4acb159f3ce0d411c10d85a1de3e958a0Paul Westbrook ops.add(mConversationListCursor.getConversationFolderOperation(target, 396630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao folderUris, adds, targetFolders.values(), mUndoCallback)); 3967389f0b21a9b21bc3607b810c88272d06d48d0fe6mindyp } 3968389f0b21a9b21bc3607b810c88272d06d48d0fe6mindyp if (mConversationListCursor != null) { 39699e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy mConversationListCursor.updateBulkValues(ops); 39708db7e407109532557718c6b8064792f2df7a073dMindy Pereira } 39717f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal refreshConversationList(); 3972f3a455644f0899a01fff4782811fcff473f9aff0Mindy Pereira if (mIsSelectedSet) { 3973f3a455644f0899a01fff4782811fcff473f9aff0Mindy Pereira mSelectedSet.clear(); 3974f3a455644f0899a01fff4782811fcff473f9aff0Mindy Pereira } 39757f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal } 39768db7e407109532557718c6b8064792f2df7a073dMindy Pereira 39777f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal /** 39787f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal * Returns true if this action has been performed, false otherwise. 3979839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang * 39807f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal */ 39817f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal private synchronized boolean isPerformed() { 39827f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal if (mCompleted) { 39837f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal return true; 398441e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal } 39857f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal mCompleted = true; 39867f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal return false; 398741e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal } 398841e6e71568a0e7a32ebeaf909a4f6cb3ba4f47cfVikram Aggarwal } 39897f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal 3990c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp public final DestructiveAction getFolderChange(Collection<Conversation> target, 3991c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp Collection<FolderOperation> folders, boolean isDestructive, boolean isBatch, 399230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao boolean showUndo, final boolean isMoveTo, final Folder actionFolder, 399330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao UndoCallback undoCallback) { 3994c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp final DestructiveAction da = getDeferredFolderChange(target, folders, isDestructive, 399530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao isBatch, showUndo, isMoveTo, actionFolder, undoCallback); 3996c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp registerDestructiveAction(da); 3997c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp return da; 3998c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp } 3999c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp 4000c84759cc974256b6af5545c4bd993b81a0a98f6fmindyp public final DestructiveAction getDeferredFolderChange(Collection<Conversation> target, 40018db7e407109532557718c6b8064792f2df7a073dMindy Pereira Collection<FolderOperation> folders, boolean isDestructive, boolean isBatch, 400230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao boolean showUndo, final boolean isMoveTo, final Folder actionFolder, 400330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao UndoCallback undoCallback) { 400430c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final DestructiveAction fd = new FolderDestruction(target, folders, isDestructive, isBatch, 400530c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao showUndo, isMoveTo ? R.id.move_folder : R.id.change_folders, actionFolder); 400630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao fd.setUndoCallback(undoCallback); 400730c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return fd; 400801f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira } 400901f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira 401001f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira @Override 401101f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira public final DestructiveAction getDeferredRemoveFolder(Collection<Conversation> target, 401201f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira Folder toRemove, boolean isDestructive, boolean isBatch, 401330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao boolean showUndo, UndoCallback undoCallback) { 401401f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira Collection<FolderOperation> folderOps = new ArrayList<FolderOperation>(); 401501f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira folderOps.add(new FolderOperation(toRemove, false)); 401630c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final DestructiveAction da = new FolderDestruction(target, folderOps, isDestructive, isBatch, 40176a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy showUndo, R.id.remove_folder, mFolder); 401830c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao da.setUndoCallback(undoCallback); 401930c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao return da; 402001f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira } 402101f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira 40224f4782bcc53e13b30f1fd417beb1a6c04a54faedVikram Aggarwal @Override 40234f4782bcc53e13b30f1fd417beb1a6c04a54faedVikram Aggarwal public final void refreshConversationList() { 402475daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal final ConversationListFragment convList = getConversationListFragment(); 402575daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal if (convList == null) { 402675daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal return; 402775daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal } 402875daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal convList.requestListRefresh(); 402975daee52f08c9bf66652b9bddf42cfbd1ca71987Vikram Aggarwal } 4030c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein 4031c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein protected final ActionClickedListener getUndoClickedListener( 4032c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein final AnimatedAdapter listAdapter) { 4033c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein return new ActionClickedListener() { 4034c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein @Override 4035f8ccdcfc26f362d9c20771e2295a0c0e8d1195f3Andrew Sapperstein public void onActionClicked(Context context) { 4036c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein if (mAccount.undoUri != null) { 4037c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein // NOTE: We might want undo to return the messages affected, in which case 4038c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein // the resulting cursor might be interesting... 4039c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein // TODO: Use UIProvider.SEQUENCE_QUERY_PARAMETER to indicate the set of 4040c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein // commands to undo 4041c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein if (mConversationListCursor != null) { 4042c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein mConversationListCursor.undo( 4043c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein mActivity.getActivityContext(), mAccount.undoUri); 4044c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 4045c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein if (listAdapter != null) { 4046c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein listAdapter.setUndo(true); 4047c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 4048c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 4049c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 4050c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein }; 4051c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 4052c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein 405341b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal /** 405441b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal * Shows an error toast in the bottom when a folder was not fetched successfully. 405541b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal * @param folder the folder which could not be fetched. 405641b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal * @param replaceVisibleToast if true, this should replace any currently visible toast. 405741b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal */ 40589d7519d18e8ddbcdd59b37eec7c85210fca0e8c2Andrew Sapperstein protected final void showErrorToast(final Folder folder, boolean replaceVisibleToast) { 405900179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein 406041b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal final ActionClickedListener listener; 406141b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal final int actionTextResourceId; 406200179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein final int lastSyncResult = folder.lastSyncResult; 406341b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal switch (lastSyncResult & 0x0f) { 406400179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein case UIProvider.LastSyncResult.CONNECTION_ERROR: 406541b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // The sync request that caused this failure. 406641b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal final int syncRequest = lastSyncResult >> 4; 406741b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // Show: User explicitly pressed the refresh button and there is no connection 406841b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // Show: The first time the user enters the app and there is no connection 406941b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // TODO(viki): Implement this. 407041b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // Reference: http://b/7202801 407141b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal final boolean showToast = (syncRequest & UIProvider.SyncStatus.USER_REFRESH) != 0; 407241b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // Don't show: Already in the app; user switches to a synced label 407341b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal // Don't show: In a live label and a background sync fails 407441b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal final boolean avoidToast = !showToast && (folder.syncWindow > 0 407541b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal || (syncRequest & UIProvider.SyncStatus.BACKGROUND_SYNC) != 0); 407641b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal if (avoidToast) { 407741b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal return; 407841b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal } 407900179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein listener = getRetryClickedListener(folder); 408000179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein actionTextResourceId = R.string.retry; 408100179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein break; 408200179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein case UIProvider.LastSyncResult.AUTH_ERROR: 408300179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein listener = getSignInClickedListener(); 408400179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein actionTextResourceId = R.string.signin; 408500179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein break; 408600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein case UIProvider.LastSyncResult.SECURITY_ERROR: 408700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein return; // Currently we do nothing for security errors. 408800179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein case UIProvider.LastSyncResult.STORAGE_ERROR: 408900179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein listener = getStorageErrorClickedListener(); 409000179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein actionTextResourceId = R.string.info; 409100179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein break; 409200179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein case UIProvider.LastSyncResult.INTERNAL_ERROR: 409300179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein listener = getInternalErrorClickedListener(); 409400179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein actionTextResourceId = R.string.report; 409500179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein break; 409600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein default: 409700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein return; 409800179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 409941b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal mToastBar.show(listener, 410041b9e8f7bea47bbcae71b9ae81c3608a00a90e70Vikram Aggarwal Utils.getSyncStatusText(mActivity.getActivityContext(), lastSyncResult), 410100179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein actionTextResourceId, 41029d7519d18e8ddbcdd59b37eec7c85210fca0e8c2Andrew Sapperstein replaceVisibleToast, 41036a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy new ToastBarOperation(1, 0, ToastBarOperation.ERROR, false, folder)); 4104c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 4105c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein 410600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein private ActionClickedListener getRetryClickedListener(final Folder folder) { 4107c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein return new ActionClickedListener() { 4108c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein @Override 4109f8ccdcfc26f362d9c20771e2295a0c0e8d1195f3Andrew Sapperstein public void onActionClicked(Context context) { 4110c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein final Uri uri = folder.refreshUri; 4111c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein 4112c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein if (uri != null) { 41134969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook startAsyncRefreshTask(uri); 4114c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 4115c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 4116c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein }; 4117c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 411800179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein 411900179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein private ActionClickedListener getSignInClickedListener() { 412000179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein return new ActionClickedListener() { 412100179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein @Override 4122f8ccdcfc26f362d9c20771e2295a0c0e8d1195f3Andrew Sapperstein public void onActionClicked(Context context) { 4123122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook promptUserForAuthentication(mAccount); 412400179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 412500179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein }; 412600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 412700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein 412800179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein private ActionClickedListener getStorageErrorClickedListener() { 412900179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein return new ActionClickedListener() { 413000179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein @Override 4131f8ccdcfc26f362d9c20771e2295a0c0e8d1195f3Andrew Sapperstein public void onActionClicked(Context context) { 41324969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook showStorageErrorDialog(); 413300179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 413400179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein }; 413500179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 413600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein 41374969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook private void showStorageErrorDialog() { 41384969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook DialogFragment fragment = (DialogFragment) 41394969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook mFragmentManager.findFragmentByTag(SYNC_ERROR_DIALOG_FRAGMENT_TAG); 41404969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook if (fragment == null) { 41414969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook fragment = SyncErrorDialogFragment.newInstance(); 41424969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 41434969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook fragment.show(mFragmentManager, SYNC_ERROR_DIALOG_FRAGMENT_TAG); 41444969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 41454969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook 414600179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein private ActionClickedListener getInternalErrorClickedListener() { 414700179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein return new ActionClickedListener() { 414800179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein @Override 4149f8ccdcfc26f362d9c20771e2295a0c0e8d1195f3Andrew Sapperstein public void onActionClicked(Context context) { 415083e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook Utils.sendFeedback(mActivity, mAccount, true /* reportingProblem */); 415100179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 415200179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein }; 415300179f19e413461498599ab7e6eb6914cc5c3671Andrew Sapperstein } 41544969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook 41554969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook @Override 41564969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook public void onFooterViewErrorActionClick(Folder folder, int errorStatus) { 41574969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook Uri uri = null; 41584969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook switch (errorStatus) { 41594969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook case UIProvider.LastSyncResult.CONNECTION_ERROR: 41604969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook if (folder != null && folder.refreshUri != null) { 41614969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook uri = folder.refreshUri; 41624969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 41634969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook break; 41644969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook case UIProvider.LastSyncResult.AUTH_ERROR: 4165122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook promptUserForAuthentication(mAccount); 41664969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook return; 41674969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook case UIProvider.LastSyncResult.SECURITY_ERROR: 41684969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook return; // Currently we do nothing for security errors. 41694969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook case UIProvider.LastSyncResult.STORAGE_ERROR: 41704969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook showStorageErrorDialog(); 41714969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook return; 41724969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook case UIProvider.LastSyncResult.INTERNAL_ERROR: 417383e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook Utils.sendFeedback(mActivity, mAccount, true /* reportingProblem */); 41744969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook return; 41754969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook default: 41764969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook return; 41774969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 41784969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook 41794969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook if (uri != null) { 41804969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook startAsyncRefreshTask(uri); 41814969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 41824969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 41834969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook 41844969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook @Override 41854969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook public void onFooterViewLoadMoreClick(Folder folder) { 41864969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook if (folder != null && folder.loadMoreUri != null) { 41874969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook startAsyncRefreshTask(folder.loadMoreUri); 41884969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 41894969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 41904969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook 41914969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook private void startAsyncRefreshTask(Uri uri) { 41924969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook if (mFolderSyncTask != null) { 41934969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook mFolderSyncTask.cancel(true); 41944969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 41954969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook mFolderSyncTask = new AsyncRefreshTask(mActivity.getActivityContext(), uri); 41964969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook mFolderSyncTask.execute(); 41974969e0c5f8ab837e1b0d29ea56d220e6404e9250Paul Westbrook } 4198122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook 4199122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook private void promptUserForAuthentication(Account account) { 4200429399b738f444911117978bf8229036e8814b1ePaul Westbrook if (account != null && !Utils.isEmpty(account.reauthenticationIntentUri)) { 4201122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook final Intent authenticationIntent = 4202122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook new Intent(Intent.ACTION_VIEW, account.reauthenticationIntentUri); 4203122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook mActivity.startActivityForResult(authenticationIntent, REAUTHENTICATE_REQUEST_CODE); 4204122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook } 4205122f7c2cf45cd5f07462a7b0a553f82828a8b1a2Paul Westbrook } 4206ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp 4207ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp @Override 4208ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp public void onAccessibilityStateChanged() { 4209ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp // Clear the cache of objects. 4210ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp ConversationItemViewModel.onAccessibilityUpdated(); 4211ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp // Re-render the list if it exists. 4212a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal final ConversationListFragment frag = getConversationListFragment(); 4213ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp if (frag != null) { 4214ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp AnimatedAdapter adapter = frag.getAnimatedAdapter(); 4215ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp if (adapter != null) { 4216ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp adapter.notifyDataSetInvalidated(); 4217ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp } 4218ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp } 4219ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp } 42206cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal 42216cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal @Override 422230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao public void makeDialogListener (final int action, final boolean isBatch, 422330c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao UndoCallback undoCallback) { 4224b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal final Collection<Conversation> target; 4225b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal if (isBatch) { 4226b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal target = mSelectedSet.values(); 4227b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal } else { 4228b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal LogUtils.d(LOG_TAG, "Will act upon %s", mCurrentConversation); 4229b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal target = Conversation.listOf(mCurrentConversation); 4230b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal } 423130c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao final DestructiveAction destructiveAction = getDeferredAction(action, target, isBatch, 423230c881a7d31203fc7b233abf4a0c1413de4cd517Jin Cao undoCallback); 42336cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal mDialogAction = action; 4234b8c3171710b7f97247fd0c841ce95f5f515ef576Vikram Aggarwal mDialogFromSelectedSet = isBatch; 42356cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal mDialogListener = new AlertDialog.OnClickListener() { 42366cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal @Override 42376cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal public void onClick(DialogInterface dialog, int which) { 4238caaeed3837316175111bb16e6b60aeb0d523debfScott Kennedy delete(action, target, destructiveAction, isBatch); 42396cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal // Afterwards, let's remove references to the listener and the action. 42406cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal setListener(null, -1); 42416cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal } 42426cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal }; 42436cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal } 42446cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal 42456cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal @Override 42466cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal public AlertDialog.OnClickListener getListener() { 42476cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal return mDialogListener; 42486cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal } 42496cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal 42506cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal /** 42516cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal * Sets the listener for the positive action on a confirmation dialog. Since only a single 42526cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal * confirmation dialog can be shown, this overwrites the previous listener. It is safe to 42536cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal * unset the listener; in which case action should be set to -1. 4254715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param listener the listener that will perform the task for this dialog's positive action. 4255715f83dc3556a0e33cba63acdf4b4842cc042af8Vikram Aggarwal * @param action the action that created this dialog. 42566cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal */ 42576cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal private void setListener(AlertDialog.OnClickListener listener, final int action){ 42586cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal mDialogListener = listener; 42596cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal mDialogAction = action; 42606cadbfce032c5f8d61c873d91989bff1fb7cc4e5Vikram Aggarwal } 426169a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 426269a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal @Override 426369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal public VeiledAddressMatcher getVeiledAddressMatcher() { 426469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal return mVeiledMatcher; 4265a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 4266a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal 4267a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal @Override 4268a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal public void setDetachedMode() { 4269a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // Tell the conversation list not to select anything. 4270a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal final ConversationListFragment frag = getConversationListFragment(); 4271a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal if (frag != null) { 4272a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal frag.setChoiceNone(); 427381230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal } else if (mIsTablet) { 427481230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal // How did we ever land here? Detached mode, and no CLF on tablet??? 4275a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal LogUtils.e(LOG_TAG, "AAC.setDetachedMode(): CLF = null!"); 4276a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 4277a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal mDetachedConvUri = mCurrentConversation.uri; 4278a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 4279a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal 4280a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal private void clearDetachedMode() { 4281a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // Tell the conversation list to go back to its usual selection behavior. 4282a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal final ConversationListFragment frag = getConversationListFragment(); 4283a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal if (frag != null) { 4284a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal frag.revertChoiceMode(); 428581230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal } else if (mIsTablet) { 428681230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal // How did we ever land here? Detached mode, and no CLF on tablet??? 428781230ee24b65099109ee91add5a137d3795c454aVikram Aggarwal LogUtils.e(LOG_TAG, "AAC.clearDetachedMode(): CLF = null on tablet!"); 4288a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 4289a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal mDetachedConvUri = null; 4290a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 429112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 429261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang @Override 429361f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang public DrawerController getDrawerController() { 429461f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang return mDrawerListener; 429561f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 429661f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 429761f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang private class MailDrawerListener extends Observable<DrawerLayout.DrawerListener> 429861f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang implements DrawerLayout.DrawerListener, DrawerController { 4299a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein private int mDrawerState; 4300fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein private float mOldSlideOffset; 4301a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein 4302a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein public MailDrawerListener() { 4303a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mDrawerState = DrawerLayout.STATE_IDLE; 4304fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein mOldSlideOffset = 0.f; 4305a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein } 4306a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein 430712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang @Override 43083e95fe9af0d1f8d7557d6b8e9daf4cf08aade140Andy Huang public boolean isDrawerEnabled() { 43093e95fe9af0d1f8d7557d6b8e9daf4cf08aade140Andy Huang return AbstractActivityController.this.isDrawerEnabled(); 43103e95fe9af0d1f8d7557d6b8e9daf4cf08aade140Andy Huang } 43113e95fe9af0d1f8d7557d6b8e9daf4cf08aade140Andy Huang 43123e95fe9af0d1f8d7557d6b8e9daf4cf08aade140Andy Huang @Override 431361f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang public void registerDrawerListener(DrawerLayout.DrawerListener l) { 431461f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang registerObserver(l); 431561f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 431661f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 431761f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang @Override 431861f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang public void unregisterDrawerListener(DrawerLayout.DrawerListener l) { 431961f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang unregisterObserver(l); 432061f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 432161f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 432261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang @Override 432361f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang public boolean isDrawerOpen() { 432461f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang return isDrawerEnabled() && mDrawerContainer.isDrawerOpen(mDrawerPullout); 432561f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 432661f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 432761f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang @Override 432861f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang public boolean isDrawerVisible() { 432961f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang return isDrawerEnabled() && mDrawerContainer.isDrawerVisible(mDrawerPullout); 433061f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 433161f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 433261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang @Override 4333f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang public void toggleDrawerState() { 4334f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang AbstractActivityController.this.toggleDrawerState(); 4335f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang } 4336f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang 4337f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang @Override 433812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang public void onDrawerOpened(View drawerView) { 433912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerToggle.onDrawerOpened(drawerView); 434061f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 434161f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang for (DrawerLayout.DrawerListener l : mObservers) { 434261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang l.onDrawerOpened(drawerView); 434361f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 434412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 434512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 434612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang @Override 434712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang public void onDrawerClosed(View drawerView) { 434812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerToggle.onDrawerClosed(drawerView); 434912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (mHasNewAccountOrFolder) { 435012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang refreshDrawer(); 435112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 435210c99efe431335ce8db9924c3dcb0f977f3c63f3Scott Kennedy 435310c99efe431335ce8db9924c3dcb0f977f3c63f3Scott Kennedy // When closed, we want to use either the burger, or up, based on where we are 435410c99efe431335ce8db9924c3dcb0f977f3c63f3Scott Kennedy final int mode = mViewMode.getMode(); 43559695e0046f79bd2d7166a411d6feff4cf0fb2539Jin Cao final boolean isTopLevel = Folder.isRoot(mFolder); 435610c99efe431335ce8db9924c3dcb0f977f3c63f3Scott Kennedy mDrawerToggle.setDrawerIndicatorEnabled(getShouldShowDrawerIndicator(mode, isTopLevel)); 435761f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 435861f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang for (DrawerLayout.DrawerListener l : mObservers) { 435961f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang l.onDrawerClosed(drawerView); 436061f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 436112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 436212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 436312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang /** 436412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * As part of the overriden function, it will animate the alpha of the conversation list 436512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * view along with the drawer sliding when we're in the process of switching accounts or 436612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * folders. Note, this is the same amount of work done as {@link ValueAnimator#ofFloat}. 436712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang */ 436812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang @Override 436912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang public void onDrawerSlide(View drawerView, float slideOffset) { 437012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerToggle.onDrawerSlide(drawerView, slideOffset); 437112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (mHasNewAccountOrFolder && mListViewForAnimating != null) { 437212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mListViewForAnimating.setAlpha(slideOffset); 437312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 4374fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein 4375fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // This code handles when to change the visibility of action items 4376fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // based on drawer state. The basic logic is that right when we 4377fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // open the drawer, we hide the action items. We show the action items 4378fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // when the drawer closes. However, due to the animation of the drawer closing, 4379fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // to make the reshowing of the action items feel right, we make the items visible 4380fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // slightly sooner. 4381fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // 4382fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // However, to make the animating behavior work properly, we have to know whether 4383fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // we're animating open or closed. Only if we're animating closed do we want to 4384fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // show the action items early. We save the last slide offset so that we can compare 4385fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein // the current slide offset to it to determine if we're opening or closing. 4386fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein if (mDrawerState == DrawerLayout.STATE_SETTLING) { 4387fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein if (mHideMenuItems && slideOffset < 0.15f && mOldSlideOffset > slideOffset) { 4388fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein mHideMenuItems = false; 438952882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein mActivity.supportInvalidateOptionsMenu(); 439043fab3224230c235db5be395f96096e1cac6b376Tony Mantler maybeEnableCabMode(); 4391fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein } else if (!mHideMenuItems && slideOffset > 0.f && mOldSlideOffset < slideOffset) { 4392fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein mHideMenuItems = true; 439352882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein mActivity.supportInvalidateOptionsMenu(); 439443fab3224230c235db5be395f96096e1cac6b376Tony Mantler disableCabMode(); 4395fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein } 4396fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein } else { 4397fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein if (mHideMenuItems && Float.compare(slideOffset, 0.f) == 0) { 4398fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein mHideMenuItems = false; 439952882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein mActivity.supportInvalidateOptionsMenu(); 440043fab3224230c235db5be395f96096e1cac6b376Tony Mantler maybeEnableCabMode(); 4401fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein } else if (!mHideMenuItems && slideOffset > 0.f) { 4402fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein mHideMenuItems = true; 440352882ff08fe9420fe2dbb3f681545a330222e9c8Andrew Sapperstein mActivity.supportInvalidateOptionsMenu(); 440443fab3224230c235db5be395f96096e1cac6b376Tony Mantler disableCabMode(); 4405fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein } 4406fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein } 4407fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein 4408fc5be1c9fb937c1e0b6e981581fbba2157a009acAndrew Sapperstein mOldSlideOffset = slideOffset; 440910c99efe431335ce8db9924c3dcb0f977f3c63f3Scott Kennedy 441010c99efe431335ce8db9924c3dcb0f977f3c63f3Scott Kennedy // If we're sliding, we always want to show the burger 441110c99efe431335ce8db9924c3dcb0f977f3c63f3Scott Kennedy mDrawerToggle.setDrawerIndicatorEnabled(true /* enable */); 441261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 441361f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang for (DrawerLayout.DrawerListener l : mObservers) { 441461f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang l.onDrawerSlide(drawerView, slideOffset); 441561f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 441612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 441712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 441812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang /** 441912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * This condition here should only be called when the drawer is stuck in a weird state 442012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * and doesn't register the onDrawerClosed, but shows up as idle. Make sure to refresh 442112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * and, more importantly, unlock the drawer when this is the case. 442212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang */ 442312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang @Override 442412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang public void onDrawerStateChanged(int newState) { 4425371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon LogUtils.d(LOG_TAG, "AAC onDrawerStateChanged %d", newState); 4426a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mDrawerState = newState; 4427a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mDrawerToggle.onDrawerStateChanged(mDrawerState); 442861f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 442961f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang for (DrawerLayout.DrawerListener l : mObservers) { 443061f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang l.onDrawerStateChanged(newState); 443161f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang } 443261f26c2d1c1d3735cf883b58fe7e45550bb1a54cAndy Huang 4433e764cfd130c4f92ae823fd1f361ab70439e8ec95Andy Huang if (mViewMode.isSearchMode()) { 4434371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon return; 4435371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon } 4436a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein if (mDrawerState == DrawerLayout.STATE_IDLE) { 4437a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein if (mHasNewAccountOrFolder) { 4438a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein refreshDrawer(); 4439a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein } 4440a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein if (mConversationListLoadFinishedIgnored) { 4441a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mConversationListLoadFinishedIgnored = false; 4442a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein final Bundle args = new Bundle(); 4443a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein args.putParcelable(BUNDLE_ACCOUNT_KEY, mAccount); 4444a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein args.putParcelable(BUNDLE_FOLDER_KEY, mFolder); 4445a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein mActivity.getLoaderManager().initLoader( 4446a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein LOADER_CONVERSATION_LIST, args, mListCursorCallbacks); 4447a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein } 444812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 444912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 445012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 445112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang /** 445212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * If we've reached a stable drawer state, unlock the drawer for usage, clear the 445312b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * conversation list, and finish end actions. Also, make 445412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang * {@link #mHasNewAccountOrFolder} false to reflect we're done changing. 445512b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang */ 445612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang public void refreshDrawer() { 445712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mHasNewAccountOrFolder = false; 445812b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); 445912b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang ConversationListFragment conversationList = getConversationListFragment(); 446012b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang if (conversationList != null) { 446112b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang conversationList.clear(); 446212b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 446354022ee4c98f02401ca567e643f24ed42aebe203Tony Mantler mFolderOrAccountObservers.notifyChanged(); 446412b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 4465a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein 4466a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein /** 4467a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein * Returns the most recent update of the {@link DrawerLayout}'s state provided 4468a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein * by {@link #onDrawerStateChanged(int)}. 4469a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein * @return The {@link DrawerLayout}'s current state. One of 4470a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein * {@link DrawerLayout#STATE_DRAGGING}, {@link DrawerLayout#STATE_IDLE}, 4471a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein * or {@link DrawerLayout#STATE_SETTLING}. 4472a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein */ 4473a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein public int getDrawerState() { 4474a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein return mDrawerState; 4475a3ce678020691f9aef7a3a4efcd015b396595486Andrew Sapperstein } 447612b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang } 447712b3ee458e04ac7e0b69302e671d10b24a5c98cfAndy Huang 44788a72b8590d9166ada55f69eeb083d2b8c5c915c9Scott Kennedy @Override 44798a72b8590d9166ada55f69eeb083d2b8c5c915c9Scott Kennedy public boolean isDrawerPullEnabled() { 4480371a71c7f41155a83526e4745c993585c236b9d7Martin Hibdon return true; 44818a72b8590d9166ada55f69eeb083d2b8c5c915c9Scott Kennedy } 44825747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein 44835747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein @Override 44845747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein public boolean shouldHideMenuItems() { 44855747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein return mHideMenuItems; 44865747e152fa606c20261b18431f4a9f0ff3be7b5aAndrew Sapperstein } 4487ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 4488ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang protected void navigateUpFolderHierarchy() { 4489ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang new AsyncTask<Void, Void, Folder>() { 4490ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang @Override 4491ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang protected Folder doInBackground(final Void... params) { 4492ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang if (mInbox == null) { 4493ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang // We don't have an inbox, but we need it 4494ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang final Cursor cursor = mContext.getContentResolver().query( 4495ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang mAccount.settings.defaultInbox, UIProvider.FOLDERS_PROJECTION, null, 4496ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang null, null); 4497ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 4498ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang if (cursor != null) { 4499ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang try { 4500ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang if (cursor.moveToFirst()) { 4501ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang mInbox = new Folder(cursor); 4502ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4503ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } finally { 4504ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang cursor.close(); 4505ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4506ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4507ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4508ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 4509ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang // Now try to load our parent 4510ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang final Folder folder; 4511ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 45125ac10036fd45cd2a6da32abd02e942617edec50dAlice Yang if (mFolder != null) { 4513e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon Cursor cursor = null; 4514e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon try { 4515e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon cursor = mContext.getContentResolver().query(mFolder.parent, 4516e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon UIProvider.FOLDERS_PROJECTION, null, null, null); 4517e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon 4518e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon if (cursor == null || !cursor.moveToFirst()) { 4519e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon // We couldn't load the parent, so use the inbox 4520e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon folder = mInbox; 4521e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon } else { 45225ac10036fd45cd2a6da32abd02e942617edec50dAlice Yang folder = new Folder(cursor); 4523e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon } 4524e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon } finally { 4525e78c40f7ea2159df17aec33ecc2599dfb866c3cdMartin Hibdon if (cursor != null) { 45265ac10036fd45cd2a6da32abd02e942617edec50dAlice Yang cursor.close(); 45275ac10036fd45cd2a6da32abd02e942617edec50dAlice Yang } 4528ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 45295ac10036fd45cd2a6da32abd02e942617edec50dAlice Yang } else { 45305ac10036fd45cd2a6da32abd02e942617edec50dAlice Yang folder = mInbox; 4531ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4532ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 4533ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang return folder; 4534ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4535ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang 4536ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang @Override 4537ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang protected void onPostExecute(final Folder result) { 4538ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang onFolderSelected(result); 4539ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4540ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); 4541ebeef1babe39de2c1d97429a93ea956c655cd377Alice Yang } 4542f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy 4543f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy @Override 4544f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy public Parcelable getConversationListScrollPosition(final String folderUri) { 4545f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy return mConversationListScrollPositions.getParcelable(folderUri); 4546f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy } 4547f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy 4548f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy @Override 4549f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy public void setConversationListScrollPosition(final String folderUri, 4550f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy final Parcelable savedPosition) { 4551f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy mConversationListScrollPositions.putParcelable(folderUri, savedPosition); 4552f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy } 455353de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein 455453de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein @Override 455553de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein public View.OnClickListener getNavigationViewClickListener() { 455653de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein return mHomeButtonListener; 455753de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein } 455853de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein 455953de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein // TODO: Fold this into the outer class when b/16627877 is fixed 456053de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein private class HomeButtonListener implements View.OnClickListener { 456153de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein 456253de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein @Override 456353de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein public void onClick(View v) { 456453de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein onUpPressed(); 456553de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein } 456653de448d6c67e56df4e3bcefb3e2d84c810e2e89Andrew Sapperstein } 45674a5c530b0a67e22bd74df8f10f29278dc8d86459Vikram Aggarwal} 4568