| /* |
| * 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.Email; |
| 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.MailService; |
| import com.android.emailcommon.Logging; |
| import com.android.emailcommon.provider.Account; |
| import com.android.emailcommon.provider.HostAuth; |
| import com.android.emailcommon.provider.Policy; |
| import com.android.emailcommon.service.SyncWindow; |
| import com.android.emailcommon.utility.Utility; |
| |
| import java.io.IOException; |
| |
| /** |
| * TODO: Cleanup the manipulation of Account.FLAGS_INCOMPLETE and make sure it's never left set. |
| */ |
| 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; |
| |
| 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 Intent(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); |
| |
| // Generate spinner entries using XML arrays used by the preferences |
| int frequencyValuesId; |
| int frequencyEntriesId; |
| Account account = SetupData.getAccount(); |
| String protocol = account.mHostAuthRecv.mProtocol; |
| boolean eas = HostAuth.SCHEME_EAS.equals(protocol); |
| if (eas) { |
| frequencyValuesId = R.array.account_settings_check_frequency_values_push; |
| frequencyEntriesId = R.array.account_settings_check_frequency_entries_push; |
| } else { |
| frequencyValuesId = R.array.account_settings_check_frequency_values; |
| frequencyEntriesId = R.array.account_settings_check_frequency_entries; |
| } |
| CharSequence[] frequencyValues = getResources().getTextArray(frequencyValuesId); |
| CharSequence[] frequencyEntries = getResources().getTextArray(frequencyEntriesId); |
| |
| // Now create the array used by the 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<SpinnerOption> checkFrequenciesAdapter = new ArrayAdapter<SpinnerOption>(this, |
| android.R.layout.simple_spinner_item, checkFrequencies); |
| checkFrequenciesAdapter |
| .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
| mCheckFrequencyView.setAdapter(checkFrequenciesAdapter); |
| |
| if (eas) { |
| enableEASSyncWindowSpinner(); |
| } |
| |
| // 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()); |
| |
| // Setup any additional items to support EAS & EAS flow mode |
| if (eas) { |
| // "also sync contacts" == "true" |
| mSyncContactsView.setVisibility(View.VISIBLE); |
| mSyncContactsView.setChecked(true); |
| mSyncCalendarView.setVisibility(View.VISIBLE); |
| mSyncCalendarView.setChecked(true); |
| // Show the associated dividers |
| UiUtilities.setVisibilitySafe(this, R.id.account_sync_contacts_divider, View.VISIBLE); |
| UiUtilities.setVisibilitySafe(this, R.id.account_sync_calendar_divider, View.VISIBLE); |
| } |
| |
| // If we are in POP3, hide the "Background Attachments" mode |
| if (HostAuth.SCHEME_POP3.equals(protocol)) { |
| 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. |
| */ |
| 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; |
| boolean calendar = false; |
| boolean contacts = false; |
| boolean email = mSyncEmailView.isChecked(); |
| if (account.mHostAuthRecv.mProtocol.equals("eas")) { |
| if (SetupData.getPolicy() != null) { |
| account.mFlags |= Account.FLAGS_SECURITY_HOLD; |
| account.mPolicy = SetupData.getPolicy(); |
| } |
| // Get flags for contacts/calendar sync |
| contacts = mSyncContactsView.isChecked(); |
| calendar = mSyncCalendarView.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<Bundle> mAccountManagerCallback = new AccountManagerCallback<Bundle>() { |
| public void run(AccountManagerFuture<Bundle> future) { |
| try { |
| Bundle bundle = future.getResult(); |
| bundle.keySet(); |
| AccountSetupOptions.this.runOnUiThread(new Runnable() { |
| 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() { |
| 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() { |
| 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 |
| */ |
| 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) |
| Email.setServicesEnabledSync(context); |
| EmailServiceUtils.startExchangeService(context); |
| // Move to final setup screen |
| AccountSetupNames.actionSetNames(context); |
| finish(); |
| } |
| }); |
| } |
| |
| /** |
| * Enable an additional spinner using the arrays normally handled by preferences |
| */ |
| private void enableEASSyncWindowSpinner() { |
| // 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<SpinnerOption> windowOptionsAdapter = new ArrayAdapter<SpinnerOption>(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); |
| } |
| } |
| } |