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