AccountSetupOptions.java revision d6d874f8c6ce2580ef9ec2406fe411af45b2d92d
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.email.activity.setup;
18
19import com.android.email.Email;
20import com.android.email.ExchangeUtils;
21import com.android.email.R;
22import com.android.email.SecurityPolicy.PolicySet;
23import com.android.email.mail.Store;
24import com.android.email.mail.store.ExchangeStore;
25import com.android.email.provider.EmailContent;
26import com.android.email.provider.EmailContent.Account;
27
28import android.accounts.AccountManagerCallback;
29import android.accounts.AccountManagerFuture;
30import android.accounts.AuthenticatorException;
31import android.accounts.OperationCanceledException;
32import android.app.Activity;
33import android.app.AlertDialog;
34import android.content.DialogInterface;
35import android.content.Intent;
36import android.os.Bundle;
37import android.os.Handler;
38import android.util.Log;
39import android.view.View;
40import android.view.View.OnClickListener;
41import android.widget.ArrayAdapter;
42import android.widget.CheckBox;
43import android.widget.Spinner;
44
45import java.io.IOException;
46
47public class AccountSetupOptions extends Activity implements OnClickListener {
48
49    private static final String EXTRA_ACCOUNT = "account";
50    private static final String EXTRA_MAKE_DEFAULT = "makeDefault";
51    private static final String EXTRA_EAS_FLOW = "easFlow";
52    private static final String EXTRA_POLICY_SET = "policySet";
53
54    private Spinner mCheckFrequencyView;
55    private Spinner mSyncWindowView;
56    private CheckBox mDefaultView;
57    private CheckBox mNotifyView;
58    private CheckBox mSyncContactsView;
59    private CheckBox mSyncCalendarView;
60    private EmailContent.Account mAccount;
61    private boolean mEasFlowMode;
62    private Handler mHandler = new Handler();
63    private boolean mDonePressed = false;
64    private PolicySet mPolicySet;
65
66    public static final int REQUEST_CODE_ACCEPT_POLICIES = 1;
67
68    /** Default sync window for new EAS accounts */
69    private static final int SYNC_WINDOW_EAS_DEFAULT = com.android.email.Account.SYNC_WINDOW_3_DAYS;
70
71    public static void actionOptions(Activity fromActivity, EmailContent.Account account,
72            boolean makeDefault, boolean easFlowMode, PolicySet policySet) {
73        Intent i = new Intent(fromActivity, AccountSetupOptions.class);
74        i.putExtra(EXTRA_ACCOUNT, account);
75        i.putExtra(EXTRA_MAKE_DEFAULT, makeDefault);
76        i.putExtra(EXTRA_EAS_FLOW, easFlowMode);
77        if (policySet != null) {
78            i.putExtra(EXTRA_POLICY_SET, policySet);
79        }
80        fromActivity.startActivity(i);
81    }
82
83    @Override
84    public void onCreate(Bundle savedInstanceState) {
85        super.onCreate(savedInstanceState);
86        setContentView(R.layout.account_setup_options);
87
88        mCheckFrequencyView = (Spinner)findViewById(R.id.account_check_frequency);
89        mSyncWindowView = (Spinner) findViewById(R.id.account_sync_window);
90        mDefaultView = (CheckBox)findViewById(R.id.account_default);
91        mNotifyView = (CheckBox)findViewById(R.id.account_notify);
92        mSyncContactsView = (CheckBox) findViewById(R.id.account_sync_contacts);
93        mSyncCalendarView = (CheckBox) findViewById(R.id.account_sync_calendar);
94
95        findViewById(R.id.next).setOnClickListener(this);
96
97        mAccount = (EmailContent.Account) getIntent().getParcelableExtra(EXTRA_ACCOUNT);
98        boolean makeDefault = getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false);
99        mPolicySet = (PolicySet) getIntent().getParcelableExtra(EXTRA_POLICY_SET);
100
101        // Generate spinner entries using XML arrays used by the preferences
102        int frequencyValuesId;
103        int frequencyEntriesId;
104        Store.StoreInfo info = Store.StoreInfo.getStoreInfo(mAccount.getStoreUri(this), this);
105        if (info.mPushSupported) {
106            frequencyValuesId = R.array.account_settings_check_frequency_values_push;
107            frequencyEntriesId = R.array.account_settings_check_frequency_entries_push;
108        } else {
109            frequencyValuesId = R.array.account_settings_check_frequency_values;
110            frequencyEntriesId = R.array.account_settings_check_frequency_entries;
111        }
112        CharSequence[] frequencyValues = getResources().getTextArray(frequencyValuesId);
113        CharSequence[] frequencyEntries = getResources().getTextArray(frequencyEntriesId);
114
115        // Now create the array used by the Spinner
116        SpinnerOption[] checkFrequencies = new SpinnerOption[frequencyEntries.length];
117        for (int i = 0; i < frequencyEntries.length; i++) {
118            checkFrequencies[i] = new SpinnerOption(
119                    Integer.valueOf(frequencyValues[i].toString()), frequencyEntries[i].toString());
120        }
121
122        ArrayAdapter<SpinnerOption> checkFrequenciesAdapter = new ArrayAdapter<SpinnerOption>(this,
123                android.R.layout.simple_spinner_item, checkFrequencies);
124        checkFrequenciesAdapter
125                .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
126        mCheckFrequencyView.setAdapter(checkFrequenciesAdapter);
127
128        if (info.mVisibleLimitDefault == -1) {
129            enableEASSyncWindowSpinner();
130        }
131
132        // Note:  It is OK to use mAccount.mIsDefault here *only* because the account
133        // has not been written to the DB yet.  Ordinarily, call Account.getDefaultAccountId().
134        if (mAccount.mIsDefault || makeDefault) {
135            mDefaultView.setChecked(true);
136        }
137        mNotifyView.setChecked(
138                (mAccount.getFlags() & EmailContent.Account.FLAGS_NOTIFY_NEW_MAIL) != 0);
139        SpinnerOption.setSpinnerOptionValue(mCheckFrequencyView, mAccount
140                .getSyncInterval());
141
142        // Setup any additional items to support EAS & EAS flow mode
143        mEasFlowMode = getIntent().getBooleanExtra(EXTRA_EAS_FLOW, false);
144        if ("eas".equals(info.mScheme)) {
145            // "also sync contacts" == "true"
146            mSyncContactsView.setVisibility(View.VISIBLE);
147            mSyncContactsView.setChecked(true);
148            mSyncCalendarView.setVisibility(View.VISIBLE);
149            mSyncCalendarView.setChecked(true);
150        }
151    }
152
153    AccountManagerCallback<Bundle> mAccountManagerCallback = new AccountManagerCallback<Bundle>() {
154        public void run(AccountManagerFuture<Bundle> future) {
155            try {
156                Bundle bundle = future.getResult();
157                bundle.keySet();
158                mHandler.post(new Runnable() {
159                    public void run() {
160                        optionsComplete();
161                    }
162                });
163                return;
164            } catch (OperationCanceledException e) {
165                Log.d(Email.LOG_TAG, "addAccount was canceled");
166            } catch (IOException e) {
167                Log.d(Email.LOG_TAG, "addAccount failed: " + e);
168            } catch (AuthenticatorException e) {
169                Log.d(Email.LOG_TAG, "addAccount failed: " + e);
170            }
171            showErrorDialog(R.string.account_setup_failed_dlg_auth_message,
172                    R.string.system_account_create_failed);
173        }
174    };
175
176    private void showErrorDialog(final int msgResId, final Object... args) {
177        mHandler.post(new Runnable() {
178            public void run() {
179                new AlertDialog.Builder(AccountSetupOptions.this)
180                        .setIcon(android.R.drawable.ic_dialog_alert)
181                        .setTitle(getString(R.string.account_setup_failed_dlg_title))
182                        .setMessage(getString(msgResId, args))
183                        .setCancelable(true)
184                        .setPositiveButton(
185                                getString(R.string.account_setup_failed_dlg_edit_details_action),
186                                new DialogInterface.OnClickListener() {
187                                    public void onClick(DialogInterface dialog, int which) {
188                                       finish();
189                                    }
190                                })
191                        .show();
192            }
193        });
194    }
195
196    @Override
197    public void onActivityResult(int requestCode, int resultCode, Intent data) {
198        saveAccountAndFinish();
199    }
200
201    private void optionsComplete() {
202        // If we've got policies for this account, ask the user to accept.
203        if ((mAccount.mFlags & Account.FLAGS_SECURITY_HOLD) != 0) {
204            Intent intent = AccountSecurity.actionUpdateSecurityIntent(this, mAccount.mId);
205            startActivityForResult(intent, AccountSetupOptions.REQUEST_CODE_ACCEPT_POLICIES);
206            return;
207        }
208        saveAccountAndFinish();
209    }
210
211    private void saveAccountAndFinish() {
212        // Clear the incomplete/security hold flag now
213        mAccount.mFlags &= ~(Account.FLAGS_INCOMPLETE | Account.FLAGS_SECURITY_HOLD);
214        AccountSettingsUtils.commitSettings(this, mAccount);
215        Email.setServicesEnabled(this);
216        AccountSetupNames.actionSetNames(this, mAccount.mId, mEasFlowMode);
217        // Start up SyncManager (if it isn't already running)
218        ExchangeUtils.startExchangeService(this);
219        finish();
220    }
221
222    private void onDone() {
223        mAccount.setDisplayName(mAccount.getEmailAddress());
224        int newFlags = mAccount.getFlags() & ~(EmailContent.Account.FLAGS_NOTIFY_NEW_MAIL);
225        if (mNotifyView.isChecked()) {
226            newFlags |= EmailContent.Account.FLAGS_NOTIFY_NEW_MAIL;
227        }
228        mAccount.setFlags(newFlags);
229        mAccount.setSyncInterval((Integer)((SpinnerOption)mCheckFrequencyView
230                .getSelectedItem()).value);
231        if (mSyncWindowView.getVisibility() == View.VISIBLE) {
232            int window = (Integer)((SpinnerOption)mSyncWindowView.getSelectedItem()).value;
233            mAccount.setSyncLookback(window);
234        }
235        mAccount.setDefaultAccount(mDefaultView.isChecked());
236
237        // If this is an Exchange account, setup up the AccountManager account
238        if (!mAccount.isSaved()
239                && mAccount.mHostAuthRecv != null
240                && mAccount.mHostAuthRecv.mProtocol.equals("eas")) {
241            boolean alsoSyncContacts = mSyncContactsView.isChecked();
242            boolean alsoSyncCalendar = mSyncCalendarView.isChecked();
243            // Set the incomplete flag here to avoid reconciliation issues in SyncManager
244            // Set security hold if necessary to prevent initial sync until policies are accepted
245            mAccount.mFlags |= Account.FLAGS_INCOMPLETE;
246            if (mPolicySet != null && mPolicySet.getSecurityCode() != 0) {
247                mAccount.mSecurityFlags = mPolicySet.getSecurityCode();
248                mAccount.mFlags |= Account.FLAGS_SECURITY_HOLD;
249            }
250            AccountSettingsUtils.commitSettings(this, mAccount);
251            // The callback will call finishOnDone()
252            ExchangeStore.addSystemAccount(getApplication(), mAccount,
253                    alsoSyncContacts, alsoSyncCalendar, mAccountManagerCallback);
254        } else {
255            optionsComplete();
256        }
257    }
258
259    public void onClick(View v) {
260        switch (v.getId()) {
261            case R.id.next:
262                // Don't allow this more than once (Exchange accounts call an async method
263                // before finish()'ing the Activity, which allows this code to potentially be
264                // executed multiple times
265                if (!mDonePressed) {
266                    onDone();
267                    mDonePressed = true;
268                }
269                break;
270        }
271    }
272
273    /**
274     * Enable an additional spinner using the arrays normally handled by preferences
275     */
276    private void enableEASSyncWindowSpinner() {
277        // Show everything
278        findViewById(R.id.account_sync_window_label).setVisibility(View.VISIBLE);
279        mSyncWindowView.setVisibility(View.VISIBLE);
280
281        // Generate spinner entries using XML arrays used by the preferences
282        CharSequence[] windowValues = getResources().getTextArray(
283                R.array.account_settings_mail_window_values);
284        CharSequence[] windowEntries = getResources().getTextArray(
285                R.array.account_settings_mail_window_entries);
286
287        // Now create the array used by the Spinner
288        SpinnerOption[] windowOptions = new SpinnerOption[windowEntries.length];
289        int defaultIndex = -1;
290        for (int i = 0; i < windowEntries.length; i++) {
291            final int value = Integer.valueOf(windowValues[i].toString());
292            windowOptions[i] = new SpinnerOption(value, windowEntries[i].toString());
293            if (value == SYNC_WINDOW_EAS_DEFAULT) {
294                defaultIndex = i;
295            }
296        }
297
298        ArrayAdapter<SpinnerOption> windowOptionsAdapter = new ArrayAdapter<SpinnerOption>(this,
299                android.R.layout.simple_spinner_item, windowOptions);
300        windowOptionsAdapter
301                .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
302        mSyncWindowView.setAdapter(windowOptionsAdapter);
303
304        SpinnerOption.setSpinnerOptionValue(mSyncWindowView, mAccount.getSyncLookback());
305        if (defaultIndex >= 0) {
306            mSyncWindowView.setSelection(defaultIndex);
307        }
308    }
309}
310