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