replicant-packages_apps_Email/src/com/android/email/activity/UIControllerBase.java

416 lines
13 KiB
Java

/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.email.activity;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.RefreshManager;
import com.android.email.activity.setup.AccountSettingsXL;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.utility.EmailAsyncTask;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import java.util.ArrayList;
/**
* Base class for the UI controller.
*
* Note: Always use {@link #commitFragmentTransaction} and {@link #popBackStack} to operate fragment
* transactions.
* (Currently we use synchronous transactions only, but we may want to switch back to asynchronous
* later.)
*/
abstract class UIControllerBase {
protected static final String BUNDLE_KEY_ACCOUNT_ID = "UIController.state.account_id";
protected static final String BUNDLE_KEY_MAILBOX_ID = "UIController.state.mailbox_id";
protected static final String BUNDLE_KEY_MESSAGE_ID = "UIController.state.message_id";
/** No account selected */
static final long NO_ACCOUNT = -1;
/** No mailbox selected */
static final long NO_MAILBOX = -1;
/** No message selected */
static final long NO_MESSAGE = -1;
/** The owner activity */
final EmailActivity mActivity;
final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker();
final RefreshManager mRefreshManager;
/**
* List of fragments that are restored by the framework while the activity is being re-created
* for configuration changes (e.g. screen rotation). We'll install them later when the activity
* is created in {@link #installRestoredFragments()}.
*/
private final ArrayList<Fragment> mRestoredFragments = new ArrayList<Fragment>();
/**
* Whether fragment installation should be hold.
* We hold installing fragments until {@link #installRestoredFragments()} is called.
*/
private boolean mHoldFragmentInstallation = true;
private final RefreshManager.Listener mRefreshListener
= new RefreshManager.Listener() {
@Override
public void onMessagingError(final long accountId, long mailboxId, final String message) {
updateRefreshProgress();
}
@Override
public void onRefreshStatusChanged(long accountId, long mailboxId) {
updateRefreshProgress();
}
};
public UIControllerBase(EmailActivity activity) {
mActivity = activity;
mRefreshManager = RefreshManager.getInstance(mActivity);
}
/** @return the layout ID for the activity. */
public abstract int getLayoutId();
/**
* @return true if the UI controller currently can install fragments.
*/
boolean isFragmentInstallable() {
return !mHoldFragmentInstallation;
}
/**
* Must be called just after the activity sets up the content view. Used to initialize views.
*
* (Due to the complexity regarding class/activity initialization order, we can't do this in
* the constructor.)
*/
public void onActivityViewReady() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " onActivityViewReady");
}
}
/**
* Called at the end of {@link EmailActivity#onCreate}.
*/
public void onActivityCreated() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " onActivityCreated");
}
mRefreshManager.registerListener(mRefreshListener);
}
/**
* Handles the {@link android.app.Activity#onStart} callback.
*/
public void onActivityStart() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " onActivityStart");
}
}
/**
* Handles the {@link android.app.Activity#onResume} callback.
*/
public void onActivityResume() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " onActivityResume");
}
}
/**
* Handles the {@link android.app.Activity#onPause} callback.
*/
public void onActivityPause() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " onActivityPause");
}
}
/**
* Handles the {@link android.app.Activity#onStop} callback.
*/
public void onActivityStop() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " onActivityStop");
}
}
/**
* Handles the {@link android.app.Activity#onDestroy} callback.
*/
public void onActivityDestroy() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " onActivityDestroy");
}
mHoldFragmentInstallation = true; // No more fragment installation.
mRefreshManager.unregisterListener(mRefreshListener);
mTaskTracker.cancellAllInterrupt();
}
/**
* Install all the fragments kept in {@link #mRestoredFragments}.
*
* Must be called at the end of {@link EmailActivity#onCreate}.
*/
public final void installRestoredFragments() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " installRestoredFragments");
}
mHoldFragmentInstallation = false;
// Install all the fragments restored by the framework.
for (Fragment fragment : mRestoredFragments) {
installFragment(fragment);
}
mRestoredFragments.clear();
}
/**
* Handles the {@link android.app.Activity#onSaveInstanceState} callback.
*/
public void onSaveInstanceState(Bundle outState) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " onSaveInstanceState");
}
}
/**
* Handles the {@link android.app.Activity#onRestoreInstanceState} callback.
*/
public void restoreInstanceState(Bundle savedInstanceState) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " restoreInstanceState");
}
}
/**
* Handles the {@link android.app.Activity#onAttachFragment} callback.
*
* If the activity has already been created, we initialize the fragment here. Otherwise we
* keep the fragment in {@link #mRestoredFragments} and initialize it after the activity's
* onCreate.
*/
public final void onAttachFragment(Fragment fragment) {
if (mHoldFragmentInstallation) {
// Fragment being restored by the framework during the activity recreation.
mRestoredFragments.add(fragment);
return;
}
installFragment(fragment);
}
void installFragment(Fragment fragment) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " installFragment fragment=" + fragment);
}
}
// not used
void popBackStack(FragmentManager fm, String name, int flags) {
fm.popBackStackImmediate(name, flags);
}
void commitFragmentTransaction(FragmentTransaction ft) {
ft.commit();
mActivity.getFragmentManager().executePendingTransactions();
}
/**
* @return the currently selected account ID, *or* {@link Account#ACCOUNT_ID_COMBINED_VIEW}.
*
* @see #getActualAccountId()
*/
public abstract long getUIAccountId();
/**
* @return true if an account is selected, or the current view is the combined view.
*/
public final boolean isAccountSelected() {
return getUIAccountId() != NO_ACCOUNT;
}
/**
* @return if an actual account is selected. (i.e. {@link Account#ACCOUNT_ID_COMBINED_VIEW}
* is not considered "actual".s)
*/
public final boolean isActualAccountSelected() {
return isAccountSelected() && (getUIAccountId() != Account.ACCOUNT_ID_COMBINED_VIEW);
}
/**
* @return the currently selected account ID. If the current view is the combined view,
* it'll return {@link #NO_ACCOUNT}.
*
* @see #getUIAccountId()
*/
public final long getActualAccountId() {
return isActualAccountSelected() ? getUIAccountId() : NO_ACCOUNT;
}
/**
* Show the default view for the given account.
*
* @param accountId ID of the account to load. Can be {@link Account#ACCOUNT_ID_COMBINED_VIEW}.
* Must never be {@link #NO_ACCOUNT}.
*/
public abstract void openAccount(long accountId);
/**
* Loads the given account and optionally selects the given mailbox and message. Used to open
* a particular view at a request from outside of the activity, such as the widget.
*
* @param accountId ID of the account to load. Can be {@link Account#ACCOUNT_ID_COMBINED_VIEW}.
* Must never be {@link #NO_ACCOUNT}.
* @param mailboxId ID of the mailbox to load. If {@link #NO_MAILBOX}, load the account's inbox.
* @param messageId ID of the message to load. If {@link #NO_MESSAGE}, do not open a message.
*/
public abstract void open(long accountId, long mailboxId, long messageId);
/**
* Performs the back action.
*
* @param isSystemBackKey <code>true</code> if the system back key was pressed.
* <code>false</code> if it's caused by the "home" icon click on the action bar.
*/
public abstract boolean onBackPressed(boolean isSystemBackKey);
/**
* Handles the {@link android.app.Activity#onCreateOptionsMenu} callback.
*/
public boolean onCreateOptionsMenu(MenuInflater inflater, Menu menu) {
inflater.inflate(R.menu.email_activity_options, menu);
return true;
}
/**
* Handles the {@link android.app.Activity#onPrepareOptionsMenu} callback.
*/
public boolean onPrepareOptionsMenu(MenuInflater inflater, Menu menu) {
// Update the refresh button.
MenuItem item = menu.findItem(R.id.refresh);
if (isRefreshEnabled()) {
item.setVisible(true);
if (isRefreshInProgress()) {
item.setActionView(R.layout.action_bar_indeterminate_progress);
} else {
item.setActionView(null);
}
} else {
item.setVisible(false);
}
return true;
}
/**
* Handles the {@link android.app.Activity#onOptionsItemSelected} callback.
*
* @return true if the option item is handled.
*/
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// Comes from the action bar when the app icon on the left is pressed.
// It works like a back press, but it won't close the activity.
return onBackPressed(false);
case R.id.compose:
return onCompose();
case R.id.refresh:
onRefresh();
return true;
case R.id.account_settings:
return onAccountSettings();
}
return false;
}
/**
* Opens the message compose activity.
*/
private boolean onCompose() {
if (!isAccountSelected()) {
return false; // this shouldn't really happen
}
MessageCompose.actionCompose(mActivity, getActualAccountId());
return true;
}
/**
* Handles the "Settings" option item. Opens the settings activity.
*/
private boolean onAccountSettings() {
AccountSettingsXL.actionSettings(mActivity, getActualAccountId());
return true;
}
/**
* STOPSHIP For experimental UI. Remove this.
*
* @return mailbox ID which we search for messages.
*/
public abstract long getSearchMailboxId();
/**
* STOPSHIP For experimental UI. Remove this.
*
* @return mailbox ID for "mailbox settings" option.
*/
public abstract long getMailboxSettingsMailboxId();
/**
* STOPSHIP For experimental UI. Make it abstract protected.
*
* Performs "refesh".
*/
public abstract void onRefresh();
/**
* @return true if refresh is in progress for the current mailbox.
*/
protected abstract boolean isRefreshInProgress();
/**
* @return true if the UI should enable the "refresh" command.
*/
protected abstract boolean isRefreshEnabled();
/**
* Start/stop the "refresh" animation on the action bar according to the current refresh state.
*
* (We start the animation if {@link #isRefreshInProgress} returns true,
* and stop otherwise.)
*/
protected void updateRefreshProgress() {
mActivity.invalidateOptionsMenu();
}
}