Home | History | Annotate | Download | only in activity
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.email.activity;
     18 
     19 import android.app.Activity;
     20 import android.app.FragmentTransaction;
     21 import android.content.Context;
     22 import android.os.Bundle;
     23 import android.util.Log;
     24 import android.view.Menu;
     25 import android.view.MenuInflater;
     26 
     27 import com.android.email.Clock;
     28 import com.android.email.Email;
     29 import com.android.email.MessageListContext;
     30 import com.android.email.Preferences;
     31 import com.android.email.R;
     32 import com.android.email.RefreshManager;
     33 import com.android.emailcommon.Logging;
     34 import com.android.emailcommon.provider.Account;
     35 import com.android.emailcommon.provider.EmailContent.Message;
     36 import com.android.emailcommon.provider.Mailbox;
     37 import com.android.emailcommon.utility.EmailAsyncTask;
     38 import com.android.emailcommon.utility.Utility;
     39 import com.google.common.annotations.VisibleForTesting;
     40 
     41 import java.util.Set;
     42 
     43 /**
     44  * UI Controller for x-large devices.  Supports a multi-pane layout.
     45  *
     46  * Note: Always use {@link #commitFragmentTransaction} to operate fragment transactions,
     47  * so that we can easily switch between synchronous and asynchronous transactions.
     48  */
     49 class UIControllerTwoPane extends UIControllerBase implements ThreePaneLayout.Callback {
     50     @VisibleForTesting
     51     static final int MAILBOX_REFRESH_MIN_INTERVAL = 30 * 1000; // in milliseconds
     52 
     53     @VisibleForTesting
     54     static final int INBOX_AUTO_REFRESH_MIN_INTERVAL = 10 * 1000; // in milliseconds
     55 
     56     // Other UI elements
     57     protected ThreePaneLayout mThreePane;
     58 
     59     private MessageCommandButtonView mMessageCommandButtons;
     60 
     61     private MessageCommandButtonView mInMessageCommandButtons;
     62 
     63     public UIControllerTwoPane(EmailActivity activity) {
     64         super(activity);
     65     }
     66 
     67     @Override
     68     public int getLayoutId() {
     69         return R.layout.email_activity_two_pane;
     70     }
     71 
     72     // ThreePaneLayoutCallback
     73     @Override
     74     public void onVisiblePanesChanged(int previousVisiblePanes) {
     75         // If the right pane is gone, remove the message view.
     76         final int visiblePanes = mThreePane.getVisiblePanes();
     77 
     78         if (((visiblePanes & ThreePaneLayout.PANE_RIGHT) == 0) &&
     79                 ((previousVisiblePanes & ThreePaneLayout.PANE_RIGHT) != 0)) {
     80             // Message view just got hidden
     81             unselectMessage();
     82         }
     83         // Disable CAB when the message list is not visible.
     84         if (isMessageListInstalled()) {
     85             getMessageListFragment().onHidden((visiblePanes & ThreePaneLayout.PANE_MIDDLE) == 0);
     86         }
     87         refreshActionBar();
     88     }
     89 
     90     // MailboxListFragment$Callback
     91     @Override
     92     public void onMailboxSelected(long accountId, long mailboxId, boolean nestedNavigation) {
     93         setListContext(MessageListContext.forMailbox(accountId, mailboxId));
     94         if (getMessageListMailboxId() != mListContext.getMailboxId()) {
     95             updateMessageList(true);
     96         }
     97     }
     98 
     99     /**
    100      * Handles the {@link android.app.Activity#onCreateOptionsMenu} callback.
    101      */
    102     public boolean onCreateOptionsMenu(MenuInflater inflater, Menu menu) {
    103         int state = mThreePane.getPaneState();
    104         boolean handled = false;
    105         int menuId = -1;
    106         switch (state) {
    107             case ThreePaneLayout.STATE_LEFT_VISIBLE:
    108                 MessageListFragment fragment = getMessageListFragment();
    109                 MessageListContext context = fragment == null ? null : fragment.getListContext();
    110                 if (context != null && context.isSearch()) {
    111                     menuId = R.menu.message_search_list_fragment_option;
    112                 } else {
    113                     menuId = R.menu.message_list_fragment_option;
    114                 }
    115                 handled=  true;
    116                 break;
    117             case ThreePaneLayout.STATE_MIDDLE_EXPANDED:
    118             case ThreePaneLayout.STATE_RIGHT_VISIBLE:
    119                 menuId = R.menu.message_view_fragment_option;
    120                 handled=  true;
    121                 break;
    122         }
    123         if (menuId != -1) {
    124             inflater.inflate(menuId, menu);
    125         }
    126         return handled;
    127     }
    128 
    129     // MailboxListFragment$Callback
    130     @Override
    131     public void onAccountSelected(long accountId) {
    132         // It's from combined view, so "forceShowInbox" doesn't really matter.
    133         // (We're always switching accounts.)
    134         switchAccount(accountId, true);
    135     }
    136 
    137     // MailboxListFragment$Callback
    138     @Override
    139     public void onParentMailboxChanged() {
    140         refreshActionBar();
    141     }
    142 
    143     // MessageListFragment$Callback
    144     @Override
    145     public void onMessageOpen(long messageId, long messageMailboxId, long listMailboxId,
    146             int type) {
    147         if (type == MessageListFragment.Callback.TYPE_DRAFT) {
    148             MessageCompose.actionEditDraft(mActivity, messageId);
    149         } else {
    150             if (getMessageId() != messageId) {
    151                 navigateToMessage(messageId);
    152                 mThreePane.showRightPane();
    153             }
    154         }
    155     }
    156 
    157     // MessageListFragment$Callback
    158     /**
    159      * Apply the auto-advance policy upon initation of a batch command that could potentially
    160      * affect the currently selected conversation.
    161      */
    162     @Override
    163     public void onAdvancingOpAccepted(Set<Long> affectedMessages) {
    164         if (!isMessageViewInstalled()) {
    165             // Do nothing if message view is not visible.
    166             return;
    167         }
    168 
    169         final MessageOrderManager orderManager = getMessageOrderManager();
    170         int autoAdvanceDir = Preferences.getPreferences(mActivity).getAutoAdvanceDirection();
    171         if ((autoAdvanceDir == Preferences.AUTO_ADVANCE_MESSAGE_LIST) || (orderManager == null)) {
    172             if (affectedMessages.contains(getMessageId())) {
    173                 goBackToMailbox();
    174             }
    175             return;
    176         }
    177 
    178         // Navigate to the first unselected item in the appropriate direction.
    179         switch (autoAdvanceDir) {
    180             case Preferences.AUTO_ADVANCE_NEWER:
    181                 while (affectedMessages.contains(orderManager.getCurrentMessageId())) {
    182                     if (!orderManager.moveToNewer()) {
    183                         goBackToMailbox();
    184                         return;
    185                     }
    186                 }
    187                 navigateToMessage(orderManager.getCurrentMessageId());
    188                 break;
    189 
    190             case Preferences.AUTO_ADVANCE_OLDER:
    191                 while (affectedMessages.contains(orderManager.getCurrentMessageId())) {
    192                     if (!orderManager.moveToOlder()) {
    193                         goBackToMailbox();
    194                         return;
    195                     }
    196                 }
    197                 navigateToMessage(orderManager.getCurrentMessageId());
    198                 break;
    199         }
    200     }
    201 
    202     // MessageListFragment$Callback
    203     @Override
    204     public boolean onDragStarted() {
    205         if (Email.DEBUG) {
    206             Log.i(Logging.LOG_TAG, "Drag started");
    207         }
    208 
    209         if (((mListContext != null) && mListContext.isSearch())
    210                 || !mThreePane.isLeftPaneVisible()) {
    211             // D&D not allowed.
    212             return false;
    213         }
    214 
    215         return true;
    216     }
    217 
    218     // MessageListFragment$Callback
    219     @Override
    220     public void onDragEnded() {
    221         if (Email.DEBUG) {
    222             Log.i(Logging.LOG_TAG, "Drag ended");
    223         }
    224     }
    225 
    226 
    227     // MessageViewFragment$Callback
    228     @Override
    229     public boolean onUrlInMessageClicked(String url) {
    230         return ActivityHelper.openUrlInMessage(mActivity, url, getActualAccountId());
    231     }
    232 
    233     // MessageViewFragment$Callback
    234     @Override
    235     public void onLoadMessageStarted() {
    236     }
    237 
    238     // MessageViewFragment$Callback
    239     @Override
    240     public void onLoadMessageFinished() {
    241     }
    242 
    243     // MessageViewFragment$Callback
    244     @Override
    245     public void onLoadMessageError(String errorMessage) {
    246     }
    247 
    248     // MessageViewFragment$Callback
    249     @Override
    250     public void onCalendarLinkClicked(long epochEventStartTime) {
    251         ActivityHelper.openCalendar(mActivity, epochEventStartTime);
    252     }
    253 
    254     // MessageViewFragment$Callback
    255     @Override
    256     public void onForward() {
    257         MessageCompose.actionForward(mActivity, getMessageId());
    258     }
    259 
    260     // MessageViewFragment$Callback
    261     @Override
    262     public void onReply() {
    263         MessageCompose.actionReply(mActivity, getMessageId(), false);
    264     }
    265 
    266     // MessageViewFragment$Callback
    267     @Override
    268     public void onReplyAll() {
    269         MessageCompose.actionReply(mActivity, getMessageId(), true);
    270     }
    271 
    272     /**
    273      * Must be called just after the activity sets up the content view.
    274      */
    275     @Override
    276     public void onActivityViewReady() {
    277         super.onActivityViewReady();
    278 
    279         // Set up content
    280         mThreePane = (ThreePaneLayout) mActivity.findViewById(R.id.three_pane);
    281         mThreePane.setCallback(this);
    282 
    283         mMessageCommandButtons = mThreePane.getMessageCommandButtons();
    284         mMessageCommandButtons.setCallback(new CommandButtonCallback());
    285         mInMessageCommandButtons = mThreePane.getInMessageCommandButtons();
    286         mInMessageCommandButtons.setCallback(new CommandButtonCallback());
    287     }
    288 
    289     @Override
    290     protected ActionBarController createActionBarController(Activity activity) {
    291         return new ActionBarController(activity, activity.getLoaderManager(),
    292                 activity.getActionBar(), new ActionBarControllerCallback());
    293     }
    294 
    295     /**
    296      * @return the currently selected account ID, *or* {@link Account#ACCOUNT_ID_COMBINED_VIEW}.
    297      *
    298      * @see #getActualAccountId()
    299      */
    300     @Override
    301     public long getUIAccountId() {
    302         return isMailboxListInstalled() ? getMailboxListFragment().getAccountId()
    303                 :Account.NO_ACCOUNT;
    304     }
    305 
    306     @Override
    307     public long getMailboxSettingsMailboxId() {
    308         return getMessageListMailboxId();
    309     }
    310 
    311     /**
    312      * @return true if refresh is in progress for the current mailbox.
    313      */
    314     @Override
    315     protected boolean isRefreshInProgress() {
    316         long messageListMailboxId = getMessageListMailboxId();
    317         return (messageListMailboxId >= 0)
    318                 && mRefreshManager.isMessageListRefreshing(messageListMailboxId);
    319     }
    320 
    321     /**
    322      * @return true if the UI should enable the "refresh" command.
    323      */
    324     @Override
    325     protected boolean isRefreshEnabled() {
    326         return getActualAccountId() != Account.NO_ACCOUNT
    327                 && (mListContext.getMailboxId() > 0);
    328     }
    329 
    330 
    331     /** {@inheritDoc} */
    332     @Override
    333     public void onSaveInstanceState(Bundle outState) {
    334         super.onSaveInstanceState(outState);
    335     }
    336 
    337     /** {@inheritDoc} */
    338     @Override
    339     public void onRestoreInstanceState(Bundle savedInstanceState) {
    340         super.onRestoreInstanceState(savedInstanceState);
    341     }
    342 
    343     @Override
    344     protected void installMessageListFragment(MessageListFragment fragment) {
    345         super.installMessageListFragment(fragment);
    346 
    347         if (isMailboxListInstalled()) {
    348             getMailboxListFragment().setHighlightedMailbox(fragment.getMailboxId());
    349         }
    350         getMessageListFragment().setLayout(mThreePane);
    351         mThreePane.setIsSearch(getMessageListFragment().getListContext().isSearch());
    352     }
    353 
    354     @Override
    355     protected void installMessageViewFragment(MessageViewFragment fragment) {
    356         super.installMessageViewFragment(fragment);
    357 
    358         if (isMessageListInstalled()) {
    359             getMessageListFragment().setSelectedMessage(fragment.getMessageId());
    360         }
    361     }
    362 
    363     @Override
    364     public void openInternal(final MessageListContext listContext, final long messageId) {
    365         if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
    366             Log.d(Logging.LOG_TAG, this + " open " + listContext);
    367         }
    368 
    369         final FragmentTransaction ft = mFragmentManager.beginTransaction();
    370         updateMailboxList(ft, true);
    371         updateMessageList(ft, true);
    372 
    373         if (messageId != Message.NO_MESSAGE) {
    374             updateMessageView(ft, messageId);
    375             mThreePane.showRightPane();
    376         } else if (mListContext.isSearch() && UiUtilities.showTwoPaneSearchResults(mActivity)) {
    377             mThreePane.showRightPane();
    378         } else {
    379             mThreePane.showLeftPane();
    380         }
    381         commitFragmentTransaction(ft);
    382     }
    383 
    384     /**
    385      * Loads the given account and optionally selects the given mailbox and message. If the
    386      * specified account is already selected, no actions will be performed unless
    387      * <code>forceReload</code> is <code>true</code>.
    388      *
    389      * @param ft {@link FragmentTransaction} to use.
    390      * @param clearDependentPane if true, the message list and the message view will be cleared
    391      */
    392     private void updateMailboxList(FragmentTransaction ft, boolean clearDependentPane) {
    393         if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
    394             Log.d(Logging.LOG_TAG, this + " updateMailboxList " + mListContext);
    395         }
    396 
    397         long accountId = mListContext.mAccountId;
    398         long mailboxId = mListContext.getMailboxId();
    399         if ((getUIAccountId() != accountId) || (getMailboxListMailboxId() != mailboxId)) {
    400             removeMailboxListFragment(ft);
    401             boolean enableHighlight = !mListContext.isSearch();
    402             ft.add(mThreePane.getLeftPaneId(),
    403                     MailboxListFragment.newInstance(accountId, mailboxId, enableHighlight));
    404         }
    405         if (clearDependentPane) {
    406             removeMessageListFragment(ft);
    407             removeMessageViewFragment(ft);
    408         }
    409     }
    410 
    411     /**
    412      * Go back to a mailbox list view. If a message view is currently active, it will
    413      * be hidden.
    414      */
    415     private void goBackToMailbox() {
    416         if (isMessageViewInstalled()) {
    417             mThreePane.showLeftPane(); // Show mailbox list
    418         }
    419     }
    420 
    421     /**
    422      * Show the message list fragment for the given mailbox.
    423      *
    424      * @param ft {@link FragmentTransaction} to use.
    425      */
    426     private void updateMessageList(FragmentTransaction ft, boolean clearDependentPane) {
    427         if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
    428             Log.d(Logging.LOG_TAG, this + " updateMessageList " + mListContext);
    429         }
    430 
    431         if (mListContext.getMailboxId() != getMessageListMailboxId()) {
    432             removeMessageListFragment(ft);
    433             ft.add(mThreePane.getMiddlePaneId(), MessageListFragment.newInstance(mListContext));
    434         }
    435         if (clearDependentPane) {
    436             removeMessageViewFragment(ft);
    437         }
    438     }
    439 
    440     /**
    441      * Shortcut to call {@link #updateMessageList(FragmentTransaction, boolean)} and
    442      * commit.
    443      */
    444     private void updateMessageList(boolean clearDependentPane) {
    445         FragmentTransaction ft = mFragmentManager.beginTransaction();
    446         updateMessageList(ft, clearDependentPane);
    447         commitFragmentTransaction(ft);
    448     }
    449 
    450     /**
    451      * Show a message on the message view.
    452      *
    453      * @param ft {@link FragmentTransaction} to use.
    454      * @param messageId ID of the mailbox to load. Must never be {@link Message#NO_MESSAGE}.
    455      */
    456     private void updateMessageView(FragmentTransaction ft, long messageId) {
    457         if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
    458             Log.d(Logging.LOG_TAG, this + " updateMessageView messageId=" + messageId);
    459         }
    460         if (messageId == Message.NO_MESSAGE) {
    461             throw new IllegalArgumentException();
    462         }
    463 
    464         if (messageId == getMessageId()) {
    465             return; // nothing to do.
    466         }
    467 
    468         removeMessageViewFragment(ft);
    469 
    470         ft.add(mThreePane.getRightPaneId(), MessageViewFragment.newInstance(messageId));
    471     }
    472 
    473     /**
    474      * Shortcut to call {@link #updateMessageView(FragmentTransaction, long)} and commit.
    475      */
    476     @Override protected void navigateToMessage(long messageId) {
    477         FragmentTransaction ft = mFragmentManager.beginTransaction();
    478         updateMessageView(ft, messageId);
    479         commitFragmentTransaction(ft);
    480     }
    481 
    482     /**
    483      * Remove the message view if shown.
    484      */
    485     private void unselectMessage() {
    486         commitFragmentTransaction(removeMessageViewFragment(mFragmentManager.beginTransaction()));
    487         if (isMessageListInstalled()) {
    488             getMessageListFragment().setSelectedMessage(Message.NO_MESSAGE);
    489         }
    490         stopMessageOrderManager();
    491     }
    492 
    493     private class CommandButtonCallback implements MessageCommandButtonView.Callback {
    494         @Override
    495         public void onMoveToNewer() {
    496             moveToNewer();
    497         }
    498 
    499         @Override
    500         public void onMoveToOlder() {
    501             moveToOlder();
    502         }
    503     }
    504 
    505     /**
    506      * Disable/enable the move-to-newer/older buttons.
    507      */
    508     @Override protected void updateNavigationArrows() {
    509         final MessageOrderManager orderManager = getMessageOrderManager();
    510         if (orderManager == null) {
    511             // shouldn't happen, but just in case
    512             mMessageCommandButtons.enableNavigationButtons(false, false, 0, 0);
    513             mInMessageCommandButtons.enableNavigationButtons(false, false, 0, 0);
    514         } else {
    515             mMessageCommandButtons.enableNavigationButtons(
    516                     orderManager.canMoveToNewer(), orderManager.canMoveToOlder(),
    517                     orderManager.getCurrentPosition(), orderManager.getTotalMessageCount());
    518             mInMessageCommandButtons.enableNavigationButtons(
    519                     orderManager.canMoveToNewer(), orderManager.canMoveToOlder(),
    520                     orderManager.getCurrentPosition(), orderManager.getTotalMessageCount());
    521         }
    522     }
    523 
    524     /** {@inheritDoc} */
    525     @Override
    526     public boolean onBackPressed(boolean isSystemBackKey) {
    527         if (!mThreePane.isPaneCollapsible()) {
    528             if (mActionBarController.onBackPressed(isSystemBackKey)) {
    529                 return true;
    530             }
    531 
    532             if (mThreePane.showLeftPane()) {
    533                 return true;
    534             }
    535         }
    536 
    537         if (isMailboxListInstalled() && getMailboxListFragment().navigateUp()) {
    538             return true;
    539         }
    540         return false;
    541     }
    542 
    543     @Override
    544     protected void onRefresh() {
    545         // Cancel previously running instance if any.
    546         new RefreshTask(mTaskTracker, mActivity, getActualAccountId(),
    547                 getMessageListMailboxId()).cancelPreviousAndExecuteParallel();
    548     }
    549 
    550     /**
    551      * Class to handle refresh.
    552      *
    553      * When the user press "refresh",
    554      * <ul>
    555      *   <li>Refresh the current mailbox, if it's refreshable.  (e.g. don't refresh combined inbox,
    556      *       drafts, etc.
    557      *   <li>Refresh the mailbox list, if it hasn't been refreshed in the last
    558      *       {@link #MAILBOX_REFRESH_MIN_INTERVAL}.
    559      *   <li>Refresh inbox, if it's not the current mailbox and it hasn't been refreshed in the last
    560      *       {@link #INBOX_AUTO_REFRESH_MIN_INTERVAL}.
    561      * </ul>
    562      */
    563     @VisibleForTesting
    564     static class RefreshTask extends EmailAsyncTask<Void, Void, Boolean> {
    565         private final Clock mClock;
    566         private final Context mContext;
    567         private final long mAccountId;
    568         private final long mMailboxId;
    569         private final RefreshManager mRefreshManager;
    570         @VisibleForTesting
    571         long mInboxId;
    572 
    573         public RefreshTask(EmailAsyncTask.Tracker tracker, Context context, long accountId,
    574                 long mailboxId) {
    575             this(tracker, context, accountId, mailboxId, Clock.INSTANCE,
    576                     RefreshManager.getInstance(context));
    577         }
    578 
    579         @VisibleForTesting
    580         RefreshTask(EmailAsyncTask.Tracker tracker, Context context, long accountId,
    581                 long mailboxId, Clock clock, RefreshManager refreshManager) {
    582             super(tracker);
    583             mClock = clock;
    584             mContext = context;
    585             mRefreshManager = refreshManager;
    586             mAccountId = accountId;
    587             mMailboxId = mailboxId;
    588         }
    589 
    590         /**
    591          * Do DB access on a worker thread.
    592          */
    593         @Override
    594         protected Boolean doInBackground(Void... params) {
    595             mInboxId = Account.getInboxId(mContext, mAccountId);
    596             return Mailbox.isRefreshable(mContext, mMailboxId);
    597         }
    598 
    599         /**
    600          * Do the actual refresh.
    601          */
    602         @Override
    603         protected void onSuccess(Boolean isCurrentMailboxRefreshable) {
    604             if (isCurrentMailboxRefreshable == null) {
    605                 return;
    606             }
    607             if (isCurrentMailboxRefreshable) {
    608                 mRefreshManager.refreshMessageList(mAccountId, mMailboxId, true);
    609             }
    610             // Refresh mailbox list
    611             if (mAccountId != Account.NO_ACCOUNT) {
    612                 if (shouldRefreshMailboxList()) {
    613                     mRefreshManager.refreshMailboxList(mAccountId);
    614                 }
    615             }
    616             // Refresh inbox
    617             if (shouldAutoRefreshInbox()) {
    618                 mRefreshManager.refreshMessageList(mAccountId, mInboxId, true);
    619             }
    620         }
    621 
    622         /**
    623          * @return true if the mailbox list of the current account hasn't been refreshed
    624          * in the last {@link #MAILBOX_REFRESH_MIN_INTERVAL}.
    625          */
    626         @VisibleForTesting
    627         boolean shouldRefreshMailboxList() {
    628             if (mRefreshManager.isMailboxListRefreshing(mAccountId)) {
    629                 return false;
    630             }
    631             final long nextRefreshTime = mRefreshManager.getLastMailboxListRefreshTime(mAccountId)
    632                     + MAILBOX_REFRESH_MIN_INTERVAL;
    633             if (nextRefreshTime > mClock.getTime()) {
    634                 return false;
    635             }
    636             return true;
    637         }
    638 
    639         /**
    640          * @return true if the inbox of the current account hasn't been refreshed
    641          * in the last {@link #INBOX_AUTO_REFRESH_MIN_INTERVAL}.
    642          */
    643         @VisibleForTesting
    644         boolean shouldAutoRefreshInbox() {
    645             if (mInboxId == mMailboxId) {
    646                 return false; // Current ID == inbox.  No need to auto-refresh.
    647             }
    648             if (mRefreshManager.isMessageListRefreshing(mInboxId)) {
    649                 return false;
    650             }
    651             final long nextRefreshTime = mRefreshManager.getLastMessageListRefreshTime(mInboxId)
    652                     + INBOX_AUTO_REFRESH_MIN_INTERVAL;
    653             if (nextRefreshTime > mClock.getTime()) {
    654                 return false;
    655             }
    656             return true;
    657         }
    658     }
    659 
    660     private class ActionBarControllerCallback implements ActionBarController.Callback {
    661 
    662         @Override
    663         public long getUIAccountId() {
    664             return UIControllerTwoPane.this.getUIAccountId();
    665         }
    666 
    667         @Override
    668         public long getMailboxId() {
    669             return getMessageListMailboxId();
    670         }
    671 
    672         @Override
    673         public boolean isAccountSelected() {
    674             return UIControllerTwoPane.this.isAccountSelected();
    675         }
    676 
    677         @Override
    678         public void onAccountSelected(long accountId) {
    679             switchAccount(accountId, false);
    680         }
    681 
    682         @Override
    683         public void onMailboxSelected(long accountId, long mailboxId) {
    684             openMailbox(accountId, mailboxId);
    685         }
    686 
    687         @Override
    688         public void onNoAccountsFound() {
    689             Welcome.actionStart(mActivity);
    690             mActivity.finish();
    691         }
    692 
    693         @Override
    694         public int getTitleMode() {
    695             if (mThreePane.isLeftPaneVisible()) {
    696                 // Mailbox list visible
    697                 return TITLE_MODE_ACCOUNT_NAME_ONLY;
    698             } else if (mThreePane.isRightPaneVisible()
    699                     && !mThreePane.isMiddlePaneVisible()) {
    700                 return TITLE_MODE_MESSAGE_SUBJECT;
    701             } else {
    702                 // Mailbox list hidden
    703                 return TITLE_MODE_ACCOUNT_WITH_MAILBOX;
    704             }
    705         }
    706 
    707         public String getMessageSubject() {
    708             if (isMessageViewInstalled() && getMessageViewFragment().isMessageOpen()) {
    709                 return getMessageViewFragment().getMessage().mSubject;
    710             } else {
    711                 return null;
    712             }
    713         }
    714 
    715         @Override
    716         public boolean shouldShowUp() {
    717             final int visiblePanes = mThreePane.getVisiblePanes();
    718             final boolean leftPaneHidden = ((visiblePanes & ThreePaneLayout.PANE_LEFT) == 0);
    719             return leftPaneHidden
    720                     || (isMailboxListInstalled() && getMailboxListFragment().canNavigateUp());
    721         }
    722 
    723         @Override
    724         public String getSearchHint() {
    725             return UIControllerTwoPane.this.getSearchHint();
    726         }
    727 
    728         @Override
    729         public void onSearchStarted() {
    730             UIControllerTwoPane.this.onSearchStarted();
    731         }
    732 
    733         @Override
    734         public void onSearchSubmit(final String queryTerm) {
    735             UIControllerTwoPane.this.onSearchSubmit(queryTerm);
    736         }
    737 
    738         @Override
    739         public void onSearchExit() {
    740             UIControllerTwoPane.this.onSearchExit();
    741         }
    742 
    743         @Override
    744         public void onUpPressed() {
    745             onBackPressed(false);
    746         }
    747     }
    748 }
    749