• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
UIControllerTwoPane(EmailActivity activity)63     public UIControllerTwoPane(EmailActivity activity) {
64         super(activity);
65     }
66 
67     @Override
getLayoutId()68     public int getLayoutId() {
69         return R.layout.email_activity_two_pane;
70     }
71 
72     // ThreePaneLayoutCallback
73     @Override
onVisiblePanesChanged(int previousVisiblePanes)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
onMailboxSelected(long accountId, long mailboxId, boolean nestedNavigation)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      */
onCreateOptionsMenu(MenuInflater inflater, Menu menu)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
onAccountSelected(long accountId)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
onParentMailboxChanged()139     public void onParentMailboxChanged() {
140         refreshActionBar();
141     }
142 
143     // MessageListFragment$Callback
144     @Override
onMessageOpen(long messageId, long messageMailboxId, long listMailboxId, int type)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
onAdvancingOpAccepted(Set<Long> affectedMessages)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
onDragStarted()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
onDragEnded()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
onUrlInMessageClicked(String url)229     public boolean onUrlInMessageClicked(String url) {
230         return ActivityHelper.openUrlInMessage(mActivity, url, getActualAccountId());
231     }
232 
233     // MessageViewFragment$Callback
234     @Override
onLoadMessageStarted()235     public void onLoadMessageStarted() {
236     }
237 
238     // MessageViewFragment$Callback
239     @Override
onLoadMessageFinished()240     public void onLoadMessageFinished() {
241     }
242 
243     // MessageViewFragment$Callback
244     @Override
onLoadMessageError(String errorMessage)245     public void onLoadMessageError(String errorMessage) {
246     }
247 
248     // MessageViewFragment$Callback
249     @Override
onCalendarLinkClicked(long epochEventStartTime)250     public void onCalendarLinkClicked(long epochEventStartTime) {
251         ActivityHelper.openCalendar(mActivity, epochEventStartTime);
252     }
253 
254     // MessageViewFragment$Callback
255     @Override
onForward()256     public void onForward() {
257         MessageCompose.actionForward(mActivity, getMessageId());
258     }
259 
260     // MessageViewFragment$Callback
261     @Override
onReply()262     public void onReply() {
263         MessageCompose.actionReply(mActivity, getMessageId(), false);
264     }
265 
266     // MessageViewFragment$Callback
267     @Override
onReplyAll()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
onActivityViewReady()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
createActionBarController(Activity activity)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
getUIAccountId()301     public long getUIAccountId() {
302         return isMailboxListInstalled() ? getMailboxListFragment().getAccountId()
303                 :Account.NO_ACCOUNT;
304     }
305 
306     @Override
getMailboxSettingsMailboxId()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
isRefreshInProgress()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
isRefreshEnabled()325     protected boolean isRefreshEnabled() {
326         return getActualAccountId() != Account.NO_ACCOUNT
327                 && (mListContext.getMailboxId() > 0);
328     }
329 
330 
331     /** {@inheritDoc} */
332     @Override
onSaveInstanceState(Bundle outState)333     public void onSaveInstanceState(Bundle outState) {
334         super.onSaveInstanceState(outState);
335     }
336 
337     /** {@inheritDoc} */
338     @Override
onRestoreInstanceState(Bundle savedInstanceState)339     public void onRestoreInstanceState(Bundle savedInstanceState) {
340         super.onRestoreInstanceState(savedInstanceState);
341     }
342 
343     @Override
installMessageListFragment(MessageListFragment fragment)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
installMessageViewFragment(MessageViewFragment fragment)355     protected void installMessageViewFragment(MessageViewFragment fragment) {
356         super.installMessageViewFragment(fragment);
357 
358         if (isMessageListInstalled()) {
359             getMessageListFragment().setSelectedMessage(fragment.getMessageId());
360         }
361     }
362 
363     @Override
openInternal(final MessageListContext listContext, final long messageId)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      */
updateMailboxList(FragmentTransaction ft, boolean clearDependentPane)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      */
goBackToMailbox()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      */
updateMessageList(FragmentTransaction ft, boolean clearDependentPane)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      */
updateMessageList(boolean clearDependentPane)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      */
updateMessageView(FragmentTransaction ft, long messageId)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      */
navigateToMessage(long messageId)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      */
unselectMessage()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
onMoveToNewer()495         public void onMoveToNewer() {
496             moveToNewer();
497         }
498 
499         @Override
onMoveToOlder()500         public void onMoveToOlder() {
501             moveToOlder();
502         }
503     }
504 
505     /**
506      * Disable/enable the move-to-newer/older buttons.
507      */
updateNavigationArrows()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
onBackPressed(boolean isSystemBackKey)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
onRefresh()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 
RefreshTask(EmailAsyncTask.Tracker tracker, Context context, long accountId, long mailboxId)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
RefreshTask(EmailAsyncTask.Tracker tracker, Context context, long accountId, long mailboxId, Clock clock, RefreshManager refreshManager)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
doInBackground(Void... params)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
onSuccess(Boolean isCurrentMailboxRefreshable)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
shouldRefreshMailboxList()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
shouldAutoRefreshInbox()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
getUIAccountId()663         public long getUIAccountId() {
664             return UIControllerTwoPane.this.getUIAccountId();
665         }
666 
667         @Override
getMailboxId()668         public long getMailboxId() {
669             return getMessageListMailboxId();
670         }
671 
672         @Override
isAccountSelected()673         public boolean isAccountSelected() {
674             return UIControllerTwoPane.this.isAccountSelected();
675         }
676 
677         @Override
onAccountSelected(long accountId)678         public void onAccountSelected(long accountId) {
679             switchAccount(accountId, false);
680         }
681 
682         @Override
onMailboxSelected(long accountId, long mailboxId)683         public void onMailboxSelected(long accountId, long mailboxId) {
684             openMailbox(accountId, mailboxId);
685         }
686 
687         @Override
onNoAccountsFound()688         public void onNoAccountsFound() {
689             Welcome.actionStart(mActivity);
690             mActivity.finish();
691         }
692 
693         @Override
getTitleMode()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 
getMessageSubject()707         public String getMessageSubject() {
708             if (isMessageViewInstalled() && getMessageViewFragment().isMessageOpen()) {
709                 return getMessageViewFragment().getMessage().mSubject;
710             } else {
711                 return null;
712             }
713         }
714 
715         @Override
shouldShowUp()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
getSearchHint()724         public String getSearchHint() {
725             return UIControllerTwoPane.this.getSearchHint();
726         }
727 
728         @Override
onSearchStarted()729         public void onSearchStarted() {
730             UIControllerTwoPane.this.onSearchStarted();
731         }
732 
733         @Override
onSearchSubmit(final String queryTerm)734         public void onSearchSubmit(final String queryTerm) {
735             UIControllerTwoPane.this.onSearchSubmit(queryTerm);
736         }
737 
738         @Override
onSearchExit()739         public void onSearchExit() {
740             UIControllerTwoPane.this.onSearchExit();
741         }
742     }
743 }
744