/* * Copyright (C) 2008 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.setup; import android.accounts.AccountAuthenticatorResponse; import android.accounts.AccountManager; import android.accounts.AccountManagerCallback; import android.accounts.AccountManagerFuture; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.Spinner; import com.android.email.R; import com.android.email.activity.ActivityHelper; import com.android.email.activity.UiUtilities; import com.android.email.service.EmailServiceUtils; import com.android.email.service.EmailServiceUtils.EmailServiceInfo; import com.android.email.service.MailService; import com.android.email2.ui.MailActivityEmail; import com.android.emailcommon.Logging; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.Policy; import com.android.emailcommon.service.SyncWindow; import com.android.emailcommon.utility.Utility; import java.io.IOException; public class AccountSetupOptions extends AccountSetupActivity implements OnClickListener { private Spinner mCheckFrequencyView; private Spinner mSyncWindowView; private CheckBox mDefaultView; private CheckBox mNotifyView; private CheckBox mSyncContactsView; private CheckBox mSyncCalendarView; private CheckBox mSyncEmailView; private CheckBox mBackgroundAttachmentsView; private View mAccountSyncWindowRow; private boolean mDonePressed = false; private EmailServiceInfo mServiceInfo; public static final int REQUEST_CODE_ACCEPT_POLICIES = 1; /** Default sync window for new EAS accounts */ private static final int SYNC_WINDOW_EAS_DEFAULT = SyncWindow.SYNC_WINDOW_AUTO; public static void actionOptions(Activity fromActivity) { fromActivity.startActivity(new ForwardingIntent(fromActivity, AccountSetupOptions.class)); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityHelper.debugSetWindowFlags(this); setContentView(R.layout.account_setup_options); mCheckFrequencyView = (Spinner) UiUtilities.getView(this, R.id.account_check_frequency); mSyncWindowView = (Spinner) UiUtilities.getView(this, R.id.account_sync_window); mDefaultView = (CheckBox) UiUtilities.getView(this, R.id.account_default); mNotifyView = (CheckBox) UiUtilities.getView(this, R.id.account_notify); mSyncContactsView = (CheckBox) UiUtilities.getView(this, R.id.account_sync_contacts); mSyncCalendarView = (CheckBox) UiUtilities.getView(this, R.id.account_sync_calendar); mSyncEmailView = (CheckBox) UiUtilities.getView(this, R.id.account_sync_email); mSyncEmailView.setChecked(true); mBackgroundAttachmentsView = (CheckBox) UiUtilities.getView(this, R.id.account_background_attachments); mBackgroundAttachmentsView.setChecked(true); UiUtilities.getView(this, R.id.previous).setOnClickListener(this); UiUtilities.getView(this, R.id.next).setOnClickListener(this); mAccountSyncWindowRow = UiUtilities.getView(this, R.id.account_sync_window_row); Account account = SetupData.getAccount(); mServiceInfo = EmailServiceUtils.getServiceInfo(getApplicationContext(), account.mHostAuthRecv.mProtocol); CharSequence[] frequencyValues = mServiceInfo.syncIntervals; CharSequence[] frequencyEntries = mServiceInfo.syncIntervalStrings; // Now create the array used by the sync interval Spinner SpinnerOption[] checkFrequencies = new SpinnerOption[frequencyEntries.length]; for (int i = 0; i < frequencyEntries.length; i++) { checkFrequencies[i] = new SpinnerOption( Integer.valueOf(frequencyValues[i].toString()), frequencyEntries[i].toString()); } ArrayAdapter checkFrequenciesAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, checkFrequencies); checkFrequenciesAdapter .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mCheckFrequencyView.setAdapter(checkFrequenciesAdapter); if (mServiceInfo.offerLookback) { enableLookbackSpinner(); } // Note: It is OK to use mAccount.mIsDefault here *only* because the account // has not been written to the DB yet. Ordinarily, call Account.getDefaultAccountId(). if (account.mIsDefault || SetupData.isDefault()) { mDefaultView.setChecked(true); } mNotifyView.setChecked( (account.getFlags() & Account.FLAGS_NOTIFY_NEW_MAIL) != 0); SpinnerOption.setSpinnerOptionValue(mCheckFrequencyView, account.getSyncInterval()); if (mServiceInfo.syncContacts) { mSyncContactsView.setVisibility(View.VISIBLE); mSyncContactsView.setChecked(true); UiUtilities.setVisibilitySafe(this, R.id.account_sync_contacts_divider, View.VISIBLE); } if (mServiceInfo.syncCalendar) { mSyncCalendarView.setVisibility(View.VISIBLE); mSyncCalendarView.setChecked(true); UiUtilities.setVisibilitySafe(this, R.id.account_sync_calendar_divider, View.VISIBLE); } if (!mServiceInfo.offerAttachmentPreload) { mBackgroundAttachmentsView.setVisibility(View.GONE); UiUtilities.setVisibilitySafe(this, R.id.account_background_attachments_divider, View.GONE); } // If we are just visiting here to fill in details, exit immediately if (SetupData.isAutoSetup() || SetupData.getFlowMode() == SetupData.FLOW_MODE_FORCE_CREATE) { onDone(); } } @Override public void finish() { // If the account manager initiated the creation, and success was not reported, // then we assume that we're giving up (for any reason) - report failure. AccountAuthenticatorResponse authenticatorResponse = SetupData.getAccountAuthenticatorResponse(); if (authenticatorResponse != null) { authenticatorResponse.onError(AccountManager.ERROR_CODE_CANCELED, "canceled"); SetupData.setAccountAuthenticatorResponse(null); } super.finish(); } /** * Respond to clicks in the "Next" or "Previous" buttons */ @Override public void onClick(View view) { switch (view.getId()) { case R.id.next: // Don't allow this more than once (Exchange accounts call an async method // before finish()'ing the Activity, which allows this code to potentially be // executed multiple times if (!mDonePressed) { onDone(); mDonePressed = true; } break; case R.id.previous: onBackPressed(); break; } } /** * Ths is called when the user clicks the "done" button. * It collects the data from the UI, updates the setup account record, and commits * the account to the database (making it real for the first time.) * Finally, we call setupAccountManagerAccount(), which will eventually complete via callback. */ @SuppressWarnings("deprecation") private void onDone() { final Account account = SetupData.getAccount(); if (account.isSaved()) { // Disrupting the normal flow could get us here, but if the account is already // saved, we've done this work return; } account.setDisplayName(account.getEmailAddress()); int newFlags = account.getFlags() & ~(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_BACKGROUND_ATTACHMENTS); if (mNotifyView.isChecked()) { newFlags |= Account.FLAGS_NOTIFY_NEW_MAIL; } if (mBackgroundAttachmentsView.isChecked()) { newFlags |= Account.FLAGS_BACKGROUND_ATTACHMENTS; } account.setFlags(newFlags); account.setSyncInterval((Integer)((SpinnerOption)mCheckFrequencyView .getSelectedItem()).value); if (mAccountSyncWindowRow.getVisibility() == View.VISIBLE) { int window = (Integer)((SpinnerOption)mSyncWindowView.getSelectedItem()).value; account.setSyncLookback(window); } account.setDefaultAccount(mDefaultView.isChecked()); if (account.mHostAuthRecv == null) { throw new IllegalStateException("in AccountSetupOptions with null mHostAuthRecv"); } // Finish setting up the account, and commit it to the database // Set the incomplete flag here to avoid reconciliation issues in ExchangeService account.mFlags |= Account.FLAGS_INCOMPLETE; if (SetupData.getPolicy() != null) { account.mFlags |= Account.FLAGS_SECURITY_HOLD; account.mPolicy = SetupData.getPolicy(); } boolean contacts = false; if (mServiceInfo.syncContacts) { contacts = mSyncContactsView.isChecked(); } boolean calendar = false; if (mServiceInfo.syncCalendar) { calendar = mSyncCalendarView.isChecked(); } boolean email = mSyncEmailView.isChecked(); // Finally, write the completed account (for the first time) and then // install it into the Account manager as well. These are done off-thread. // The account manager will report back via the callback, which will take us to // the next operations. final boolean email2 = email; final boolean calendar2 = calendar; final boolean contacts2 = contacts; Utility.runAsync(new Runnable() { @Override public void run() { Context context = AccountSetupOptions.this; AccountSettingsUtils.commitSettings(context, account); MailService.setupAccountManagerAccount(context, account, email2, calendar2, contacts2, mAccountManagerCallback); } }); } /** * This is called at the completion of MailService.setupAccountManagerAccount() */ AccountManagerCallback mAccountManagerCallback = new AccountManagerCallback() { @Override public void run(AccountManagerFuture future) { try { Bundle bundle = future.getResult(); bundle.keySet(); AccountSetupOptions.this.runOnUiThread(new Runnable() { @Override public void run() { optionsComplete(); } }); return; } catch (OperationCanceledException e) { Log.d(Logging.LOG_TAG, "addAccount was canceled"); } catch (IOException e) { Log.d(Logging.LOG_TAG, "addAccount failed: " + e); } catch (AuthenticatorException e) { Log.d(Logging.LOG_TAG, "addAccount failed: " + e); } showErrorDialog(R.string.account_setup_failed_dlg_auth_message, R.string.system_account_create_failed); } }; /** * This is called if MailService.setupAccountManagerAccount() fails for some reason */ private void showErrorDialog(final int msgResId, final Object... args) { runOnUiThread(new Runnable() { @Override public void run() { new AlertDialog.Builder(AccountSetupOptions.this) .setIconAttribute(android.R.attr.alertDialogIcon) .setTitle(getString(R.string.account_setup_failed_dlg_title)) .setMessage(getString(msgResId, args)) .setCancelable(true) .setPositiveButton( getString(R.string.account_setup_failed_dlg_edit_details_action), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }) .show(); } }); } /** * This is called after the account manager creates the new account. */ private void optionsComplete() { // If the account manager initiated the creation, report success at this point AccountAuthenticatorResponse authenticatorResponse = SetupData.getAccountAuthenticatorResponse(); if (authenticatorResponse != null) { authenticatorResponse.onResult(null); SetupData.setAccountAuthenticatorResponse(null); } // Now that AccountManager account creation is complete, clear the INCOMPLETE flag Account account = SetupData.getAccount(); account.mFlags &= ~Account.FLAGS_INCOMPLETE; AccountSettingsUtils.commitSettings(AccountSetupOptions.this, account); // If we've got policies for this account, ask the user to accept. if ((account.mFlags & Account.FLAGS_SECURITY_HOLD) != 0) { Intent intent = AccountSecurity.actionUpdateSecurityIntent(this, account.mId, false); startActivityForResult(intent, AccountSetupOptions.REQUEST_CODE_ACCEPT_POLICIES); return; } saveAccountAndFinish(); } /** * This is called after the AccountSecurity activity completes. */ @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { saveAccountAndFinish(); } /** * These are the final cleanup steps when creating an account: * Clear incomplete & security hold flags * Update account in DB * Enable email services * Enable exchange services * Move to final setup screen */ @SuppressWarnings("deprecation") private void saveAccountAndFinish() { Utility.runAsync(new Runnable() { @Override public void run() { AccountSetupOptions context = AccountSetupOptions.this; // Clear the security hold flag now Account account = SetupData.getAccount(); account.mFlags &= ~Account.FLAGS_SECURITY_HOLD; AccountSettingsUtils.commitSettings(context, account); // Start up services based on new account(s) MailActivityEmail.setServicesEnabledSync(context); EmailServiceUtils.startService(context, account.mHostAuthRecv.mProtocol); // Move to final setup screen AccountSetupNames.actionSetNames(context); finish(); } }); } /** * Enable an additional spinner using the arrays normally handled by preferences */ private void enableLookbackSpinner() { // Show everything mAccountSyncWindowRow.setVisibility(View.VISIBLE); // Generate spinner entries using XML arrays used by the preferences CharSequence[] windowValues = getResources().getTextArray( R.array.account_settings_mail_window_values); CharSequence[] windowEntries = getResources().getTextArray( R.array.account_settings_mail_window_entries); // Find a proper maximum for email lookback, based on policy (if we have one) int maxEntry = windowEntries.length; Policy policy = SetupData.getAccount().mPolicy; if (policy != null) { int maxLookback = policy.mMaxEmailLookback; if (maxLookback != 0) { // Offset/Code 0 1 2 3 4 5 // Entries auto, 1 day, 3 day, 1 week, 2 week, 1 month // Lookback N/A 1 day, 3 day, 1 week, 2 week, 1 month // Since our test below is i < maxEntry, we must set maxEntry to maxLookback + 1 maxEntry = maxLookback + 1; } } // Now create the array used by the Spinner SpinnerOption[] windowOptions = new SpinnerOption[maxEntry]; int defaultIndex = -1; for (int i = 0; i < maxEntry; i++) { final int value = Integer.valueOf(windowValues[i].toString()); windowOptions[i] = new SpinnerOption(value, windowEntries[i].toString()); if (value == SYNC_WINDOW_EAS_DEFAULT) { defaultIndex = i; } } ArrayAdapter windowOptionsAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, windowOptions); windowOptionsAdapter .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mSyncWindowView.setAdapter(windowOptionsAdapter); SpinnerOption.setSpinnerOptionValue(mSyncWindowView, SetupData.getAccount().getSyncLookback()); if (defaultIndex >= 0) { mSyncWindowView.setSelection(defaultIndex); } } }