AbstractActivityController.java revision e0828393e175c9293c86a7490225f324cbec5eef
1/******************************************************************************* 2 * Copyright (C) 2012 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 *******************************************************************************/ 17 18package com.android.mail.ui; 19 20import android.app.ActionBar; 21import android.app.ActionBar.LayoutParams; 22import android.app.Activity; 23import android.app.Dialog; 24import android.content.ContentResolver; 25import android.content.Context; 26import android.content.CursorLoader; 27import android.content.Intent; 28import android.content.Loader; 29import android.database.Cursor; 30import android.net.Uri; 31import android.os.AsyncTask; 32import android.os.Bundle; 33import android.view.KeyEvent; 34import android.view.LayoutInflater; 35import android.view.Menu; 36import android.view.MenuInflater; 37import android.view.MenuItem; 38import android.view.MotionEvent; 39import android.widget.LinearLayout; 40 41import com.android.mail.R; 42import com.android.mail.ConversationListContext; 43import com.android.mail.compose.ComposeActivity; 44import com.android.mail.providers.Account; 45import com.android.mail.providers.AccountCacheProvider; 46import com.android.mail.providers.Conversation; 47import com.android.mail.providers.Folder; 48import com.android.mail.providers.Settings; 49import com.android.mail.providers.UIProvider; 50import com.android.mail.ui.AsyncRefreshTask; 51import com.android.mail.utils.LogUtils; 52import com.android.mail.utils.Utils; 53 54import com.google.common.collect.Sets; 55 56import java.util.Set; 57 58 59/** 60 * This is an abstract implementation of the Activity Controller. This class 61 * knows how to respond to menu items, state changes, layout changes, etc. It 62 * weaves together the views and listeners, dispatching actions to the 63 * respective underlying classes. 64 * <p> 65 * Even though this class is abstract, it should provide default implementations 66 * for most, if not all the methods in the ActivityController interface. This 67 * makes the task of the subclasses easier: OnePaneActivityController and 68 * TwoPaneActivityController can be concise when the common functionality is in 69 * AbstractActivityController. 70 * </p> 71 * <p> 72 * In the Gmail codebase, this was called BaseActivityController 73 * </p> 74 */ 75public abstract class AbstractActivityController implements ActivityController { 76 private static final String SAVED_CONVERSATION = "saved-conversation"; 77 private static final String SAVED_CONVERSATION_POSITION = "saved-conv-pos"; 78 // Keys for serialization of various information in Bundles. 79 private static final String SAVED_LIST_CONTEXT = "saved-list-context"; 80 private static final String SAVED_ACCOUNT = "saved-account"; 81 82 /** 83 * Are we on a tablet device or not. 84 */ 85 public final boolean IS_TABLET_DEVICE; 86 87 protected Account mAccount; 88 protected Folder mFolder; 89 protected ActionBarView mActionBarView; 90 protected final RestrictedActivity mActivity; 91 protected final Context mContext; 92 protected ConversationListContext mConvListContext; 93 private FetchAccountFolderTask mFetchAccountFolderTask; 94 protected Conversation mCurrentConversation; 95 96 protected ConversationListFragment mConversationListFragment; 97 /** 98 * The current mode of the application. All changes in mode are initiated by 99 * the activity controller. View mode changes are propagated to classes that 100 * attach themselves as listeners of view mode changes. 101 */ 102 protected final ViewMode mViewMode; 103 protected ContentResolver mResolver; 104 protected FolderListFragment mFolderListFragment; 105 protected ConversationViewFragment mConversationViewFragment; 106 protected boolean isLoaderInitialized = false; 107 private AsyncRefreshTask mAsyncRefreshTask; 108 109 private final Set<Uri> mCurrentAccountUris = Sets.newHashSet(); 110 protected Settings mCachedSettings; 111 private FetchSearchFolderTask mFetchSearchFolderTask; 112 113 protected static final String LOG_TAG = new LogUtils().getLogTag(); 114 private static final int ACCOUNT_CURSOR_LOADER = 0; 115 private static final int ACCOUNT_SETTINGS_LOADER = 1; 116 private static final int FOLDER_CURSOR_LOADER = 2; 117 118 public AbstractActivityController(MailActivity activity, ViewMode viewMode) { 119 mActivity = activity; 120 mViewMode = viewMode; 121 mContext = activity.getApplicationContext(); 122 IS_TABLET_DEVICE = Utils.useTabletUI(mContext); 123 } 124 125 @Override 126 public synchronized void attachConversationList(ConversationListFragment fragment) { 127 // If there is an existing fragment, unregister it 128 if (mConversationListFragment != null) { 129 mViewMode.removeListener(mConversationListFragment); 130 } 131 mConversationListFragment = fragment; 132 // If the current fragment is non-null, add it as a listener. 133 if (fragment != null) { 134 mViewMode.addListener(mConversationListFragment); 135 } 136 } 137 138 @Override 139 public synchronized void attachFolderList(FolderListFragment fragment) { 140 // If there is an existing fragment, unregister it 141 if (mFolderListFragment != null) { 142 mViewMode.removeListener(mFolderListFragment); 143 } 144 mFolderListFragment = fragment; 145 if (fragment != null) { 146 mViewMode.addListener(mFolderListFragment); 147 } 148 } 149 150 @Override 151 public void attachConversationView(ConversationViewFragment conversationViewFragment) { 152 mConversationViewFragment = conversationViewFragment; 153 } 154 155 @Override 156 public void clearSubject() { 157 // TODO(viki): Auto-generated method stub 158 } 159 160 @Override 161 public Account getCurrentAccount() { 162 return mAccount; 163 } 164 165 @Override 166 public ConversationListContext getCurrentListContext() { 167 return mConvListContext; 168 } 169 170 @Override 171 public String getHelpContext() { 172 return "Mail"; 173 } 174 175 @Override 176 public int getMode() { 177 return mViewMode.getMode(); 178 } 179 180 @Override 181 public String getUnshownSubject(String subject) { 182 // Calculate how much of the subject is shown, and return the remaining. 183 return null; 184 } 185 186 @Override 187 public void handleConversationLoadError() { 188 // TODO(viki): Auto-generated method stub 189 } 190 191 /** 192 * Initialize the action bar. This is not visible to OnePaneController and 193 * TwoPaneController so they cannot override this behavior. 194 */ 195 private void initCustomActionBarView() { 196 ActionBar actionBar = mActivity.getActionBar(); 197 mActionBarView = (ActionBarView) LayoutInflater.from(mContext).inflate( 198 R.layout.actionbar_view, null); 199 200 if (actionBar != null && mActionBarView != null) { 201 // Why have a different variable for the same thing? We should apply 202 // the same actions 203 // on mActionBarView instead. 204 mActionBarView.initialize(mActivity, this, mViewMode, actionBar); 205 actionBar.setCustomView((LinearLayout) mActionBarView, new ActionBar.LayoutParams( 206 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 207 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, 208 ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_TITLE); 209 } 210 } 211 212 /** 213 * Returns whether the conversation list fragment is visible or not. 214 * Different layouts will have their own notion on the visibility of 215 * fragments, so this method needs to be overriden. 216 * 217 * @return 218 */ 219 protected abstract boolean isConversationListVisible(); 220 221 @Override 222 public void onAccountChanged(Account account) { 223 if (!account.equals(mAccount)) { 224 mAccount = account; 225 onSettingsChanged(null); 226 restartSettingsLoader(); 227 mActionBarView.setAccount(mAccount); 228 mActivity.invalidateOptionsMenu(); 229 // Account changed; existing folder is invalid. 230 mFolder = null; 231 fetchAccountFolderInfo(); 232 } 233 } 234 235 private void restartSettingsLoader() { 236 if (mAccount.settingsQueryUri != null) { 237 mActivity.getLoaderManager().restartLoader(ACCOUNT_SETTINGS_LOADER, null, this); 238 } 239 } 240 241 public void onSettingsChanged(Settings settings) { 242 mCachedSettings = settings; 243 resetActionBarIcon(); 244 } 245 246 @Override 247 public Settings getSettings() { 248 return mCachedSettings; 249 } 250 251 private void fetchAccountFolderInfo() { 252 if (mFetchAccountFolderTask != null) { 253 mFetchAccountFolderTask.cancel(true); 254 } 255 mFetchAccountFolderTask = new FetchAccountFolderTask(); 256 mFetchAccountFolderTask.execute(); 257 } 258 259 private void fetchSearchFolder(Intent intent) { 260 if (mFetchSearchFolderTask != null) { 261 mFetchSearchFolderTask.cancel(true); 262 } 263 mFetchSearchFolderTask = new FetchSearchFolderTask(intent 264 .getStringExtra(ConversationListContext.EXTRA_SEARCH_QUERY)); 265 mFetchSearchFolderTask.execute(); 266 } 267 268 @Override 269 public void onFolderChanged(Folder folder) { 270 if (folder != null && !folder.equals(mFolder)) { 271 setFolder(folder); 272 mConvListContext = ConversationListContext.forFolder(mContext, mAccount, mFolder); 273 showConversationList(mConvListContext); 274 } 275 } 276 277 private void setFolder(Folder folder) { 278 // Start watching folder for sync status. 279 if (folder != null && !folder.equals(mFolder)) { 280 mActionBarView.setRefreshInProgress(false); 281 mFolder = folder; 282 mActionBarView.setFolder(mFolder); 283 mActivity.getLoaderManager().restartLoader(FOLDER_CURSOR_LOADER, null, this); 284 } else if (folder == null) { 285 LogUtils.wtf(LOG_TAG, "Folder in setFolder is null"); 286 } 287 } 288 289 @Override 290 public void onActivityResult(int requestCode, int resultCode, Intent data) { 291 // TODO(viki): Auto-generated method stub 292 } 293 294 @Override 295 public void onConversationListVisibilityChanged(boolean visible) { 296 // TODO(viki): Auto-generated method stub 297 } 298 299 /** 300 * By default, doing nothing is right. A two-pane controller will need to 301 * override this. 302 */ 303 @Override 304 public void onConversationVisibilityChanged(boolean visible) { 305 // Do nothing. 306 return; 307 } 308 309 @Override 310 public boolean onCreate(Bundle savedState) { 311 // Initialize the action bar view. 312 initCustomActionBarView(); 313 // Allow shortcut keys to function for the ActionBar and menus. 314 mActivity.setDefaultKeyMode(Activity.DEFAULT_KEYS_SHORTCUT); 315 mResolver = mActivity.getContentResolver(); 316 317 // All the individual UI components listen for ViewMode changes. This 318 // simplifies the amount of logic in the AbstractActivityController, but increases the 319 // possibility of timing-related bugs. 320 mViewMode.addListener(this); 321 assert (mActionBarView != null); 322 mViewMode.addListener(mActionBarView); 323 324 restoreState(savedState); 325 return true; 326 } 327 328 @Override 329 public Dialog onCreateDialog(int id, Bundle bundle) { 330 // TODO(viki): Auto-generated method stub 331 return null; 332 } 333 334 @Override 335 public boolean onCreateOptionsMenu(Menu menu) { 336 MenuInflater inflater = mActivity.getMenuInflater(); 337 inflater.inflate(mActionBarView.getOptionsMenuId(), menu); 338 mActionBarView.onCreateOptionsMenu(menu); 339 return true; 340 } 341 342 @Override 343 public boolean onKeyDown(int keyCode, KeyEvent event) { 344 // TODO(viki): Auto-generated method stub 345 return false; 346 } 347 348 @Override 349 public boolean onOptionsItemSelected(MenuItem item) { 350 int id = item.getItemId(); 351 boolean handled = true; 352 switch (id) { 353 case android.R.id.home: 354 onUpPressed(); 355 break; 356 case R.id.compose: 357 ComposeActivity.compose(mActivity.getActivityContext(), mAccount); 358 break; 359 case R.id.show_all_folders: 360 showFolderList(); 361 break; 362 case R.id.refresh: 363 requestFolderRefresh(); 364 break; 365 case R.id.settings: 366 Utils.showSettings(mActivity.getActivityContext(), mAccount); 367 break; 368 case R.id.help_info_menu_item: 369 // TODO: enable context sensitive help 370 Utils.showHelp(mActivity.getActivityContext(), mAccount.helpIntentUri, null); 371 break; 372 default: 373 handled = false; 374 break; 375 } 376 return handled; 377 } 378 379 private void requestFolderRefresh() { 380 if (mFolder != null) { 381 if (mAsyncRefreshTask != null) { 382 mAsyncRefreshTask.cancel(true); 383 } 384 mAsyncRefreshTask = new AsyncRefreshTask(mContext, mFolder); 385 mAsyncRefreshTask.execute(); 386 } 387 } 388 389 @Override 390 public void onPrepareDialog(int id, Dialog dialog, Bundle bundle) { 391 // TODO(viki): Auto-generated method stub 392 393 } 394 395 @Override 396 public boolean onPrepareOptionsMenu(Menu menu) { 397 mActionBarView.onPrepareOptionsMenu(menu); 398 return true; 399 } 400 401 @Override 402 public void onPause() { 403 isLoaderInitialized = false; 404 } 405 406 @Override 407 public void onResume() { 408 if (mActionBarView != null) { 409 mActionBarView.onResume(); 410 } 411 } 412 413 @Override 414 public void onSaveInstanceState(Bundle outState) { 415 if (mAccount != null) { 416 LogUtils.d(LOG_TAG, "Saving the account now"); 417 outState.putParcelable(SAVED_ACCOUNT, mAccount); 418 } 419 if (mConvListContext != null) { 420 outState.putBundle(SAVED_LIST_CONTEXT, mConvListContext.toBundle()); 421 } 422 } 423 424 @Override 425 public void onSearchRequested(String query) { 426 Intent intent = new Intent(); 427 intent.setAction(Intent.ACTION_SEARCH); 428 intent.putExtra(ConversationListContext.EXTRA_SEARCH_QUERY, query); 429 intent.putExtra(Utils.EXTRA_ACCOUNT, mAccount); 430 intent.setComponent(mActivity.getComponentName()); 431 mActivity.startActivity(intent); 432 } 433 434 @Override 435 public void onStartDragMode() { 436 // TODO(viki): Auto-generated method stub 437 } 438 439 @Override 440 public void onStop() { 441 // TODO(viki): Auto-generated method stub 442 } 443 444 @Override 445 public void onStopDragMode() { 446 // TODO(viki): Auto-generated method stub 447 } 448 449 /** 450 * {@inheritDoc} Subclasses must override this to listen to mode changes 451 * from the ViewMode. Subclasses <b>must</b> call the parent's 452 * onViewModeChanged since the parent will handle common state changes. 453 */ 454 @Override 455 public void onViewModeChanged(int newMode) { 456 // Perform any mode specific work here. 457 // reset the action bar icon based on the mode. Why don't the individual 458 // controllers do 459 // this themselves? 460 461 // In conversation list mode, clean up the conversation. 462 if (newMode == ViewMode.CONVERSATION_LIST) { 463 // Clean up the conversation here. 464 } 465 466 // We don't want to invalidate the options menu when switching to 467 // conversation 468 // mode, as it will happen when the conversation finishes loading. 469 if (newMode != ViewMode.CONVERSATION) { 470 mActivity.invalidateOptionsMenu(); 471 } 472 } 473 474 @Override 475 public void onWindowFocusChanged(boolean hasFocus) { 476 // TODO(viki): Auto-generated method stub 477 } 478 479 @Override 480 public void reloadSearch(String string) { 481 // TODO(viki): Auto-generated method stub 482 } 483 484 /** 485 * @param savedState 486 */ 487 protected void restoreListContext(Bundle savedState) { 488 // TODO(viki): Restore the account, the folder, and the conversation, if any. 489 Bundle listContextBundle = savedState.getBundle(SAVED_LIST_CONTEXT); 490 if (listContextBundle != null) { 491 mConvListContext = ConversationListContext.forBundle(listContextBundle); 492 mFolder = mConvListContext.folder; 493 } 494 } 495 496 /** 497 * Restore the state from the previous bundle. Subclasses should call this 498 * method from the parent class, since it performs important UI 499 * initialization. 500 * 501 * @param savedState 502 */ 503 protected void restoreState(Bundle savedState) { 504 final Intent intent = mActivity.getIntent(); 505 if (savedState != null) { 506 restoreListContext(savedState); 507 mAccount = savedState.getParcelable(SAVED_ACCOUNT); 508 mActionBarView.setAccount(mAccount); 509 restartSettingsLoader(); 510 } else if (intent != null) { 511 if (Intent.ACTION_VIEW.equals(intent.getAction())) { 512 if (intent.hasExtra(Utils.EXTRA_ACCOUNT)) { 513 mAccount = ((Account) intent.getParcelableExtra(Utils.EXTRA_ACCOUNT)); 514 mActionBarView.setAccount(mAccount); 515 mActivity.getLoaderManager().restartLoader(ACCOUNT_SETTINGS_LOADER, null, this); 516 mActivity.invalidateOptionsMenu(); 517 } 518 if (intent.hasExtra(Utils.EXTRA_FOLDER)) { 519 // Open the folder. 520 LogUtils.d(LOG_TAG, "SHOW THE FOLDER at %s", 521 intent.getParcelableExtra(Utils.EXTRA_FOLDER)); 522 onFolderChanged((Folder) intent.getParcelableExtra(Utils.EXTRA_FOLDER)); 523 } 524 if (intent.hasExtra(Utils.EXTRA_CONVERSATION)) { 525 // Open the conversation. 526 LogUtils.d(LOG_TAG, "SHOW THE CONVERSATION at %s", 527 intent.getParcelableExtra(Utils.EXTRA_CONVERSATION)); 528 showConversation((Conversation) intent 529 .getParcelableExtra(Utils.EXTRA_CONVERSATION)); 530 } 531 } else if (Intent.ACTION_SEARCH.equals(intent.getAction())) { 532 mViewMode.enterSearchResultsListMode(); 533 mAccount = ((Account) intent.getParcelableExtra(Utils.EXTRA_ACCOUNT)); 534 mActionBarView.setAccount(mAccount); 535 fetchSearchFolder(intent); 536 } 537 } 538 // Create the accounts loader; this loads the account switch spinner. 539 mActivity.getLoaderManager().initLoader(ACCOUNT_CURSOR_LOADER, null, this); 540 } 541 542 @Override 543 public void setSubject(String subject) { 544 // Do something useful with the subject. This requires changing the 545 // conversation view's subject text. 546 } 547 548 @Override 549 public void startActionBarStatusCursorLoader(String account) { 550 // TODO(viki): Auto-generated method stub 551 } 552 553 @Override 554 public void stopActionBarStatusCursorLoader(String account) { 555 // TODO(viki): Auto-generated method stub 556 } 557 558 @Override 559 public void toggleStar(boolean toggleOn, long conversationId, long maxMessageId) { 560 // TODO(viki): Auto-generated method stub 561 } 562 563 @Override 564 public void onConversationSelected(Conversation conversation) { 565 mCurrentConversation = conversation; 566 showConversation(mCurrentConversation); 567 if (mConvListContext != null && mConvListContext.isSearchResult()) { 568 mViewMode.enterSearchResultsConversationMode(); 569 } else { 570 mViewMode.enterConversationMode(); 571 } 572 } 573 574 /** 575 * {@inheritDoc} 576 */ 577 @Override 578 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 579 // Create a loader to listen in on account changes. 580 if (id == ACCOUNT_CURSOR_LOADER) { 581 return new CursorLoader(mContext, AccountCacheProvider.getAccountsUri(), 582 UIProvider.ACCOUNTS_PROJECTION, null, null, null); 583 } else if (id == FOLDER_CURSOR_LOADER) { 584 return new CursorLoader(mActivity.getActivityContext(), mFolder.uri, 585 UIProvider.FOLDERS_PROJECTION, null, null, null); 586 } else if (id == ACCOUNT_SETTINGS_LOADER) { 587 if (mAccount.settingsQueryUri != null) { 588 return new CursorLoader(mActivity.getActivityContext(), mAccount.settingsQueryUri, 589 UIProvider.SETTINGS_PROJECTION, null, null, null); 590 } 591 } 592 return null; 593 } 594 595 private boolean accountsUpdated(Cursor accountCursor) { 596 // Check to see if the current account hasn't been set, or the account cursor is empty 597 if (mAccount == null || !accountCursor.moveToFirst()) { 598 return true; 599 } 600 601 // Check to see if the number of accounts are different, from the number we saw on the last 602 // updated 603 if (mCurrentAccountUris.size() != accountCursor.getCount()) { 604 return true; 605 } 606 607 // Check to see if the account list is different or if the current account is not found in 608 // the cursor. 609 boolean foundCurrentAccount = false; 610 do { 611 final Uri accountUri = 612 Uri.parse(accountCursor.getString(UIProvider.ACCOUNT_URI_COLUMN)); 613 if (!foundCurrentAccount && mAccount.uri.equals(accountUri)) { 614 foundCurrentAccount = true; 615 } 616 617 if (!mCurrentAccountUris.contains(accountUri)) { 618 return true; 619 } 620 } while (accountCursor.moveToNext()); 621 622 // As long as we found the current account, the list hasn't been updated 623 return !foundCurrentAccount; 624 } 625 626 /** 627 * Update the accounts on the device. This currently loads the first account 628 * in the list. 629 * 630 * @param loader 631 * @param accounts cursor into the AccountCache 632 * @return true if the update was successful, false otherwise 633 */ 634 private boolean updateAccounts(Loader<Cursor> loader, Cursor accounts) { 635 if (accounts == null || !accounts.moveToFirst()) { 636 return false; 637 } 638 639 final Account[] allAccounts = Account.getAllAccounts(accounts); 640 641 // Save the uris for the accounts 642 mCurrentAccountUris.clear(); 643 for (Account account : allAccounts) { 644 mCurrentAccountUris.add(account.uri); 645 } 646 647 final Account newAccount; 648 if (mAccount == null || !mCurrentAccountUris.contains(mAccount.uri)) { 649 accounts.moveToFirst(); 650 newAccount = new Account(accounts); 651 } else { 652 newAccount = mAccount; 653 } 654 // only bother updating the account/folder if the new account is different than the 655 // existing one 656 final boolean refetchFolderInfo = !newAccount.equals(mAccount); 657 onAccountChanged(newAccount); 658 659 if(refetchFolderInfo) { 660 fetchAccountFolderInfo(); 661 } 662 663 mActionBarView.setAccounts(allAccounts); 664 return (allAccounts.length > 0); 665 } 666 667 /** 668 * {@inheritDoc} 669 */ 670 @Override 671 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 672 // We want to reinitialize only if we haven't ever been initialized, or 673 // if the current account has vanished. 674 final int id = loader.getId(); 675 if (data == null) { 676 LogUtils.e(LOG_TAG, "Received null cursor from loader id: %d", id); 677 } 678 if (id == ACCOUNT_CURSOR_LOADER) { 679 680 final boolean accountListUpdated = accountsUpdated(data); 681 if (!isLoaderInitialized || accountListUpdated) { 682 isLoaderInitialized = updateAccounts(loader, data); 683 } 684 } else if (id == FOLDER_CURSOR_LOADER) { 685 // Check status of the cursor. 686 if (data != null) { 687 data.moveToFirst(); 688 Folder folder = new Folder(data); 689 if (folder.isSyncInProgress()) { 690 mActionBarView.onRefreshStarted(); 691 } else { 692 // Stop the spinner here. 693 mActionBarView.onRefreshStopped(folder.lastSyncResult); 694 } 695 LogUtils.v(LOG_TAG, "FOLDER STATUS = " + folder.syncStatus); 696 } 697 } else if (id == ACCOUNT_SETTINGS_LOADER) { 698 if (data != null) { 699 data.moveToFirst(); 700 onSettingsChanged(new Settings(data)); 701 } 702 } 703 } 704 705 /** 706 * {@inheritDoc} 707 */ 708 @Override 709 public void onLoaderReset(Loader<Cursor> loader) { 710 // Do nothing for now, since we don't have any state. When a load is 711 // finished, the 712 // onLoadFinished will be called and we will be fine. 713 } 714 715 @Override 716 public void onTouchEvent(MotionEvent event) { 717 if (event.getAction() == MotionEvent.ACTION_DOWN) { 718 int mode = mViewMode.getMode(); 719 if (mode == ViewMode.CONVERSATION_LIST) { 720 mConversationListFragment.onTouchEvent(event); 721 } else if (mode == ViewMode.CONVERSATION) { 722 mConversationViewFragment.onTouchEvent(event); 723 } 724 } 725 } 726 727 private class FetchAccountFolderTask extends AsyncTask<Void, Void, ConversationListContext> { 728 @Override 729 public ConversationListContext doInBackground(Void... params) { 730 return ConversationListContext.forFolder(mContext, mAccount, mFolder); 731 } 732 733 @Override 734 public void onPostExecute(ConversationListContext result) { 735 mConvListContext = result; 736 setFolder(mConvListContext.folder); 737 if (mFolderListFragment != null) { 738 mFolderListFragment.selectFolder(mConvListContext.folder); 739 } 740 showConversationList(mConvListContext); 741 mFetchAccountFolderTask = null; 742 } 743 } 744 745 private class FetchSearchFolderTask extends AsyncTask<Void, Void, Folder> { 746 String mQuery; 747 public FetchSearchFolderTask(String query) { 748 mQuery = query; 749 } 750 public Folder doInBackground(Void... params) { 751 Folder searchFolder = Folder.forSearchResults(mAccount, mQuery, 752 mActivity.getActivityContext()); 753 return searchFolder; 754 } 755 public void onPostExecute(Folder folder) { 756 setFolder(folder); 757 mConvListContext = ConversationListContext.forSearchQuery(mAccount, mFolder, mQuery); 758 showConversationList(mConvListContext); 759 mActivity.invalidateOptionsMenu(); 760 } 761 } 762} 763