/* * Copyright (C) 2012 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.mail.ui; import com.android.mail.R; import com.android.mail.analytics.Analytics; import com.android.mail.providers.Account; import com.android.mail.providers.MailAppProvider; import com.android.mail.providers.UIProvider; import com.android.mail.utils.LogTag; import java.util.ArrayList; import android.app.Fragment; import android.app.FragmentTransaction; import android.app.LoaderManager; import android.appwidget.AppWidgetManager; import android.content.ContentResolver; import android.content.CursorLoader; import android.content.Intent; import android.content.Loader; import android.database.Cursor; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.ActionBarActivity; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ListView; import android.widget.SimpleCursorAdapter; import android.widget.TextView; /** * An activity that shows the list of all the available accounts and return the * one selected in onResult(). */ public class MailboxSelectionActivity extends ActionBarActivity implements OnClickListener, LoaderManager.LoaderCallbacks, AdapterView.OnItemClickListener { // Used to save our instance state private static final String CREATE_SHORTCUT_KEY = "createShortcut"; private static final String CREATE_WIDGET_KEY = "createWidget"; private static final String WIDGET_ID_KEY = "widgetId"; private static final String WAITING_FOR_ADD_ACCOUNT_RESULT_KEY = "waitingForAddAccountResult"; private static final String ACCOUNT = "name"; private static final String[] COLUMN_NAMES = { ACCOUNT }; protected static final String LOG_TAG = LogTag.getLogTag(); private static final int RESULT_CREATE_ACCOUNT = 2; private static final int LOADER_ACCOUNT_CURSOR = 0; private static final String TAG_WAIT = "wait-fragment"; private final int[] VIEW_IDS = { R.id.mailbox_name }; private boolean mCreateShortcut = false; private boolean mConfigureWidget = false; private SimpleCursorAdapter mAdapter; private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; // Boolean to indicate that we are waiting for the result from an add account // operation. This boolean is necessary, as there is no guarantee on whether the // AccountManager callback or onResume will be called first. boolean mWaitingForAddAccountResult = false; // Can only do certain actions if the Activity is resumed (e.g. setVisible) private boolean mResumed = false; private Handler mHandler = new Handler(); private ListView mList; private View mContent; private View mWait; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.mailbox_selection_activity); mList = (ListView) findViewById(android.R.id.list); mList.setOnItemClickListener(this); mContent = findViewById(R.id.content); mWait = findViewById(R.id.wait); if (icicle != null) { restoreState(icicle); } else { if (Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction())) { mCreateShortcut = true; } mAppWidgetId = getIntent().getIntExtra( AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); if (mAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { mConfigureWidget = true; } } // We set the default title to "Gmail" or "Google Mail" for consistency // in Task Switcher. If this is for create shortcut or configure widget, // we should set the title to "Select account". if (mCreateShortcut || mConfigureWidget) { setTitle(getResources().getString(R.string.activity_mailbox_selection)); } findViewById(R.id.first_button).setOnClickListener(this); // Initially, assume that the main view is invisible. It will be made visible, // if we display the account list setVisible(false); setResult(RESULT_CANCELED); } @Override protected void onSaveInstanceState(Bundle icicle) { super.onSaveInstanceState(icicle); icicle.putBoolean(CREATE_SHORTCUT_KEY, mCreateShortcut); icicle.putBoolean(CREATE_WIDGET_KEY, mConfigureWidget); if (mAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { icicle.putInt(WIDGET_ID_KEY, mAppWidgetId); } icicle.putBoolean(WAITING_FOR_ADD_ACCOUNT_RESULT_KEY, mWaitingForAddAccountResult); } @Override public void onStart() { super.onStart(); Analytics.getInstance().activityStart(this); } @Override protected void onStop() { super.onStop(); Analytics.getInstance().activityStop(this); } @Override public void onResume() { super.onResume(); mResumed = true; // Only fetch the accounts, if we are not handling a response from the // launched child activity. if (!mWaitingForAddAccountResult) { setupWithAccounts(); } } @Override public void onPause() { super.onPause(); mResumed = false; } @Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); } /** * Restores the activity state from a bundle */ private void restoreState(Bundle icicle) { if (icicle.containsKey(CREATE_SHORTCUT_KEY)) { mCreateShortcut = icicle.getBoolean(CREATE_SHORTCUT_KEY); } if (icicle.containsKey(CREATE_WIDGET_KEY)) { mConfigureWidget = icicle.getBoolean(CREATE_WIDGET_KEY); } if (icicle.containsKey(WIDGET_ID_KEY)) { mAppWidgetId = icicle.getInt(WIDGET_ID_KEY); } if (icicle.containsKey(WAITING_FOR_ADD_ACCOUNT_RESULT_KEY)) { mWaitingForAddAccountResult = icicle.getBoolean(WAITING_FOR_ADD_ACCOUNT_RESULT_KEY); } } private void setupWithAccounts() { final ContentResolver resolver = getContentResolver(); new AsyncTask() { @Override protected Void doInBackground(Void... params) { Cursor cursor = null; try { cursor = resolver.query(MailAppProvider.getAccountsUri(), UIProvider.ACCOUNTS_PROJECTION, null, null, null); completeSetupWithAccounts(cursor); } finally { if (cursor != null) { cursor.close(); } } return null; } }.execute(); } private void completeSetupWithAccounts(final Cursor accounts) { mHandler.post(new Runnable() { @Override public void run() { updateAccountList(accounts); } }); } private void updateAccountList(final Cursor accounts) { boolean displayAccountList = true; // Configuring a widget or shortcut. if (mConfigureWidget || mCreateShortcut) { if (accounts == null || accounts.getCount() == 0) { // No account found, show Add Account screen, for both the widget or // shortcut creation process // No account found, show Add Account screen, for both the widget or // shortcut creation process final Intent noAccountIntent = MailAppProvider.getNoAccountIntent(this); if (noAccountIntent != null) { startActivityForResult(noAccountIntent, RESULT_CREATE_ACCOUNT); } // No reason to display the account list displayAccountList = false; // Indicate that we need to handle the response from the add account action // This allows us to process the results that we get in the AddAccountCallback mWaitingForAddAccountResult = true; } else if (mConfigureWidget && accounts.getCount() == 1) { mWait.setVisibility(View.GONE); // When configuring a widget, if there is only one account, automatically // choose that account. accounts.moveToFirst(); selectAccount(Account.builder().buildFrom(accounts)); // No reason to display the account list displayAccountList = false; } } if (displayAccountList) { mContent.setVisibility(View.VISIBLE); // We are about to display the list, make this activity visible // But only if the Activity is not paused! if (mResumed) { setVisible(true); } mAdapter = new SimpleCursorAdapter(this, R.layout.mailbox_item, accounts, COLUMN_NAMES, VIEW_IDS, 0) { @Override public View getView(int position, View convertView, ViewGroup parent) { View v = super.getView(position, convertView, parent); TextView accountView = (TextView) v.findViewById(R.id.mailbox_name); final Account account = Account.builder().buildFrom((Cursor) getItem(position)); accountView.setText(account.getDisplayName()); return v; } }; mList.setAdapter(mAdapter); } } @Override public void onItemClick(AdapterView parent, View view, int position, long id) { selectAccount(Account.builder().buildFrom((Cursor) mAdapter.getItem(position))); } private void selectAccount(Account account) { if (mCreateShortcut || mConfigureWidget) { // Invoked for a shortcut creation final Intent intent = new Intent(this, getFolderSelectionActivity()); intent.setFlags( Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_FORWARD_RESULT); intent.setAction(mCreateShortcut ? Intent.ACTION_CREATE_SHORTCUT : AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); if (mConfigureWidget) { intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); } intent.putExtra(FolderSelectionActivity.EXTRA_ACCOUNT_SHORTCUT, account); startActivity(intent); finish(); } else { // TODO: (mindyp) handle changing the account for this shortcut. finish(); } } /** * Return the class responsible for launching the folder selection activity. */ protected Class getFolderSelectionActivity() { return FolderSelectionActivity.class; } @Override public void onClick(View v) { final int id = v.getId(); if (id == R.id.first_button) { setResult(RESULT_CANCELED); finish(); } } @Override protected final void onActivityResult(int request, int result, Intent data) { if (request == RESULT_CREATE_ACCOUNT) { // We were waiting for the user to create an account if (result != RESULT_OK) { finish(); } else { // Watch for accounts to show up! // restart the loader to get the updated list of accounts getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this); showWaitFragment(null); } } } private void showWaitFragment(Account account) { WaitFragment fragment = getWaitFragment(); if (fragment != null) { fragment.updateAccount(account); } else { mWait.setVisibility(View.VISIBLE); replaceFragment(WaitFragment.newInstance(account, false /* expectingMessages */), FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT); } mContent.setVisibility(View.GONE); } @Override public Loader onCreateLoader(int id, Bundle args) { switch (id) { case LOADER_ACCOUNT_CURSOR: return new CursorLoader(this, MailAppProvider.getAccountsUri(), UIProvider.ACCOUNTS_PROJECTION, null, null, null); } return null; } private WaitFragment getWaitFragment() { return (WaitFragment) getFragmentManager().findFragmentByTag(TAG_WAIT); } private int replaceFragment(Fragment fragment, int transition, String tag) { FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); fragmentTransaction.setTransition(transition); fragmentTransaction.replace(R.id.wait, fragment, tag); final int transactionId = fragmentTransaction.commitAllowingStateLoss(); return transactionId; } @Override public void onLoaderReset(Loader arg0) { // Do nothing. } @Override public void onLoadFinished(Loader cursor, Cursor data) { if (data != null && data.moveToFirst()) { // there are accounts now! Account account; ArrayList accounts = new ArrayList(); ArrayList initializedAccounts = new ArrayList(); do { account = Account.builder().buildFrom(data); if (account.isAccountReady()) { initializedAccounts.add(account); } accounts.add(account); } while (data.moveToNext()); if (initializedAccounts.size() > 0) { mWait.setVisibility(View.GONE); getLoaderManager().destroyLoader(LOADER_ACCOUNT_CURSOR); mContent.setVisibility(View.VISIBLE); updateAccountList(data); } else { // Show "waiting" account = accounts.size() > 0 ? accounts.get(0) : null; showWaitFragment(account); } } } @Override public void onBackPressed() { mWaitingForAddAccountResult = false; // If we are showing the wait fragment, just exit. if (getWaitFragment() != null) { finish(); } else { super.onBackPressed(); } } }