MessageList.java revision d632426c0a05ac7f1e8db08cc0b2e21a261771f4
1/*
2 * Copyright (C) 2009 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
17package com.android.email.activity;
18
19import com.android.email.Controller;
20import com.android.email.ControllerResultUiThreadWrapper;
21import com.android.email.Email;
22import com.android.email.R;
23import com.android.email.Utility;
24import com.android.email.activity.setup.AccountSecurity;
25import com.android.email.activity.setup.AccountSettings;
26import com.android.email.mail.AuthenticationFailedException;
27import com.android.email.mail.CertificateValidationException;
28import com.android.email.mail.MessagingException;
29import com.android.email.provider.EmailContent;
30import com.android.email.provider.EmailContent.Account;
31import com.android.email.provider.EmailContent.AccountColumns;
32import com.android.email.provider.EmailContent.Mailbox;
33import com.android.email.provider.EmailContent.MailboxColumns;
34import com.android.email.service.MailService;
35
36import android.app.Activity;
37import android.app.NotificationManager;
38import android.content.ContentResolver;
39import android.content.Context;
40import android.content.Intent;
41import android.database.Cursor;
42import android.net.Uri;
43import android.os.AsyncTask;
44import android.os.Bundle;
45import android.os.Handler;
46import android.view.Menu;
47import android.view.MenuItem;
48import android.view.View;
49import android.view.View.OnClickListener;
50import android.view.animation.Animation;
51import android.view.animation.Animation.AnimationListener;
52import android.view.animation.AnimationUtils;
53import android.widget.Button;
54import android.widget.ProgressBar;
55import android.widget.TextView;
56
57public class MessageList extends Activity implements OnClickListener,
58        AnimationListener, MessageListFragment.Callback {
59    // Intent extras (internal to this activity)
60    private static final String EXTRA_ACCOUNT_ID = "com.android.email.activity._ACCOUNT_ID";
61    private static final String EXTRA_MAILBOX_TYPE = "com.android.email.activity.MAILBOX_TYPE";
62    private static final String EXTRA_MAILBOX_ID = "com.android.email.activity.MAILBOX_ID";
63
64    private static final int REQUEST_SECURITY = 0;
65
66    // UI support
67    private MessageListFragment mListFragment;
68    private View mMultiSelectPanel;
69    private Button mReadUnreadButton;
70    private Button mFavoriteButton;
71    private Button mDeleteButton;
72    private TextView mErrorBanner;
73
74    private final Controller mController = Controller.getInstance(getApplication());
75    private ControllerResultUiThreadWrapper<ControllerResults> mControllerCallback;
76
77    private TextView mLeftTitle;
78    private ProgressBar mProgressIcon;
79
80    // DB access
81    private ContentResolver mResolver;
82    private SetTitleTask mSetTitleTask;
83
84    private MailboxFinder mMailboxFinder;
85    private MailboxFinderCallback mMailboxFinderCallback = new MailboxFinderCallback();
86
87    private static final int MAILBOX_NAME_COLUMN_ID = 0;
88    private static final int MAILBOX_NAME_COLUMN_ACCOUNT_KEY = 1;
89    private static final int MAILBOX_NAME_COLUMN_TYPE = 2;
90    private static final String[] MAILBOX_NAME_PROJECTION = new String[] {
91            MailboxColumns.DISPLAY_NAME, MailboxColumns.ACCOUNT_KEY,
92            MailboxColumns.TYPE};
93
94    private static final int ACCOUNT_DISPLAY_NAME_COLUMN_ID = 0;
95    private static final String[] ACCOUNT_NAME_PROJECTION = new String[] {
96            AccountColumns.DISPLAY_NAME };
97
98    private static final String ID_SELECTION = EmailContent.RECORD_ID + "=?";
99
100    /* package */ MessageListFragment getListFragmentForTest() {
101        return mListFragment;
102    }
103
104    /**
105     * Open a specific mailbox.
106     *
107     * TODO This should just shortcut to a more generic version that can accept a list of
108     * accounts/mailboxes (e.g. merged inboxes).
109     *
110     * @param context
111     * @param id mailbox key
112     */
113    public static void actionHandleMailbox(Context context, long id) {
114        context.startActivity(createIntent(context, -1, id, -1));
115    }
116
117    /**
118     * Open a specific mailbox by account & type
119     *
120     * @param context The caller's context (for generating an intent)
121     * @param accountId The account to open
122     * @param mailboxType the type of mailbox to open (e.g. @see EmailContent.Mailbox.TYPE_INBOX)
123     */
124    public static void actionHandleAccount(Context context, long accountId, int mailboxType) {
125        context.startActivity(createIntent(context, accountId, -1, mailboxType));
126    }
127
128    /**
129     * Open the inbox of the account with a UUID.  It's used to handle old style
130     * (Android <= 1.6) desktop shortcut intents.
131     */
132    public static void actionOpenAccountInboxUuid(Context context, String accountUuid) {
133        Intent i = createIntent(context, -1, -1, Mailbox.TYPE_INBOX);
134        i.setData(Account.getShortcutSafeUriFromUuid(accountUuid));
135        context.startActivity(i);
136    }
137
138    /**
139     * Return an intent to open a specific mailbox by account & type.
140     *
141     * @param context The caller's context (for generating an intent)
142     * @param accountId The account to open, or -1
143     * @param mailboxId the ID of the mailbox to open, or -1
144     * @param mailboxType the type of mailbox to open (e.g. @see Mailbox.TYPE_INBOX) or -1
145     */
146    public static Intent createIntent(Context context, long accountId, long mailboxId,
147            int mailboxType) {
148        Intent intent = new Intent(context, MessageList.class);
149        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
150        if (accountId != -1) intent.putExtra(EXTRA_ACCOUNT_ID, accountId);
151        if (mailboxId != -1) intent.putExtra(EXTRA_MAILBOX_ID, mailboxId);
152        if (mailboxType != -1) intent.putExtra(EXTRA_MAILBOX_TYPE, mailboxType);
153        return intent;
154    }
155
156    /**
157     * Create and return an intent for a desktop shortcut for an account.
158     *
159     * @param context Calling context for building the intent
160     * @param account The account of interest
161     * @param mailboxType The folder name to open (typically Mailbox.TYPE_INBOX)
162     * @return an Intent which can be used to view that account
163     */
164    public static Intent createAccountIntentForShortcut(Context context, Account account,
165            int mailboxType) {
166        Intent i = createIntent(context, -1, -1, mailboxType);
167        i.setData(account.getShortcutSafeUri());
168        return i;
169    }
170
171    @Override
172    public void onCreate(Bundle icicle) {
173        super.onCreate(icicle);
174        setContentView(R.layout.message_list);
175
176        mControllerCallback = new ControllerResultUiThreadWrapper<ControllerResults>(
177                new Handler(), new ControllerResults());
178        mListFragment = (MessageListFragment) findFragmentById(R.id.message_list_fragment);
179        mMultiSelectPanel = findViewById(R.id.footer_organize);
180        mReadUnreadButton = (Button) findViewById(R.id.btn_read_unread);
181        mFavoriteButton = (Button) findViewById(R.id.btn_multi_favorite);
182        mDeleteButton = (Button) findViewById(R.id.btn_multi_delete);
183        mLeftTitle = (TextView) findViewById(R.id.title_left_text);
184        mProgressIcon = (ProgressBar) findViewById(R.id.title_progress_icon);
185        mErrorBanner = (TextView) findViewById(R.id.connection_error_text);
186
187        mReadUnreadButton.setOnClickListener(this);
188        mFavoriteButton.setOnClickListener(this);
189        mDeleteButton.setOnClickListener(this);
190        ((Button) findViewById(R.id.account_title_button)).setOnClickListener(this);
191
192        mListFragment.setCallback(this);
193
194        mResolver = getContentResolver();
195
196        // Show the appropriate account/mailbox specified by an {@link Intent}.
197        selectAccountAndMailbox(getIntent());
198    }
199
200    /**
201     * Show the appropriate account/mailbox specified by an {@link Intent}.
202     */
203    private void selectAccountAndMailbox(Intent intent) {
204        long mailboxId = intent.getLongExtra(EXTRA_MAILBOX_ID, -1);
205        if (mailboxId != -1) {
206            // Specific mailbox ID was provided - go directly to it
207            mSetTitleTask = new SetTitleTask(mailboxId);
208            mSetTitleTask.execute();
209            mListFragment.openMailbox(-1, mailboxId);
210        } else {
211            int mailboxType = intent.getIntExtra(EXTRA_MAILBOX_TYPE, Mailbox.TYPE_INBOX);
212            Uri uri = intent.getData();
213            // TODO Possible ANR.  getAccountIdFromShortcutSafeUri accesses DB.
214            long accountId = (uri == null) ? -1
215                    : Account.getAccountIdFromShortcutSafeUri(this, uri);
216            if (accountId == -1) {
217                accountId = intent.getLongExtra(EXTRA_ACCOUNT_ID, -1);
218            }
219            if (accountId == -1) {
220                launchWelcomeAndFinish();
221                return;
222            }
223            mMailboxFinder = new MailboxFinder(this, accountId, mailboxType,
224                    mMailboxFinderCallback);
225            mMailboxFinder.startLookup();
226        }
227        // TODO set title to "account > mailbox (#unread)"
228    }
229
230    @Override
231    public void onPause() {
232        super.onPause();
233        mController.removeResultCallback(mControllerCallback);
234    }
235
236    @Override
237    public void onResume() {
238        super.onResume();
239        mController.addResultCallback(mControllerCallback);
240
241        // clear notifications here
242        NotificationManager notificationManager = (NotificationManager)
243                getSystemService(Context.NOTIFICATION_SERVICE);
244        notificationManager.cancel(MailService.NOTIFICATION_ID_NEW_MESSAGES);
245
246        // Exit immediately if the accounts list has changed (e.g. externally deleted)
247        if (Email.getNotifyUiAccountsChanged()) {
248            Welcome.actionStart(this);
249            finish();
250            return;
251        }
252    }
253
254    @Override
255    protected void onDestroy() {
256        super.onDestroy();
257
258        if (mMailboxFinder != null) {
259            mMailboxFinder.close();
260            mMailboxFinder = null;
261        }
262        Utility.cancelTaskInterrupt(mSetTitleTask);
263        mSetTitleTask = null;
264    }
265
266
267    private void launchWelcomeAndFinish() {
268        Welcome.actionStart(this);
269        finish();
270    }
271
272    /**
273     * Called when the list fragment can't find mailbox/account.
274     */
275    public void onMailboxNotFound() {
276        finish();
277    }
278
279    @Override
280    public void onMessageOpen(long messageId, long messageMailboxId, long listMailboxId, int type) {
281        if (type == MessageListFragment.Callback.TYPE_DRAFT) {
282            MessageCompose.actionEditDraft(this, messageId);
283        } else {
284            final boolean disableReply = (type == MessageListFragment.Callback.TYPE_TRASH);
285            // WARNING: here we pass "listMailboxId", which can be the negative id of
286            // a compound mailbox, instead of the mailboxId of the particular message that
287            // is opened.  This is to support the next/prev buttons on the message view
288            // properly even for combined mailboxes.
289            MessageView.actionView(this, messageId, listMailboxId, disableReply);
290        }
291    }
292
293    public void onClick(View v) {
294        switch (v.getId()) {
295            case R.id.btn_read_unread:
296                mListFragment.onMultiToggleRead();
297                break;
298            case R.id.btn_multi_favorite:
299                mListFragment.onMultiToggleFavorite();
300                break;
301            case R.id.btn_multi_delete:
302                mListFragment.onMultiDelete();
303                break;
304            case R.id.account_title_button:
305                onAccounts();
306                break;
307        }
308    }
309
310    public void onAnimationEnd(Animation animation) {
311        mListFragment.updateListPosition();
312    }
313
314    public void onAnimationRepeat(Animation animation) {
315    }
316
317    public void onAnimationStart(Animation animation) {
318    }
319
320    @Override
321    public boolean onPrepareOptionsMenu(Menu menu) {
322        // Re-create menu every time.  (We may not know the mailbox id yet)
323        menu.clear();
324        if (mListFragment.isMagicMailbox()) {
325            getMenuInflater().inflate(R.menu.message_list_option_smart_folder, menu);
326        } else {
327            getMenuInflater().inflate(R.menu.message_list_option, menu);
328        }
329        boolean showDeselect = mListFragment.getSelectedCount() > 0;
330        menu.setGroupVisible(R.id.deselect_all_group, showDeselect);
331        return true;
332    }
333
334    @Override
335    public boolean onOptionsItemSelected(MenuItem item) {
336        switch (item.getItemId()) {
337            case R.id.refresh:
338                mListFragment.onRefresh();
339                return true;
340            case R.id.folders:
341                onFolders();
342                return true;
343            case R.id.accounts:
344                onAccounts();
345                return true;
346            case R.id.compose:
347                onCompose();
348                return true;
349            case R.id.account_settings:
350                onEditAccount();
351                return true;
352            case R.id.deselect_all:
353                mListFragment.onDeselectAll();
354                return true;
355            default:
356                return super.onOptionsItemSelected(item);
357        }
358    }
359
360    private void onFolders() {
361        if (!mListFragment.isMagicMailbox()) { // Magic boxes don't have "folders" option.
362            // TODO smaller projection
363            Mailbox mailbox = Mailbox.restoreMailboxWithId(this, mListFragment.getMailboxId());
364            if (mailbox != null) {
365                MailboxList.actionHandleAccount(this, mailbox.mAccountKey);
366                finish();
367            }
368        }
369    }
370
371    private void onAccounts() {
372        AccountFolderList.actionShowAccounts(this);
373        finish();
374    }
375
376    private void onCompose() {
377        MessageCompose.actionCompose(this, mListFragment.getAccountId());
378    }
379
380    private void onEditAccount() {
381        if (!mListFragment.isMagicMailbox()) { // Magic boxes don't have "accout settings" option.
382            AccountSettings.actionSettings(this, mListFragment.getAccountId());
383        }
384    }
385
386    /**
387     * Show multi-selection panel, if one or more messages are selected.   Button labels will be
388     * updated too.
389     */
390    public void onSelectionChanged() {
391        showMultiPanel(mListFragment.getSelectedCount() > 0);
392    }
393
394    private void updateFooterButtonNames () {
395        // Show "unread_action" when one or more read messages are selected.
396        if (mListFragment.doesSelectionContainReadMessage()) {
397            mReadUnreadButton.setText(R.string.unread_action);
398        } else {
399            mReadUnreadButton.setText(R.string.read_action);
400        }
401        // Show "set_star_action" when one or more un-starred messages are selected.
402        if (mListFragment.doesSelectionContainNonStarredMessage()) {
403            mFavoriteButton.setText(R.string.set_star_action);
404        } else {
405            mFavoriteButton.setText(R.string.remove_star_action);
406        }
407    }
408
409    /**
410     * Show or hide the panel of multi-select options
411     */
412    private void showMultiPanel(boolean show) {
413        if (show && mMultiSelectPanel.getVisibility() != View.VISIBLE) {
414            mMultiSelectPanel.setVisibility(View.VISIBLE);
415            Animation animation = AnimationUtils.loadAnimation(this, R.anim.footer_appear);
416            animation.setAnimationListener(this);
417            mMultiSelectPanel.startAnimation(animation);
418        } else if (!show && mMultiSelectPanel.getVisibility() != View.GONE) {
419            mMultiSelectPanel.setVisibility(View.GONE);
420            mMultiSelectPanel.startAnimation(
421                        AnimationUtils.loadAnimation(this, R.anim.footer_disappear));
422        }
423        if (show) {
424            updateFooterButtonNames();
425        }
426    }
427
428    /**
429     * Handle the eventual result from the security update activity
430     *
431     * Note, this is extremely coarse, and it simply returns the user to the Accounts list.
432     * Anything more requires refactoring of this Activity.
433     */
434    @Override
435    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
436        switch (requestCode) {
437            case REQUEST_SECURITY:
438                onAccounts();
439        }
440        super.onActivityResult(requestCode, resultCode, data);
441    }
442
443    private class SetTitleTask extends AsyncTask<Void, Void, Object[]> {
444
445        private long mMailboxKey;
446
447        public SetTitleTask(long mailboxKey) {
448            mMailboxKey = mailboxKey;
449        }
450
451        @Override
452        protected Object[] doInBackground(Void... params) {
453            // Check special Mailboxes
454            int resIdSpecialMailbox = 0;
455            if (mMailboxKey == Mailbox.QUERY_ALL_INBOXES) {
456                resIdSpecialMailbox = R.string.account_folder_list_summary_inbox;
457            } else if (mMailboxKey == Mailbox.QUERY_ALL_FAVORITES) {
458                resIdSpecialMailbox = R.string.account_folder_list_summary_starred;
459            } else if (mMailboxKey == Mailbox.QUERY_ALL_DRAFTS) {
460                resIdSpecialMailbox = R.string.account_folder_list_summary_drafts;
461            } else if (mMailboxKey == Mailbox.QUERY_ALL_OUTBOX) {
462                resIdSpecialMailbox = R.string.account_folder_list_summary_outbox;
463            }
464            if (resIdSpecialMailbox != 0) {
465                return new Object[] {null, getString(resIdSpecialMailbox), 0};
466            }
467
468            String accountName = null;
469            String mailboxName = null;
470            String accountKey = null;
471            Cursor c = MessageList.this.mResolver.query(Mailbox.CONTENT_URI,
472                    MAILBOX_NAME_PROJECTION, ID_SELECTION,
473                    new String[] { Long.toString(mMailboxKey) }, null);
474            try {
475                if (c.moveToFirst()) {
476                    mailboxName = Utility.FolderProperties.getInstance(MessageList.this)
477                            .getDisplayName(c.getInt(MAILBOX_NAME_COLUMN_TYPE));
478                    if (mailboxName == null) {
479                        mailboxName = c.getString(MAILBOX_NAME_COLUMN_ID);
480                    }
481                    accountKey = c.getString(MAILBOX_NAME_COLUMN_ACCOUNT_KEY);
482                }
483            } finally {
484                c.close();
485            }
486            if (accountKey != null) {
487                c = MessageList.this.mResolver.query(Account.CONTENT_URI,
488                        ACCOUNT_NAME_PROJECTION, ID_SELECTION, new String[] { accountKey },
489                        null);
490                try {
491                    if (c.moveToFirst()) {
492                        accountName = c.getString(ACCOUNT_DISPLAY_NAME_COLUMN_ID);
493                    }
494                } finally {
495                    c.close();
496                }
497            }
498            int nAccounts = EmailContent.count(MessageList.this, Account.CONTENT_URI, null, null);
499            return new Object[] {accountName, mailboxName, nAccounts};
500        }
501
502        @Override
503        protected void onPostExecute(Object[] result) {
504            if (result == null) {
505                return;
506            }
507
508            final int nAccounts = (Integer) result[2];
509            if (result[0] != null) {
510                setTitleAccountName((String) result[0], nAccounts > 1);
511            }
512
513            if (result[1] != null) {
514                mLeftTitle.setText((String) result[1]);
515            }
516        }
517    }
518
519    private void setTitleAccountName(String accountName, boolean showAccountsButton) {
520        TextView accountsButton = (TextView) findViewById(R.id.account_title_button);
521        TextView textPlain = (TextView) findViewById(R.id.title_right_text);
522        if (showAccountsButton) {
523            accountsButton.setVisibility(View.VISIBLE);
524            textPlain.setVisibility(View.GONE);
525            accountsButton.setText(accountName);
526        } else {
527            accountsButton.setVisibility(View.GONE);
528            textPlain.setVisibility(View.VISIBLE);
529            textPlain.setText(accountName);
530        }
531    }
532
533    private void showProgressIcon(boolean show) {
534        int visibility = show ? View.VISIBLE : View.GONE;
535        mProgressIcon.setVisibility(visibility);
536        mListFragment.showProgressIcon(show);
537    }
538
539    private void showErrorBanner(String message) {
540        boolean isVisible = mErrorBanner.getVisibility() == View.VISIBLE;
541        if (message != null) {
542            mErrorBanner.setText(message);
543            if (!isVisible) {
544                mErrorBanner.setVisibility(View.VISIBLE);
545                mErrorBanner.startAnimation(
546                        AnimationUtils.loadAnimation(
547                                MessageList.this, R.anim.header_appear));
548            }
549        } else {
550            if (isVisible) {
551                mErrorBanner.setVisibility(View.GONE);
552                mErrorBanner.startAnimation(
553                        AnimationUtils.loadAnimation(
554                                MessageList.this, R.anim.header_disappear));
555            }
556        }
557    }
558
559    /**
560     * Controller results listener.  We wrap it with {@link ControllerResultUiThreadWrapper},
561     * so all methods are called on the UI thread.
562     */
563    private class ControllerResults extends Controller.Result {
564
565        // This is used to alter the connection banner operation for sending messages
566        private MessagingException mSendMessageException;
567
568        // TODO check accountKey and only react to relevant notifications
569        @Override
570        public void updateMailboxCallback(MessagingException result, long accountKey,
571                long mailboxKey, int progress, int numNewMessages) {
572            updateBanner(result, progress, mailboxKey);
573            if (result != null || progress == 100) {
574                Email.updateMailboxRefreshTime(mailboxKey);
575            }
576            updateProgress(result, progress);
577        }
578
579        /**
580         * We alter the updateBanner hysteresis here to capture any failures and handle
581         * them just once at the end.  This callback is overly overloaded:
582         *  result == null, messageId == -1, progress == 0:     start batch send
583         *  result == null, messageId == xx, progress == 0:     start sending one message
584         *  result == xxxx, messageId == xx, progress == 0;     failed sending one message
585         *  result == null, messageId == -1, progres == 100;    finish sending batch
586         */
587        @Override
588        public void sendMailCallback(MessagingException result, long accountId, long messageId,
589                int progress) {
590            if (mListFragment.isOutbox()) {
591                // reset captured error when we start sending one or more messages
592                if (messageId == -1 && result == null && progress == 0) {
593                    mSendMessageException = null;
594                }
595                // capture first exception that comes along
596                if (result != null && mSendMessageException == null) {
597                    mSendMessageException = result;
598                }
599                // if we're completing the sequence, change the banner state
600                if (messageId == -1 && progress == 100) {
601                    updateBanner(mSendMessageException, progress, mListFragment.getMailboxId());
602                }
603                // always update the spinner, which has less state to worry about
604                updateProgress(result, progress);
605            }
606        }
607
608        private void updateProgress(MessagingException result, int progress) {
609            showProgressIcon(result == null && progress < 100);
610        }
611
612        /**
613         * Show or hide the connection error banner, and convert the various MessagingException
614         * variants into localizable text.  There is hysteresis in the show/hide logic:  Once shown,
615         * the banner will remain visible until some progress is made on the connection.  The
616         * goal is to keep it from flickering during retries in a bad connection state.
617         *
618         * @param result
619         * @param progress
620         */
621        private void updateBanner(MessagingException result, int progress, long mailboxKey) {
622            if (mailboxKey != mListFragment.getMailboxId()) {
623                return;
624            }
625            if (result != null) {
626                int id = R.string.status_network_error;
627                if (result instanceof AuthenticationFailedException) {
628                    id = R.string.account_setup_failed_dlg_auth_message;
629                } else if (result instanceof CertificateValidationException) {
630                    id = R.string.account_setup_failed_dlg_certificate_message;
631                } else {
632                    switch (result.getExceptionType()) {
633                        case MessagingException.IOERROR:
634                            id = R.string.account_setup_failed_ioerror;
635                            break;
636                        case MessagingException.TLS_REQUIRED:
637                            id = R.string.account_setup_failed_tls_required;
638                            break;
639                        case MessagingException.AUTH_REQUIRED:
640                            id = R.string.account_setup_failed_auth_required;
641                            break;
642                        case MessagingException.GENERAL_SECURITY:
643                            id = R.string.account_setup_failed_security;
644                            break;
645                        // TODO Generate a unique string for this case, which is the case
646                        // where the security policy needs to be updated.
647                        case MessagingException.SECURITY_POLICIES_REQUIRED:
648                            id = R.string.account_setup_failed_security;
649                            break;
650                    }
651                }
652                showErrorBanner(getString(id));
653            } else if (progress > 0) {
654                showErrorBanner(null);
655            }
656        }
657    }
658
659    private class MailboxFinderCallback implements MailboxFinder.Callback {
660        @Override
661        public void onMailboxFound(long accountId, long mailboxId) {
662            mSetTitleTask = new SetTitleTask(mailboxId);
663            mSetTitleTask.execute();
664            mListFragment.openMailbox(accountId, mailboxId);
665        }
666
667        @Override
668        public void onAccountNotFound() {
669            // Let the Welcome activity show the default screen.
670            launchWelcomeAndFinish();
671        }
672
673        @Override
674        public void onMailboxNotFound(long accountId) {
675            // Let the Welcome activity show the default screen.
676            launchWelcomeAndFinish();
677        }
678
679        @Override
680        public void onAccountSecurityHold(long accountId) {
681            // launch the security setup activity
682            Intent i = AccountSecurity.actionUpdateSecurityIntent(
683                    MessageList.this, accountId);
684            MessageList.this.startActivityForResult(i, REQUEST_SECURITY);
685        }
686    }
687}
688