OnePaneController.java revision dd6a7ce32c4003bd0941e2f18fcf5b80b5cd43c5
1a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal/******************************************************************************* 2a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * Copyright (C) 2012 Google Inc. 3a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * Licensed to The Android Open Source Project. 4a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * 5a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * Licensed under the Apache License, Version 2.0 (the "License"); 6a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * you may not use this file except in compliance with the License. 7a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * You may obtain a copy of the License at 8a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * 9a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * http://www.apache.org/licenses/LICENSE-2.0 10a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * 11a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * Unless required by applicable law or agreed to in writing, software 12a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * distributed under the License is distributed on an "AS IS" BASIS, 13a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * See the License for the specific language governing permissions and 15a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * limitations under the License. 16a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal *******************************************************************************/ 17a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 18a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwalpackage com.android.mail.ui; 19a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 20d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwalimport android.app.Fragment; 21632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.app.FragmentManager; 22d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwalimport android.app.FragmentTransaction; 231ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huangimport android.app.LoaderManager.LoaderCallbacks; 24559c3b3d302b3f6d2c2cb43a909069d942652e34Mindy Pereiraimport android.net.Uri; 251ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwalimport android.os.Bundle; 26c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sappersteinimport android.text.Html; 27d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwalimport com.android.mail.ConversationListContext; 281ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwalimport com.android.mail.R; 29f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.browse.SecureConversationViewFragment; 30cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwalimport com.android.mail.providers.Account; 319b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereiraimport com.android.mail.providers.Conversation; 323982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereiraimport com.android.mail.providers.Folder; 33fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereiraimport com.android.mail.providers.Settings; 34fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereiraimport com.android.mail.providers.UIProvider; 359e85333dfc57e7c98ffef27cded4712ea598f554Paul Westbrookimport com.android.mail.utils.LogUtils; 36fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira 37a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal/** 38a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * Controller for one-pane Mail activity. One Pane is used for phones, where screen real estate is 39d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal * limited. This controller also does the layout, since the layout is simpler in the one pane case. 40a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal */ 41a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 42a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal// Called OnePaneActivityController in Gmail. 43a76e5aeff4a54ec70661de35be4f3ecb9d1d2fe2Mindy Pereirapublic final class OnePaneController extends AbstractActivityController { 442bfb5c0fa1cfe7f25c121d6435dc1a04439f7bacVikram Aggarwal /** Key used to store {@link #mLastFolderListTransactionId}. */ 453982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira private static final String FOLDER_LIST_TRANSACTION_KEY = "folder-list-transaction"; 462bfb5c0fa1cfe7f25c121d6435dc1a04439f7bacVikram Aggarwal /** Key used to store {@link #mLastInboxConversationListTransactionId} */ 470e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook private static final String INBOX_CONVERSATION_LIST_TRANSACTION_KEY = 480e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook "inbox_conversation-list-transaction"; 492bfb5c0fa1cfe7f25c121d6435dc1a04439f7bacVikram Aggarwal /** Key used to store {@link #mLastConversationListTransactionId} */ 503982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira private static final String CONVERSATION_LIST_TRANSACTION_KEY = "conversation-list-transaction"; 512bfb5c0fa1cfe7f25c121d6435dc1a04439f7bacVikram Aggarwal /** Key used to store {@link #mLastConversationTransactionId}. */ 523982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira private static final String CONVERSATION_TRANSACTION_KEY = "conversation-transaction"; 532bfb5c0fa1cfe7f25c121d6435dc1a04439f7bacVikram Aggarwal /** Key used to store {@link #mConversationListVisible}. */ 54649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal private static final String CONVERSATION_LIST_VISIBLE_KEY = "conversation-list-visible"; 552bfb5c0fa1cfe7f25c121d6435dc1a04439f7bacVikram Aggarwal /** Key used to store {@link #mConversationListNeverShown}. */ 56649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal private static final String CONVERSATION_LIST_NEVER_SHOWN_KEY = "conversation-list-never-shown"; 572bfb5c0fa1cfe7f25c121d6435dc1a04439f7bacVikram Aggarwal /** Key to store {@link #mInbox}. */ 582bfb5c0fa1cfe7f25c121d6435dc1a04439f7bacVikram Aggarwal private final static String SAVED_INBOX_KEY = "m-inbox"; 592d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook 603982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira private static final int INVALID_ID = -1; 612175d0a93263672d4498458c81b404b0999134baVikram Aggarwal private boolean mConversationListVisible = false; 620e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook private int mLastInboxConversationListTransactionId = INVALID_ID; 633982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira private int mLastConversationListTransactionId = INVALID_ID; 643982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira private int mLastConversationTransactionId = INVALID_ID; 653982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira private int mLastFolderListTransactionId = INVALID_ID; 663982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira private Folder mInbox; 67cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwal /** Whether a conversation list for this account has ever been shown.*/ 68cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwal private boolean mConversationListNeverShown = true; 69cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwal 70a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal /** 71a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * @param activity 72a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal * @param viewMode 73a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal */ 74a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal public OnePaneController(MailActivity activity, ViewMode viewMode) { 75a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal super(activity, viewMode); 76a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal } 77a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal 781ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 79632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void onRestoreInstanceState(Bundle inState) { 80632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.onRestoreInstanceState(inState); 813982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira // TODO(mindyp) handle saved state. 82649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal if (inState == null) { 83649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal return; 843982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } 85649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal mLastFolderListTransactionId = inState.getInt(FOLDER_LIST_TRANSACTION_KEY, INVALID_ID); 86649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal mLastInboxConversationListTransactionId = 87649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal inState.getInt(INBOX_CONVERSATION_LIST_TRANSACTION_KEY, INVALID_ID); 88649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal mLastConversationListTransactionId = 89649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal inState.getInt(CONVERSATION_LIST_TRANSACTION_KEY, INVALID_ID); 90649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal mLastConversationTransactionId = inState.getInt(CONVERSATION_TRANSACTION_KEY, INVALID_ID); 91649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal mConversationListVisible = inState.getBoolean(CONVERSATION_LIST_VISIBLE_KEY); 92649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal mConversationListNeverShown = inState.getBoolean(CONVERSATION_LIST_NEVER_SHOWN_KEY); 932bfb5c0fa1cfe7f25c121d6435dc1a04439f7bacVikram Aggarwal mInbox = inState.getParcelable(SAVED_INBOX_KEY); 943982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } 953982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira 963982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira @Override 973982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira public void onSaveInstanceState(Bundle outState) { 983982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira super.onSaveInstanceState(outState); 993982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira // TODO(mindyp) handle saved state. 1003982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira outState.putInt(FOLDER_LIST_TRANSACTION_KEY, mLastFolderListTransactionId); 1010e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook outState.putInt(INBOX_CONVERSATION_LIST_TRANSACTION_KEY, 1020e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook mLastInboxConversationListTransactionId); 1033982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira outState.putInt(CONVERSATION_LIST_TRANSACTION_KEY, mLastConversationListTransactionId); 1043982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira outState.putInt(CONVERSATION_TRANSACTION_KEY, mLastConversationTransactionId); 105649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal outState.putBoolean(CONVERSATION_LIST_VISIBLE_KEY, mConversationListVisible); 106649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal outState.putBoolean(CONVERSATION_LIST_NEVER_SHOWN_KEY, mConversationListNeverShown); 1072bfb5c0fa1cfe7f25c121d6435dc1a04439f7bacVikram Aggarwal outState.putParcelable(SAVED_INBOX_KEY, mInbox); 1083982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } 1093982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira 1103982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira @Override 111d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal public void resetActionBarIcon() { 112d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal final int mode = mViewMode.getMode(); 1136343feb48abdf2de6cc9bbc25859e614c0a15f50Vikram Aggarwal // If the viewmode is not set, preserve existing icon. 1146343feb48abdf2de6cc9bbc25859e614c0a15f50Vikram Aggarwal if (mode == ViewMode.UNKNOWN) { 1156343feb48abdf2de6cc9bbc25859e614c0a15f50Vikram Aggarwal return; 1166343feb48abdf2de6cc9bbc25859e614c0a15f50Vikram Aggarwal } 1172074a056bb2a634c66996225c55620d2aa6f7ac5Vikram Aggarwal if (!inInbox(mAccount, mConvListContext) 11868f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira || mode == ViewMode.SEARCH_RESULTS_LIST 11968f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira || mode == ViewMode.SEARCH_RESULTS_CONVERSATION 12068f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira || mode == ViewMode.CONVERSATION 12168f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira || mode == ViewMode.FOLDER_LIST) { 122d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal mActionBarView.setBackButton(); 123d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal } else { 124d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal mActionBarView.removeBackButton(); 125d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal } 126d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal } 127d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal 1287dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal /** 1297dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal * Returns true if the user is currently in the conversation list view, viewing the default 1307dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal * inbox. 1317dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal * @return 1327dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal */ 1332074a056bb2a634c66996225c55620d2aa6f7ac5Vikram Aggarwal private static boolean inInbox(final Account account, final ConversationListContext context) { 1342074a056bb2a634c66996225c55620d2aa6f7ac5Vikram Aggarwal // If we don't have valid state, then we are not in the inbox. 1352074a056bb2a634c66996225c55620d2aa6f7ac5Vikram Aggarwal if (account == null || context == null || context.folder == null 1362074a056bb2a634c66996225c55620d2aa6f7ac5Vikram Aggarwal || account.settings == null) { 1372074a056bb2a634c66996225c55620d2aa6f7ac5Vikram Aggarwal return false; 1382074a056bb2a634c66996225c55620d2aa6f7ac5Vikram Aggarwal } 1392074a056bb2a634c66996225c55620d2aa6f7ac5Vikram Aggarwal final Uri inboxUri = Settings.getDefaultInboxUri(account.settings); 140ae4ea997d3d3f3c8c11fc5a3e7f9d49f82b4e2e7Vikram Aggarwal return !ConversationListContext.isSearchResult(context) 141ae4ea997d3d3f3c8c11fc5a3e7f9d49f82b4e2e7Vikram Aggarwal && context.folder.uri.equals(inboxUri); 1423982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } 1433982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira 144d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal @Override 145cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwal public void onAccountChanged(Account account) { 146cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwal super.onAccountChanged(account); 147cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwal mConversationListNeverShown = true; 148cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwal } 149cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwal 150cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwal @Override 151d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal public boolean onCreate(Bundle savedInstanceState) { 1521ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal mActivity.setContentView(R.layout.one_pane_activity); 153d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal // The parent class sets the correct viewmode and starts the application off. 154d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal return super.onCreate(savedInstanceState); 1551ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 1561ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal 1571ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal @Override 1581ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal protected boolean isConversationListVisible() { 1592175d0a93263672d4498458c81b404b0999134baVikram Aggarwal return mConversationListVisible; 1601ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwal } 161d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal 162d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal @Override 163d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal public void onViewModeChanged(int newMode) { 164d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal super.onViewModeChanged(newMode); 165632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 166632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // When entering conversation list mode, hide and clean up any currently visible 167632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // conversation. 168632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // TODO: improve this transition 16949e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal if (ViewMode.isListMode(newMode)) { 170a3ed834c959ece3453c1b34953fabecb3b19c424Andy Huang mPagerController.hide(true /* changeVisibility */); 171632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 17249e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal // When we step away from the conversation mode, we don't have a current conversation 17349e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal // anymore. Let's blank it out so clients calling getCurrentConversation are not misled. 17449e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal if (!ViewMode.isConversationMode(newMode)) { 17549e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal setCurrentConversation(null); 17649e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal } 177a691fc799aa042fc178d5f194af55b7b63a16a7fVikram Aggarwal resetActionBarIcon(); 178d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal } 179d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal 180d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal @Override 1819b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira public void showConversationList(ConversationListContext listContext) { 182e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal super.showConversationList(listContext); 183e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal enableCabMode(); 1843982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira // TODO(viki): Check if the account has been changed since the previous 1853982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira // time. 186ae4ea997d3d3f3c8c11fc5a3e7f9d49f82b4e2e7Vikram Aggarwal if (ConversationListContext.isSearchResult(listContext)) { 18768f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira mViewMode.enterSearchResultsListMode(); 18868f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira } else { 18968f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira mViewMode.enterConversationListMode(); 19068f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira } 1919b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira // TODO(viki): This account transition looks strange in two pane mode. 1922175d0a93263672d4498458c81b404b0999134baVikram Aggarwal // Revisit as the app is coming together and improve the look and feel. 193cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwal final int transition = mConversationListNeverShown 194cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwal ? FragmentTransaction.TRANSIT_FRAGMENT_FADE 1959b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira : FragmentTransaction.TRANSIT_FRAGMENT_OPEN; 19601668eb393deaf8c8b8abf86be46109614a98631Mindy Pereira Fragment conversationListFragment = ConversationListFragment.newInstance(listContext); 197bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook 1982074a056bb2a634c66996225c55620d2aa6f7ac5Vikram Aggarwal if (!inInbox(mAccount, mConvListContext)) { 1993982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira // Maintain fragment transaction history so we can get back to the 2003982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira // fragment used to launch this list. 20172a9f3918310f581fecf6411174645ad5b5ae112Mindy Pereira mLastConversationListTransactionId = replaceFragment(conversationListFragment, 20266150d75d09324e867be42ff8c0ea8fae115ef20Paul Westbrook transition, TAG_CONVERSATION_LIST); 2033982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } else { 2043982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira // If going to the inbox, clear the folder list transaction history. 2053982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira mInbox = listContext.folder; 2060e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook mLastInboxConversationListTransactionId = replaceFragment(conversationListFragment, 2070e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook transition, TAG_CONVERSATION_LIST); 2083982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira mLastFolderListTransactionId = INVALID_ID; 2090e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook 2100e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook // If we ever to to the inbox, we want to unset the transation id for any other 2110e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook // non-inbox folder. 2120e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook mLastConversationListTransactionId = INVALID_ID; 2133982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } 2142175d0a93263672d4498458c81b404b0999134baVikram Aggarwal mConversationListVisible = true; 2157dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal onConversationVisibilityChanged(false); 2169f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook onConversationListVisibilityChanged(true); 217cd09f5e9bf55e6f4310e8dc9408132b9c88e87c3Vikram Aggarwal mConversationListNeverShown = false; 21828d5f72e0ad0db75b6243ee8125bfe3aadbdcb85Mindy Pereira } 21928d5f72e0ad0db75b6243ee8125bfe3aadbdcb85Mindy Pereira 22028d5f72e0ad0db75b6243ee8125bfe3aadbdcb85Mindy Pereira @Override 2211ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang protected void showConversation(Conversation conversation, boolean inLoaderCallbacks) { 2221ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang super.showConversation(conversation, inLoaderCallbacks); 2233d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal if (conversation == null) { 2241ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang transitionBackToConversationListMode(inLoaderCallbacks); 2253d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal return; 2263d7ca9d2aefd20dc115f20532c1e19fdb60f7d68Vikram Aggarwal } 227e128fc21fab03f6d66c656efeee2155fab449a7fVikram Aggarwal disableCabMode(); 228ae4ea997d3d3f3c8c11fc5a3e7f9d49f82b4e2e7Vikram Aggarwal if (ConversationListContext.isSearchResult(mConvListContext)) { 22968f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira mViewMode.enterSearchResultsConversationMode(); 23068f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira } else { 23168f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira mViewMode.enterConversationMode(); 23268f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira } 2337dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal final FragmentManager fm = mActivity.getFragmentManager(); 234f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp final FragmentTransaction ft = fm.beginTransaction(); 235f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp ft.addToBackStack(null); 236f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // Switching to conversation view is an incongruous transition: 237f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // we are not replacing a fragment with another fragment as 238f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // usual. Instead, reveal the heretofore inert conversation 239f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // ViewPager and just remove the previously visible fragment 240f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp // e.g. conversation list, or possibly label list?). 2417dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal final Fragment f = fm.findFragmentById(R.id.content_pane); 242deab11995a1ebb83b24bf567508440088ec943bfPaul Westbrook // FragmentManager#findFragmentById can return fragments that are not added to the activity. 243deab11995a1ebb83b24bf567508440088ec943bfPaul Westbrook // We want to make sure that we don't attempt to remove fragments that are not added to the 244deab11995a1ebb83b24bf567508440088ec943bfPaul Westbrook // activity, as when the transaction is popped off, the FragmentManager will attempt to 245deab11995a1ebb83b24bf567508440088ec943bfPaul Westbrook // readd the same fragment twice 246deab11995a1ebb83b24bf567508440088ec943bfPaul Westbrook if (f != null && f.isAdded()) { 2472b703c6c71a369485efc8ade26d449d25669ceecVikram Aggarwal // TODO: improve this transition 2482b703c6c71a369485efc8ade26d449d25669ceecVikram Aggarwal ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); 2492b703c6c71a369485efc8ade26d449d25669ceecVikram Aggarwal ft.remove(f); 2502b703c6c71a369485efc8ade26d449d25669ceecVikram Aggarwal ft.commitAllowingStateLoss(); 251632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 252a3ed834c959ece3453c1b34953fabecb3b19c424Andy Huang mPagerController.show(mAccount, mFolder, conversation, true /* changeVisibility */); 2537dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal onConversationVisibilityChanged(true); 2542175d0a93263672d4498458c81b404b0999134baVikram Aggarwal mConversationListVisible = false; 2559f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook onConversationListVisibilityChanged(false); 2569b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira } 2579b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira 2589b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira @Override 2592d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook public void showWaitForInitialization() { 2602d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook super.showWaitForInitialization(); 2612d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook 2622d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook replaceFragment(WaitFragment.newInstance(mAccount), 2636902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT); 2642d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 2652d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook 266dd6a7ce32c4003bd0941e2f18fcf5b80b5cd43c5Vikram Aggarwal protected void hideWaitForInitialization() { 2672d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook transitionToInbox(); 2682d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook } 2692d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook 2702d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook @Override 2719b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira public void showFolderList() { 2729e85333dfc57e7c98ffef27cded4712ea598f554Paul Westbrook if (mAccount == null) { 2739e85333dfc57e7c98ffef27cded4712ea598f554Paul Westbrook LogUtils.e(LOG_TAG, "Null account in showFolderList"); 2749e85333dfc57e7c98ffef27cded4712ea598f554Paul Westbrook return; 2759e85333dfc57e7c98ffef27cded4712ea598f554Paul Westbrook } 27611e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira // Null out the currently selected folder; we have nothing selected the 27711e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira // first time the user enters the folder list 278c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira setHierarchyFolder(null); 27901668eb393deaf8c8b8abf86be46109614a98631Mindy Pereira mViewMode.enterFolderListMode(); 2800ec2a71d1bb48f1fa57f1a4c8a6d81a49f44400fVikram Aggarwal enableCabMode(); 2813982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira mLastFolderListTransactionId = replaceFragment( 2822c0032dd2a4996680ab6e1958fe80a2ebcd01ef3Vikram Aggarwal FolderListFragment.newInstance(null, mAccount.folderListUri, false), 2836902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_FOLDER_LIST); 2842175d0a93263672d4498458c81b404b0999134baVikram Aggarwal mConversationListVisible = false; 2857dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal onConversationVisibilityChanged(false); 2869f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook onConversationListVisibilityChanged(false); 2879b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira } 2889b87568c9e9f1c32a9672b315229866a58a1e757Mindy Pereira 2896902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal /** 2906902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal * Replace the content_pane with the fragment specified here. The tag is specified so that 2916902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal * the {@link ActivityController} can look up the fragments through the 2926902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal * {@link android.app.FragmentManager}. 2936902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal * @param fragment 2946902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal * @param transition 2956902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal * @param tag 2966902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal * @return transaction ID returned when the transition is committed. 2976902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal */ 2982d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook private int replaceFragment(Fragment fragment, int transition, String tag) { 299d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal FragmentTransaction fragmentTransaction = mActivity.getFragmentManager().beginTransaction(); 300d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal fragmentTransaction.addToBackStack(null); 301d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal fragmentTransaction.setTransition(transition); 3022d50bcdca57756ecad20d21da0d936243215b79cPaul Westbrook fragmentTransaction.replace(R.id.content_pane, fragment, tag); 3036ffc1b8ad2d600b4886590d68af8f776b3296574Vikram Aggarwal return fragmentTransaction.commitAllowingStateLoss(); 304d7a12cd5b5c2639b653d8c671b04844ef02ee01dVikram Aggarwal } 30501668eb393deaf8c8b8abf86be46109614a98631Mindy Pereira 3063982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira /** 3073982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * Back works as follows: 3083982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * 1) If the user is in the folder list view, go back 3093982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * to the account default inbox. 3103982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * 2) If the user is in a conversation list 3113982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * that is not the inbox AND: 3123982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * a) they got there by going through the folder 3133982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * list view, go back to the folder list view. 3143982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * b) they got there by using some other means (account dropdown), go back to the inbox. 3153982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * 3) If the user is in a conversation, go back to the conversation list they were last in. 3163982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * 4) If the user is in the conversation list for the default account inbox, 3173982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * back exits the app. 3183982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira */ 31901668eb393deaf8c8b8abf86be46109614a98631Mindy Pereira @Override 32001668eb393deaf8c8b8abf86be46109614a98631Mindy Pereira public boolean onBackPressed() { 3212074a056bb2a634c66996225c55620d2aa6f7ac5Vikram Aggarwal final int mode = mViewMode.getMode(); 3223982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira if (mode == ViewMode.FOLDER_LIST) { 323aea87622d3244be963ee4e9f9780e79b34ffe260Paul Westbrook final Folder hierarchyFolder = getHierarchyFolder(); 324aea87622d3244be963ee4e9f9780e79b34ffe260Paul Westbrook final FolderListFragment folderListFragment = getFolderListFragment(); 325aea87622d3244be963ee4e9f9780e79b34ffe260Paul Westbrook if (folderListFragment != null && 326aea87622d3244be963ee4e9f9780e79b34ffe260Paul Westbrook folderListFragment.showingHierarchy() && hierarchyFolder != null) { 32711e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira // If we are showing the folder list and the user is exploring 32811e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira // the children of a single parent folder, 32911e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira // back should display the parent folder's parent and siblings. 330ea94550fcca64c3a3510cc10b0e5465d9018668eMindy Pereira goUpFolderHierarchy(hierarchyFolder); 33111e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira } else { 332649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal // We are at the topmost list of folders: go back 33311e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira mLastFolderListTransactionId = INVALID_ID; 33411e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira transitionToInbox(); 33511e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira } 33668f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira } else if (mode == ViewMode.SEARCH_RESULTS_LIST) { 33768f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira mActivity.finish(); 338b466bcf49502a1178cf7362a81470f3231d8892bMindy Pereira } else if (mViewMode.isListMode() && !inInbox(mAccount, mConvListContext)) { 33911e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira if (mLastFolderListTransactionId != INVALID_ID) { 34011e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira // If the user got here by navigating via the folder list, back 34111e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira // should bring them back to the folder list. 3423982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira mViewMode.enterFolderListMode(); 3433982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira mActivity.getFragmentManager().popBackStack(mLastFolderListTransactionId, 0); 3443982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } else { 3453982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira transitionToInbox(); 3463982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } 34768f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira } else if (mode == ViewMode.CONVERSATION || mode == ViewMode.SEARCH_RESULTS_CONVERSATION) { 3481ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang transitionBackToConversationListMode(false /* inLoaderCallbacks */); 3493982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } else { 3503982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira mActivity.finish(); 3513982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } 352c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein mToastBar.hide(false); 3533982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira return true; 3543982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } 3553982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira 35612a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira private void goUpFolderHierarchy(Folder current) { 35712a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira Folder top = current.parent; 35812a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira if (top != null) { 35999f18d1504203d2f3a82373dcc0937ef0277561aMindy Pereira setHierarchyFolder(top); 36012a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira // Replace this fragment with a new FolderListFragment 36112a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira // showing this folder's children if we are not already 36212a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira // looking at the child view for this folder. 36312a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira mLastFolderListTransactionId = replaceFragment(FolderListFragment.newInstance( 3642c0032dd2a4996680ab6e1958fe80a2ebcd01ef3Vikram Aggarwal top, top.childFoldersListUri, false), 36512a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_FOLDER_LIST); 36612a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira // Show the up affordance when digging into child folders. 36712a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira mActionBarView.setBackButton(); 36812a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira } else { 36912a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira // Otherwise, clear the selected folder and go back to whatever the 37012a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira // last folder list displayed was. 37112a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira showFolderList(); 37212a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira } 37312a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira } 37412a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira 375649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal /** 376649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal * Switch to the Inbox by creating a new conversation list context that loads the inbox. 377649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal */ 3783982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira private void transitionToInbox() { 3798690e2b71e1a3dd812ce418c9607e21f3a88ab54Mindy Pereira mViewMode.enterConversationListMode(); 380daaf8061dc6fc3cf9f2dda352988c9de08e1a8a8Vikram Aggarwal if (mInbox == null) { 381ab4863650794e81f35a0fd9abc16a5564d7b102bMindy Pereira loadAccountInbox(); 3823982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } else { 383daaf8061dc6fc3cf9f2dda352988c9de08e1a8a8Vikram Aggarwal final ConversationListContext listContext = 384649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal ConversationListContext.forFolder(mAccount, mInbox); 385649b9ea3653da73fac0c33c8fb0af18baad12ac3Vikram Aggarwal // Set the correct context for what the conversation view will be now. 386f6acdade010b2d0f49fd425b33e7f7b376286490Mindy Pereira onFolderChanged(mInbox); 38772a9f3918310f581fecf6411174645ad5b5ae112Mindy Pereira showConversationList(listContext); 38801668eb393deaf8c8b8abf86be46109614a98631Mindy Pereira } 38901668eb393deaf8c8b8abf86be46109614a98631Mindy Pereira } 390f5acda4a4b7c9e8ecacb41cb7d570ef426b6d4fcMindy Pereira 391118b3f6443f1859ff4866c97c0e8896f3415f730Mindy Pereira @Override 392505df5f59c92adbe8eaa734321c1d3f91be84a4aMindy Pereira public void onFolderSelected(Folder folder) { 393a1f99981919755e50f31fe300517d2fed752997eMindy Pereira if (folder.hasChildren && !folder.equals(getHierarchyFolder())) { 3940f7ae7a2d244463f75b3d4e1f79e27305a4dcb38Mindy Pereira mViewMode.enterFolderListMode(); 395c975e8416b64a1ebdec6adee7e65dd1d0928e8d4Mindy Pereira setHierarchyFolder(folder); 39656e3f50f5aee6606035eae4b713ef634c4f3a686Mindy Pereira // Replace this fragment with a new FolderListFragment 39711e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira // showing this folder's children if we are not already 39811e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira // looking at the child view for this folder. 39956e3f50f5aee6606035eae4b713ef634c4f3a686Mindy Pereira mLastFolderListTransactionId = replaceFragment( 4002c0032dd2a4996680ab6e1958fe80a2ebcd01ef3Vikram Aggarwal FolderListFragment.newInstance(folder, folder.childFoldersListUri, false), 4016902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_FOLDER_LIST); 40212a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira // Show the up affordance when digging into child folders. 40312a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira mActionBarView.setBackButton(); 40411e3596e8c5978d07195ae2d7c8a96bb51aa75b3Mindy Pereira } else { 40512a4d8040d64501aa5a24c25865c806331560b74Mindy Pereira super.onFolderSelected(folder); 406118b3f6443f1859ff4866c97c0e8896f3415f730Mindy Pereira } 407118b3f6443f1859ff4866c97c0e8896f3415f730Mindy Pereira } 408118b3f6443f1859ff4866c97c0e8896f3415f730Mindy Pereira 4093982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira private boolean isTransactionIdValid(int id) { 4103982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira return id >= 0; 4113982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira } 4123982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira 4133982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira /** 4143982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * Up works as follows: 4153982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * 1) If the user is in a conversation list that is not the default account inbox, 4163982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * a conversation, or the folder list, up follows the rules of back. 4173982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * 2) If the user is in search results, up exits search 4183982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * mode and returns the user to whatever view they were in when they began search. 4193982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira * 3) If the user is in the inbox, there is no up. 4203982e236fb2dd36d460df4dbf24e07e8ba55b3bdMindy Pereira */ 421f5acda4a4b7c9e8ecacb41cb7d570ef426b6d4fcMindy Pereira @Override 422f5acda4a4b7c9e8ecacb41cb7d570ef426b6d4fcMindy Pereira public boolean onUpPressed() { 4239da85df06175d25c52a09e08df3b02d1fd9cc6b7Vikram Aggarwal final int mode = mViewMode.getMode(); 42468f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira if (mode == ViewMode.SEARCH_RESULTS_LIST) { 42568f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira mActivity.finish(); 426b466bcf49502a1178cf7362a81470f3231d8892bMindy Pereira } else if ((!inInbox(mAccount, mConvListContext) && mViewMode.isListMode()) 42768f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira || mode == ViewMode.CONVERSATION 42868f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira || mode == ViewMode.FOLDER_LIST 42968f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira || mode == ViewMode.SEARCH_RESULTS_CONVERSATION) { 430f5acda4a4b7c9e8ecacb41cb7d570ef426b6d4fcMindy Pereira // Same as go back. 431f5acda4a4b7c9e8ecacb41cb7d570ef426b6d4fcMindy Pereira mActivity.onBackPressed(); 432f5acda4a4b7c9e8ecacb41cb7d570ef426b6d4fcMindy Pereira } 433f5acda4a4b7c9e8ecacb41cb7d570ef426b6d4fcMindy Pereira return true; 434f5acda4a4b7c9e8ecacb41cb7d570ef426b6d4fcMindy Pereira } 435f5acda4a4b7c9e8ecacb41cb7d570ef426b6d4fcMindy Pereira 4361ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang private void transitionBackToConversationListMode(boolean inLoaderCallbacks) { 4379da85df06175d25c52a09e08df3b02d1fd9cc6b7Vikram Aggarwal final int mode = mViewMode.getMode(); 43890d89e2194cecb6ff0179c8159870575edf7365eVikram Aggarwal enableCabMode(); 43968f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira if (mode == ViewMode.SEARCH_RESULTS_CONVERSATION) { 44068f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira mViewMode.enterSearchResultsListMode(); 44168f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira } else { 44268f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira mViewMode.enterConversationListMode(); 44368f2e222b4ffccd9f67f02b3a9cfdb3841a7eb43Mindy Pereira } 44421ab490d4919985d611bc36ae2d8aea86a911499Mindy Pereira if (isTransactionIdValid(mLastConversationListTransactionId)) { 4451ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang safelyPopBackStack(mLastConversationListTransactionId, inLoaderCallbacks); 4460e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook } else if (isTransactionIdValid(mLastInboxConversationListTransactionId)) { 4471ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang safelyPopBackStack(mLastInboxConversationListTransactionId, inLoaderCallbacks); 4480e3fd9d61bc18ad9f828bb3c4dd24fc851f11df5Paul Westbrook onFolderChanged(mInbox); 44921ab490d4919985d611bc36ae2d8aea86a911499Mindy Pereira } else { 4509da85df06175d25c52a09e08df3b02d1fd9cc6b7Vikram Aggarwal // TODO: revisit if this block is necessary 45153d46a3e3b3c3d97696ecfffc3a99ac9250063e8Vikram Aggarwal final ConversationListContext listContext = ConversationListContext.forFolder( 45221ab490d4919985d611bc36ae2d8aea86a911499Mindy Pereira mAccount, mInbox); 45321ab490d4919985d611bc36ae2d8aea86a911499Mindy Pereira // Set the correct context for what the conversation view will be now. 45421ab490d4919985d611bc36ae2d8aea86a911499Mindy Pereira onFolderChanged(mInbox); 45521ab490d4919985d611bc36ae2d8aea86a911499Mindy Pereira showConversationList(listContext); 45621ab490d4919985d611bc36ae2d8aea86a911499Mindy Pereira } 4579f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook mConversationListVisible = true; 4587dd054e39986de84a213c56a3c11ac94731402e6Vikram Aggarwal onConversationVisibilityChanged(false); 4599f119c72042e4d0382017d5ddcee9aa2113b6425Paul Westbrook onConversationListVisibilityChanged(true); 460f5acda4a4b7c9e8ecacb41cb7d570ef426b6d4fcMindy Pereira } 461b849dfbda3c917f078a5c09f03906886c27ecbecMindy Pereira 4621ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang /** 4631ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * Pop to a specified point in the fragment back stack without causing IllegalStateExceptions 4641ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * from committing a fragment transaction "at the wrong time". 4651ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * <p> 4661ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * If the caller specifies that we are in 4671ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * the scope of an {@link LoaderCallbacks#onLoadFinished(android.content.Loader, Object)}, 4681ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * this method will pop back in a Handler. The deferred job will also check that the Activity 4691ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * is in a valid state for fragment transactions, using {@link #safeToModifyFragments()}. 4701ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * Otherwise, this method will pop back immediately if safe. Finally, if we are not in 4711ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * onLoadFinished and it's not safe, this method will just ignore the request. 4721ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * 4731ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * @param transactionId back stack destination to pop to 4741ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * @param inLoaderCallbacks whether we are in the scope of an onLoadFinished (when fragment 4751ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * transactions are disallowed) 4761ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang */ 4771ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang private void safelyPopBackStack(int transactionId, boolean inLoaderCallbacks) { 4781ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang final PopBackStackRunnable r = new PopBackStackRunnable(transactionId); 4791ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (inLoaderCallbacks) { 4801ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // always run deferred. ensure deferred job checks safety. 4811ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang mHandler.post(r); 4821ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } else if (safeToModifyFragments()) { 4831ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // run now 4841ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang r.popBackStack(); 4851ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } else { 4861ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // ignore 4871ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang LogUtils.i(LOG_TAG, "Activity has been saved; ignoring unsafe immediate request" 4881ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang + " to pop back stack"); 4891ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 4901ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 4911ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 492b849dfbda3c917f078a5c09f03906886c27ecbecMindy Pereira @Override 493b849dfbda3c917f078a5c09f03906886c27ecbecMindy Pereira public boolean shouldShowFirstConversation() { 494b849dfbda3c917f078a5c09f03906886c27ecbecMindy Pereira return false; 495b849dfbda3c917f078a5c09f03906886c27ecbecMindy Pereira } 496fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira 497fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira @Override 498d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira public void onUndoAvailable(ToastBarOperation op) { 4990963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira if (op != null && mAccount.supportsCapability(UIProvider.AccountCapabilities.UNDO)) { 5007f602f7a64f176894ccb7942a6642f22584c3894Vikram Aggarwal final int mode = mViewMode.getMode(); 501dbab8fab0c98dc2d56bbe17c7436719129952b7bMindy Pereira final ConversationListFragment convList = getConversationListFragment(); 5020963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira switch (mode) { 503b466bcf49502a1178cf7362a81470f3231d8892bMindy Pereira case ViewMode.SEARCH_RESULTS_CONVERSATION: 5040963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira case ViewMode.CONVERSATION: 505c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein mToastBar.setConversationMode(true); 506c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein mToastBar.show( 507c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein getUndoClickedListener( 508c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein convList != null ? convList.getAnimatedAdapter() : null), 509c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein 0, 51001f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira Html.fromHtml(op.getDescription(mActivity.getActivityContext(), 51101f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira mFolder)), 512c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein true, /* showActionIcon */ 513c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein R.string.undo, 514d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira true, /* replaceVisibleToast */ 515d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira op); 5160963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira break; 517b466bcf49502a1178cf7362a81470f3231d8892bMindy Pereira case ViewMode.SEARCH_RESULTS_LIST: 5180963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira case ViewMode.CONVERSATION_LIST: 5196902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal if (convList != null) { 520c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein mToastBar.setConversationMode(false); 521c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein mToastBar.show( 522c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein getUndoClickedListener(convList.getAnimatedAdapter()), 523c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein 0, 52401f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira Html.fromHtml(op.getDescription(mActivity.getActivityContext(), 52501f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira mFolder)), 526c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein true, /* showActionIcon */ 527c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein R.string.undo, 528d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira true, /* replaceVisibleToast */ 529d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira op); 5304765c5c90802d0abcf2b05c4967e7dd7d2284f9aMindy Pereira } else { 5314765c5c90802d0abcf2b05c4967e7dd7d2284f9aMindy Pereira mActivity.setPendingToastOperation(op); 5326902dcf8688d7d0691639f49365a78a3a78fe9e3Vikram Aggarwal } 5330963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira break; 5340963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira } 5350963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira } 5360963ef8394e1f0bca3f931f930b127b00790361aMindy Pereira } 537c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein 538c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein @Override 5399d7519d18e8ddbcdd59b37eec7c85210fca0e8c2Andrew Sapperstein public void onError(final Folder folder, boolean replaceVisibleToast) { 540c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein final int mode = mViewMode.getMode(); 541c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein switch (mode) { 542c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein case ViewMode.SEARCH_RESULTS_LIST: 543c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein case ViewMode.CONVERSATION_LIST: 5449d7519d18e8ddbcdd59b37eec7c85210fca0e8c2Andrew Sapperstein showErrorToast(folder, replaceVisibleToast); 545c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein break; 546c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein default: 547c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein break; 548c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 549c2c9dc14aa184db1f05b8c060b27d97dda5a3ca4Andrew Sapperstein } 55030745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook 55130745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook @Override 55230745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook public String getHelpContext() { 55330745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook final int mode = mViewMode.getMode(); 55430745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook switch (mode) { 55530745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook case ViewMode.FOLDER_LIST: 55630745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook return mContext.getString(R.string.one_pane_folder_list_help_context); 55730745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook } 55830745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook return super.getHelpContext(); 55930745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook } 5601ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 5611ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang private final class PopBackStackRunnable implements Runnable { 5621ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 5631ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang private final int mTransactionId; 5641ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 5651ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang public PopBackStackRunnable(int transactionId) { 5661ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang mTransactionId = transactionId; 5671ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 5681ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 5691ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang public void popBackStack() { 5701ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang mActivity.getFragmentManager().popBackStack(mTransactionId, 0); 5711ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 5721ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 5731ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang @Override 5741ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang public void run() { 5751ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (safeToModifyFragments()) { 5761ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang popBackStack(); 5771ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } else { 5781ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang LogUtils.i(LOG_TAG, "Activity has been saved; ignoring unsafe deferred request" 5791ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang + " to pop back stack"); 5801ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 5811ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 5821ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 5831ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 584a55b36cb6b75ce8096812183651e89115300975aVikram Aggarwal} 585