public boolean onCreateOptionsMenu(Menu menu) {
   // If the mode is valid, then set the initial menu
   if (mMode == ViewMode.UNKNOWN) {
     return false;
   }
   mSearch = menu.findItem(R.id.search);
   if (mSearch != null) {
     mSearchWidget = (SearchView) mSearch.getActionView();
     mSearch.setOnActionExpandListener(this);
     SearchManager searchManager =
         (SearchManager) mActivity.getActivityContext().getSystemService(Context.SEARCH_SERVICE);
     if (searchManager != null && mSearchWidget != null) {
       SearchableInfo info = searchManager.getSearchableInfo(mActivity.getComponentName());
       mSearchWidget.setSearchableInfo(info);
       mSearchWidget.setOnQueryTextListener(this);
       mSearchWidget.setOnSuggestionListener(this);
       mSearchWidget.setIconifiedByDefault(true);
     }
   }
   mHelpItem = menu.findItem(R.id.help_info_menu_item);
   mSendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
   mRefreshItem = menu.findItem(R.id.refresh);
   mFolderSettingsItem = menu.findItem(R.id.folder_options);
   mEmptyTrashItem = menu.findItem(R.id.empty_trash);
   mEmptySpamItem = menu.findItem(R.id.empty_spam);
   return true;
 }
 @Override
 public void onViewModeChanged(int newMode) {
   mMode = newMode;
   mActivity.invalidateOptionsMenu();
   mHandler.removeMessages(SubtitleHandler.EMAIL);
   // Check if we are either on a phone, or in Conversation mode on tablet. For these, the
   // recent folders is enabled.
   switch (mMode) {
     case ViewMode.UNKNOWN:
       break;
     case ViewMode.CONVERSATION_LIST:
       showNavList();
       break;
     case ViewMode.SEARCH_RESULTS_CONVERSATION:
       mActionBar.setDisplayHomeAsUpEnabled(true);
       setEmptyMode();
       break;
     case ViewMode.CONVERSATION:
     case ViewMode.AD:
       closeSearchField();
       mActionBar.setDisplayHomeAsUpEnabled(true);
       setEmptyMode();
       break;
     case ViewMode.WAITING_FOR_ACCOUNT_INITIALIZATION:
       // We want the user to be able to switch accounts while waiting for an account
       // to sync.
       showNavList();
       break;
   }
 }
  protected void onConversationSeen() {
    LogUtils.d(LOG_TAG, "AbstractConversationViewFragment#onConversationSeen()");

    // Ignore unsafe calls made after a fragment is detached from an activity
    final ControllableActivity activity = (ControllableActivity) getActivity();
    if (activity == null) {
      LogUtils.w(LOG_TAG, "ignoring onConversationSeen for conv=%s", mConversation.id);
      return;
    }

    mViewState.setInfoForConversation(mConversation);

    LogUtils.d(
        LOG_TAG, "onConversationSeen() - mSuppressMarkingViewed = %b", mSuppressMarkingViewed);
    // In most circumstances we want to mark the conversation as viewed and read, since the
    // user has read it.  However, if the user has already marked the conversation unread, we
    // do not want a  later mark-read operation to undo this.  So we check this variable which
    // is set in #markUnread() which suppresses automatic mark-read.
    if (!mSuppressMarkingViewed) {
      // mark viewed/read if not previously marked viewed by this conversation view,
      // or if unread messages still exist in the message list cursor
      // we don't want to keep marking viewed on rotation or restore
      // but we do want future re-renders to mark read (e.g. "New message from X" case)
      final MessageCursor cursor = getMessageCursor();
      LogUtils.d(
          LOG_TAG,
          "onConversationSeen() - mConversation.isViewed() = %b, "
              + "cursor null = %b, cursor.isConversationRead() = %b",
          mConversation.isViewed(),
          cursor == null,
          cursor != null && cursor.isConversationRead());
      if (!mConversation.isViewed() || (cursor != null && !cursor.isConversationRead())) {
        // Mark the conversation viewed and read.
        activity
            .getConversationUpdater()
            .markConversationsRead(Arrays.asList(mConversation), true, true);

        // and update the Message objects in the cursor so the next time a cursor update
        // happens with these messages marked read, we know to ignore it
        if (cursor != null && !cursor.isClosed()) {
          cursor.markMessagesRead();
        }
      }
    }
    activity.getListHandler().onConversationSeen();
  }
 // BEGIN conversation header callbacks
 @Override
 public void onFoldersClicked() {
   if (mChangeFoldersMenuItem == null) {
     LogUtils.e(LOG_TAG, "unable to open 'change folders' dialog for a conversation");
     return;
   }
   mActivity.onOptionsItemSelected(mChangeFoldersMenuItem);
 }
 public void setBackButton() {
   if (mActionBar == null) {
     return;
   }
   // Show home as up, and show an icon.
   final int mask = ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME;
   mActionBar.setDisplayOptions(mask, mask);
   mActivity.getActionBar().setHomeButtonEnabled(true);
 }
 /** Removes the back button from being shown */
 public void removeBackButton() {
   if (mActionBar == null) {
     return;
   }
   // Remove the back button but continue showing an icon.
   final int mask = ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME;
   mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME, mask);
   mActivity.getActionBar().setHomeButtonEnabled(false);
 }
 private void updateAccount(Account account) {
   final boolean accountChanged = mAccount == null || !mAccount.uri.equals(account.uri);
   mAccount = account;
   if (mAccount != null && accountChanged) {
     final ContentResolver resolver = mActivity.getActivityContext().getContentResolver();
     final Bundle bundle = new Bundle(1);
     bundle.putParcelable(UIProvider.SetCurrentAccountColumns.ACCOUNT, account);
     final UpdateProvider updater = new UpdateProvider(mAccount.uri, resolver);
     updater.execute(bundle);
     setFolderAndAccount(false /* folderChanged */);
   }
 }
  public void initialize(
      ControllableActivity activity, ActivityController callback, ActionBar actionBar) {
    mActionBar = actionBar;
    mController = callback;
    mActivity = activity;
    initializeTitleViews();

    mFolderObserver =
        new FolderObserver() {
          @Override
          public void onChanged(Folder newFolder) {
            onFolderUpdated(newFolder);
          }
        };
    // Return values are purposely discarded. Initialization happens quite early, and we don't
    // have a valid folder, or a valid list of accounts.
    mFolderObserver.initialize(mController);
    updateAccount(mAccountObserver.initialize(activity.getAccountController()));
  }
  /**
   * Uses the current state to update the current folder {@link #mFolder} and the current account
   * {@link #mAccount} shown in the actionbar. Also updates the actionbar subtitle to momentarily
   * display the unread count if it has changed.
   *
   * @param folderChanged true if folder changed in terms of URI
   */
  private void setFolderAndAccount(final boolean folderChanged) {
    // Very little can be done if the actionbar or activity is null.
    if (mActionBar == null || mActivity == null) {
      return;
    }
    if (ViewMode.isWaitingForSync(mMode)) {
      // Account is not synced: clear title and update the subtitle.
      setTitle("");
      removeUnreadCount(true);
      return;
    }
    // Check if we should be changing the actionbar at all, and back off if not.
    final boolean isShowingFolder = mIsOnTablet || ViewMode.isListMode(mMode);
    if (!isShowingFolder) {
      // It isn't necessary to set the title in this case, as the title view will
      // be hidden
      return;
    }
    if (mFolder == null) {
      // Clear the action bar title.  We don't want the app name to be shown while
      // waiting for the folder query to finish
      setTitle("");
      return;
    }
    setTitle(mFolder.name);

    final int folderUnreadCount = mFolder.isUnreadCountHidden() ? 0 : mFolder.unreadCount;
    // The user shouldn't see "999+ unread messages", and then a short while later: "999+
    // unread messages". So we set our unread count just past the limit. This way we can
    // change the subtitle the first time around but not for subsequent changes as far as the
    // unread count remains over the limit.
    final int toDisplay =
        (folderUnreadCount > UNREAD_LIMIT) ? (UNREAD_LIMIT + 1) : folderUnreadCount;
    if ((mUnreadCount != toDisplay || folderChanged) && toDisplay != 0) {
      setSubtitle(Utils.getUnreadMessageString(mActivity.getApplicationContext(), toDisplay));
    }
    // Schedule a removal of unread count for the future, if there isn't one already. If the
    // unread count dropped to zero, remove it and show the account name right away.
    removeUnreadCount(toDisplay == 0);
    // Remember the new value for the next run
    mUnreadCount = toDisplay;
  }
 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
   super.onActivityCreated(savedInstanceState);
   final Activity activity = getActivity();
   if (!(activity instanceof ControllableActivity)) {
     LogUtils.wtf(
         LOG_TAG,
         "ConversationViewFragment expects only a ControllableActivity to"
             + "create it. Cannot proceed.");
   }
   if (activity == null || activity.isFinishing()) {
     // Activity is finishing, just bail.
     return;
   }
   mActivity = (ControllableActivity) activity;
   mContext = activity.getApplicationContext();
   mWebViewClient.setActivity(activity);
   mAccount = mAccountObserver.initialize(mActivity.getAccountController());
   mWebViewClient.setAccount(mAccount);
 }
 public ContactLoaderCallbacks getContactInfoSource() {
   if (mContactLoaderCallbacks == null) {
     mContactLoaderCallbacks = new ContactLoaderCallbacks(mActivity.getActivityContext());
   }
   return mContactLoaderCallbacks;
 }
 @Override
 public ConversationUpdater getListController() {
   final ControllableActivity activity = (ControllableActivity) getActivity();
   return activity != null ? activity.getConversationUpdater() : null;
 }
  // We need to do this here instead of in the fragment
  public void setConversationModeOptions(Menu menu) {
    if (mCurrentConversation == null) {
      return;
    }
    final boolean showMarkImportant = !mCurrentConversation.isImportant();
    Utils.setMenuItemVisibility(
        menu,
        R.id.mark_important,
        showMarkImportant
            && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
    Utils.setMenuItemVisibility(
        menu,
        R.id.mark_not_important,
        !showMarkImportant
            && mAccount.supportsCapability(UIProvider.AccountCapabilities.MARK_IMPORTANT));
    final boolean showDelete =
        mFolder != null && mFolder.supportsCapability(UIProvider.FolderCapabilities.DELETE);
    Utils.setMenuItemVisibility(menu, R.id.delete, showDelete);
    // We only want to show the discard drafts menu item if we are not showing the delete menu
    // item, and the current folder is a draft folder and the account supports discarding
    // drafts for a conversation
    final boolean showDiscardDrafts =
        !showDelete
            && mFolder != null
            && mFolder.isDraft()
            && mAccount.supportsCapability(AccountCapabilities.DISCARD_CONVERSATION_DRAFTS);
    Utils.setMenuItemVisibility(menu, R.id.discard_drafts, showDiscardDrafts);
    final boolean archiveVisible =
        mAccount.supportsCapability(AccountCapabilities.ARCHIVE)
            && mFolder != null
            && mFolder.supportsCapability(FolderCapabilities.ARCHIVE)
            && !mFolder.isTrash();
    Utils.setMenuItemVisibility(menu, R.id.archive, archiveVisible);
    Utils.setMenuItemVisibility(
        menu,
        R.id.remove_folder,
        !archiveVisible
            && mFolder != null
            && mFolder.supportsCapability(FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES)
            && !mFolder.isProviderFolder()
            && mAccount.supportsCapability(AccountCapabilities.ARCHIVE));
    Utils.setMenuItemVisibility(
        menu,
        R.id.move_to,
        mFolder != null
            && mFolder.supportsCapability(FolderCapabilities.ALLOWS_REMOVE_CONVERSATION));
    Utils.setMenuItemVisibility(
        menu,
        R.id.move_to_inbox,
        mFolder != null && mFolder.supportsCapability(FolderCapabilities.ALLOWS_MOVE_TO_INBOX));

    final MenuItem removeFolder = menu.findItem(R.id.remove_folder);
    if (mFolder != null && removeFolder != null) {
      removeFolder.setTitle(
          mActivity.getApplicationContext().getString(R.string.remove_folder, mFolder.name));
    }
    Utils.setMenuItemVisibility(
        menu,
        R.id.report_spam,
        mAccount.supportsCapability(AccountCapabilities.REPORT_SPAM)
            && mFolder != null
            && mFolder.supportsCapability(FolderCapabilities.REPORT_SPAM)
            && !mCurrentConversation.spam);
    Utils.setMenuItemVisibility(
        menu,
        R.id.mark_not_spam,
        mAccount.supportsCapability(AccountCapabilities.REPORT_SPAM)
            && mFolder != null
            && mFolder.supportsCapability(FolderCapabilities.MARK_NOT_SPAM)
            && mCurrentConversation.spam);
    Utils.setMenuItemVisibility(
        menu,
        R.id.report_phishing,
        mAccount.supportsCapability(AccountCapabilities.REPORT_PHISHING)
            && mFolder != null
            && mFolder.supportsCapability(FolderCapabilities.REPORT_PHISHING)
            && !mCurrentConversation.phishing);
    Utils.setMenuItemVisibility(
        menu,
        R.id.mute,
        mAccount.supportsCapability(AccountCapabilities.MUTE)
            && mFolder != null
            && mFolder.supportsCapability(FolderCapabilities.DESTRUCTIVE_MUTE)
            && !mCurrentConversation.muted);
  }