AccountSetupOptions.java revision f020910461908681978a9e0f8f98b748853b0e39
196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/*
296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * you may not use this file except in compliance with the License.
696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * You may obtain a copy of the License at
796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
1096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * See the License for the specific language governing permissions and
1496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * limitations under the License.
1596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
1696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
1796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpackage com.android.email.activity.setup;
1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
192b0c619f1edd9fd89dc06bf35d99ece91f415f1eAndy Stadlerimport com.android.email.Email;
209fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onukiimport com.android.email.ExchangeUtils;
212b0c619f1edd9fd89dc06bf35d99ece91f415f1eAndy Stadlerimport com.android.email.R;
22d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blankimport com.android.email.SecurityPolicy.PolicySet;
23ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadlerimport com.android.email.Utility;
24cd09545b87979fa6b4337f17b5a001f0ef7b5269Andrew Stadlerimport com.android.email.activity.ActivityHelper;
25ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadlerimport com.android.email.mail.Store;
26a290f503f14432163f74548a5e5d1dc5003ad049Marc Blankimport com.android.email.provider.EmailContent;
270b8b68cbebdba372c7302a207e2321cd80b384aeMarc Blankimport com.android.email.provider.EmailContent.Account;
28e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blankimport com.android.email.service.MailService;
292b0c619f1edd9fd89dc06bf35d99ece91f415f1eAndy Stadler
30f020910461908681978a9e0f8f98b748853b0e39Andy Stadlerimport android.accounts.AccountAuthenticatorResponse;
31f020910461908681978a9e0f8f98b748853b0e39Andy Stadlerimport android.accounts.AccountManager;
32a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blankimport android.accounts.AccountManagerCallback;
33a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blankimport android.accounts.AccountManagerFuture;
34a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blankimport android.accounts.AuthenticatorException;
35a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blankimport android.accounts.OperationCanceledException;
3696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.app.Activity;
37a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blankimport android.app.AlertDialog;
38ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadlerimport android.content.Context;
39a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blankimport android.content.DialogInterface;
4096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.content.Intent;
4196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.os.Bundle;
42a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blankimport android.util.Log;
4396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.view.View;
447fd78d8d6184384cd2393849a554cce58e71180aAndy Stadlerimport android.view.View.OnClickListener;
4596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.widget.ArrayAdapter;
4696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.widget.CheckBox;
4796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.widget.Spinner;
4896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
49a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blankimport java.io.IOException;
50a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank
51ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler/**
5249518bb3605d6c8e3cc4801c452e4f8f63220f44Makoto Onuki * TODO: Cleanup the manipulation of Account.FLAGS_INCOMPLETE and make sure it's never left set.
53ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler */
547fd78d8d6184384cd2393849a554cce58e71180aAndy Stadlerpublic class AccountSetupOptions extends AccountSetupActivity implements OnClickListener {
5596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
5696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private Spinner mCheckFrequencyView;
579197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler    private Spinner mSyncWindowView;
5896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private CheckBox mDefaultView;
5996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private CheckBox mNotifyView;
60bcff14acf25d3a999b7448e317604e694c204f47Andrew Stadler    private CheckBox mSyncContactsView;
61f3fcb8929e3690bc092aec0d4d643b346f079acdMarc Blank    private CheckBox mSyncCalendarView;
62e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank    private CheckBox mSyncEmailView;
63946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler    private CheckBox mBackgroundAttachmentsView;
64b7fe21676ec46ce98e88bc181fc82a18e882236aMarc Blank    private boolean mDonePressed = false;
65d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank
66d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank    public static final int REQUEST_CODE_ACCEPT_POLICIES = 1;
679019315b2642d58691cf09d32c07c0cf902f0a41Andrew Stadler
686854a4f24a0e93547fc7785553b7f53878a76e08Makoto Onuki    /** Default sync window for new EAS accounts */
696854a4f24a0e93547fc7785553b7f53878a76e08Makoto Onuki    private static final int SYNC_WINDOW_EAS_DEFAULT = com.android.email.Account.SYNC_WINDOW_3_DAYS;
706854a4f24a0e93547fc7785553b7f53878a76e08Makoto Onuki
71e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank    public static void actionOptions(Activity fromActivity) {
72e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank        fromActivity.startActivity(new Intent(fromActivity, AccountSetupOptions.class));
7396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    @Override
7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void onCreate(Bundle savedInstanceState) {
7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        super.onCreate(savedInstanceState);
78cd09545b87979fa6b4337f17b5a001f0ef7b5269Andrew Stadler        ActivityHelper.debugSetWindowFlags(this);
7996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        setContentView(R.layout.account_setup_options);
8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mCheckFrequencyView = (Spinner)findViewById(R.id.account_check_frequency);
829197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        mSyncWindowView = (Spinner) findViewById(R.id.account_sync_window);
8396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mDefaultView = (CheckBox)findViewById(R.id.account_default);
8496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mNotifyView = (CheckBox)findViewById(R.id.account_notify);
85bcff14acf25d3a999b7448e317604e694c204f47Andrew Stadler        mSyncContactsView = (CheckBox) findViewById(R.id.account_sync_contacts);
86f3fcb8929e3690bc092aec0d4d643b346f079acdMarc Blank        mSyncCalendarView = (CheckBox) findViewById(R.id.account_sync_calendar);
87e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank        mSyncEmailView = (CheckBox) findViewById(R.id.account_sync_email);
88e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank        mSyncEmailView.setChecked(true);
89946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler        mBackgroundAttachmentsView = (CheckBox) findViewById(R.id.account_background_attachments);
90946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler        mBackgroundAttachmentsView.setChecked(true);
917fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler        findViewById(R.id.previous).setOnClickListener(this);
927fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler        findViewById(R.id.next).setOnClickListener(this);
9396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
94ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler        // Generate spinner entries using XML arrays used by the preferences
95ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler        int frequencyValuesId;
96ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler        int frequencyEntriesId;
97e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank        Account account = SetupData.getAccount();
98e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank        Store.StoreInfo info = Store.StoreInfo.getStoreInfo(account.getStoreUri(this), this);
99ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler        if (info.mPushSupported) {
100ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler            frequencyValuesId = R.array.account_settings_check_frequency_values_push;
101ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler            frequencyEntriesId = R.array.account_settings_check_frequency_entries_push;
102ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler        } else {
103ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler            frequencyValuesId = R.array.account_settings_check_frequency_values;
104ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler            frequencyEntriesId = R.array.account_settings_check_frequency_entries;
105ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler        }
106ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler        CharSequence[] frequencyValues = getResources().getTextArray(frequencyValuesId);
107ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler        CharSequence[] frequencyEntries = getResources().getTextArray(frequencyEntriesId);
108a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank
109ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler        // Now create the array used by the Spinner
110ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler        SpinnerOption[] checkFrequencies = new SpinnerOption[frequencyEntries.length];
111ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler        for (int i = 0; i < frequencyEntries.length; i++) {
112ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler            checkFrequencies[i] = new SpinnerOption(
113ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler                    Integer.valueOf(frequencyValues[i].toString()), frequencyEntries[i].toString());
114ea6fea9bb22368c10083d5dce52adae86e51a243Andy Stadler        }
11596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        ArrayAdapter<SpinnerOption> checkFrequenciesAdapter = new ArrayAdapter<SpinnerOption>(this,
11796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                android.R.layout.simple_spinner_item, checkFrequencies);
11896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        checkFrequenciesAdapter
11996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
12096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mCheckFrequencyView.setAdapter(checkFrequenciesAdapter);
121a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank
1229197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        if (info.mVisibleLimitDefault == -1) {
1239197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler            enableEASSyncWindowSpinner();
1249197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        }
12596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
12654c1f2bf9a6574240b7c9af253f83a2b566442abAndrew Stadler        // Note:  It is OK to use mAccount.mIsDefault here *only* because the account
12754c1f2bf9a6574240b7c9af253f83a2b566442abAndrew Stadler        // has not been written to the DB yet.  Ordinarily, call Account.getDefaultAccountId().
128e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank        if (account.mIsDefault || SetupData.isDefault()) {
12996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mDefaultView.setChecked(true);
13096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
131294a4fd0c6b15c1f8f41ca03be66ed95e16e5a6dAndrew Stadler        mNotifyView.setChecked(
132e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank                (account.getFlags() & EmailContent.Account.FLAGS_NOTIFY_NEW_MAIL) != 0);
133e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank        SpinnerOption.setSpinnerOptionValue(mCheckFrequencyView, account.getSyncInterval());
134bcff14acf25d3a999b7448e317604e694c204f47Andrew Stadler
135bcff14acf25d3a999b7448e317604e694c204f47Andrew Stadler        // Setup any additional items to support EAS & EAS flow mode
136bcff14acf25d3a999b7448e317604e694c204f47Andrew Stadler        if ("eas".equals(info.mScheme)) {
137bcff14acf25d3a999b7448e317604e694c204f47Andrew Stadler            // "also sync contacts" == "true"
138bcff14acf25d3a999b7448e317604e694c204f47Andrew Stadler            mSyncContactsView.setVisibility(View.VISIBLE);
139bcff14acf25d3a999b7448e317604e694c204f47Andrew Stadler            mSyncContactsView.setChecked(true);
140f3fcb8929e3690bc092aec0d4d643b346f079acdMarc Blank            mSyncCalendarView.setVisibility(View.VISIBLE);
141f3fcb8929e3690bc092aec0d4d643b346f079acdMarc Blank            mSyncCalendarView.setChecked(true);
1427fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler            // Show the associated dividers
1437fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler            findViewById(R.id.account_sync_contacts_divider).setVisibility(View.VISIBLE);
1447fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler            findViewById(R.id.account_sync_calendar_divider).setVisibility(View.VISIBLE);
145bcff14acf25d3a999b7448e317604e694c204f47Andrew Stadler        }
146e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank
147946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler        // If we are in POP3, hide the "Background Attachments" mode
148946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler        if ("pop3".equals(info.mScheme)) {
149946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler            mBackgroundAttachmentsView.setVisibility(View.GONE);
150946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler            findViewById(R.id.account_background_attachments_divider).setVisibility(View.GONE);
151946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler        }
152946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler
153d685b469c73c3479c09301da2e65cd7c11fd4aceAndy Stadler        // If we are just visiting here to fill in details, exit immediately
154d685b469c73c3479c09301da2e65cd7c11fd4aceAndy Stadler        if (SetupData.isAutoSetup() ||
155d685b469c73c3479c09301da2e65cd7c11fd4aceAndy Stadler                SetupData.getFlowMode() == SetupData.FLOW_MODE_FORCE_CREATE) {
156e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank            onDone();
157e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank        }
15896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
15996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
160f020910461908681978a9e0f8f98b748853b0e39Andy Stadler    @Override
161f020910461908681978a9e0f8f98b748853b0e39Andy Stadler    public void finish() {
162f020910461908681978a9e0f8f98b748853b0e39Andy Stadler        // If the account manager initiated the creation, and success was not reported,
163f020910461908681978a9e0f8f98b748853b0e39Andy Stadler        // then we assume that we're giving up (for any reason) - report failure.
164f020910461908681978a9e0f8f98b748853b0e39Andy Stadler        AccountAuthenticatorResponse authenticatorResponse =
165f020910461908681978a9e0f8f98b748853b0e39Andy Stadler            SetupData.getAccountAuthenticatorResponse();
166f020910461908681978a9e0f8f98b748853b0e39Andy Stadler        if (authenticatorResponse != null) {
167f020910461908681978a9e0f8f98b748853b0e39Andy Stadler            authenticatorResponse.onError(AccountManager.ERROR_CODE_CANCELED, "canceled");
168f020910461908681978a9e0f8f98b748853b0e39Andy Stadler            SetupData.setAccountAuthenticatorResponse(null);
169f020910461908681978a9e0f8f98b748853b0e39Andy Stadler        }
170f020910461908681978a9e0f8f98b748853b0e39Andy Stadler        super.finish();
171f020910461908681978a9e0f8f98b748853b0e39Andy Stadler    }
172f020910461908681978a9e0f8f98b748853b0e39Andy Stadler
1738bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler    /**
1747fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler     * Respond to clicks in the "Next" or "Previous" buttons
1758bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler     */
1768bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler    @Override
1777fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler    public void onClick(View view) {
1787fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler        switch (view.getId()) {
1798bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler            case R.id.next:
1808bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler                // Don't allow this more than once (Exchange accounts call an async method
1818bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler                // before finish()'ing the Activity, which allows this code to potentially be
1828bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler                // executed multiple times
1838bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler                if (!mDonePressed) {
1848bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler                    onDone();
1858bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler                    mDonePressed = true;
1868bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler                }
1877fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler                break;
1887fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler            case R.id.previous:
1897fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler                onBackPressed();
1907fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler                break;
1918bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler        }
1928bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler    }
1938bcb572ccfdac6974c111fe6dfc753a5e0d4e7caAndrew Stadler
194ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler    /**
195ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     * Ths is called when the user clicks the "done" button.
196ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     * It collects the data from the UI, updates the setup account record, and commits
197ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     * the account to the database (making it real for the first time.)
198ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     * Finally, we call setupAccountManagerAccount(), which will eventually complete via callback.
199ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     */
200ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler    private void onDone() {
201ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        final Account account = SetupData.getAccount();
202ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        account.setDisplayName(account.getEmailAddress());
203946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler        int newFlags = account.getFlags() &
204946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler                ~(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_BACKGROUND_ATTACHMENTS);
205ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        if (mNotifyView.isChecked()) {
206946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler            newFlags |= Account.FLAGS_NOTIFY_NEW_MAIL;
207946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler        }
208946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler        if (mBackgroundAttachmentsView.isChecked()) {
209946239e8a0e01c628fae61894d3d48248b74cefcAndy Stadler            newFlags |= Account.FLAGS_BACKGROUND_ATTACHMENTS;
210ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        }
211ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        account.setFlags(newFlags);
212ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        account.setSyncInterval((Integer)((SpinnerOption)mCheckFrequencyView
213ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                .getSelectedItem()).value);
214ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        if (findViewById(R.id.account_sync_window_row).getVisibility() == View.VISIBLE) {
215ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            int window = (Integer)((SpinnerOption)mSyncWindowView.getSelectedItem()).value;
216ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            account.setSyncLookback(window);
217ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        }
218ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        account.setDefaultAccount(mDefaultView.isChecked());
219ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler
220ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        if (account.isSaved()) {
221ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            throw new IllegalStateException("in AccountSetupOptions with already-saved account");
222ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        }
223ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        if (account.mHostAuthRecv == null) {
224ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            throw new IllegalStateException("in AccountSetupOptions with null mHostAuthRecv");
225ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        }
226ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler
227ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        // Finish setting up the account, and commit it to the database
228ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        // Set the incomplete flag here to avoid reconciliation issues in ExchangeService
229ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        account.mFlags |= Account.FLAGS_INCOMPLETE;
230ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        boolean calendar = false;
231ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        boolean contacts = false;
232ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        boolean email = mSyncEmailView.isChecked();
233ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        if (account.mHostAuthRecv.mProtocol.equals("eas")) {
234ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            // Set security hold if necessary to prevent sync until policies are accepted
235ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            PolicySet policySet = SetupData.getPolicySet();
236ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            if (policySet != null && policySet.getSecurityCode() != 0) {
237ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                account.mSecurityFlags = policySet.getSecurityCode();
238ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                account.mFlags |= Account.FLAGS_SECURITY_HOLD;
239ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            }
240ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            // Get flags for contacts/calendar sync
241ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            contacts = mSyncContactsView.isChecked();
242ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            calendar = mSyncCalendarView.isChecked();
243ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        }
244ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler
245ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        // Finally, write the completed account (for the first time) and then
246ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        // install it into the Account manager as well.  These are done off-thread.
247ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        // The account manager will report back via the callback, which will take us to
248ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        // the next operations.
249ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        final boolean email2 = email;
250ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        final boolean calendar2 = calendar;
251ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        final boolean contacts2 = contacts;
252ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        Utility.runAsync(new Runnable() {
253ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            @Override
254ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            public void run() {
255ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                Context context = AccountSetupOptions.this;
256ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                AccountSettingsUtils.commitSettings(context, account);
257ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                MailService.setupAccountManagerAccount(context, account,
258ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                        email2, calendar2, contacts2, mAccountManagerCallback);
259ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            }
260ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        });
261ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler    }
262ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler
263ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler    /**
264ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     * This is called at the completion of MailService.setupAccountManagerAccount()
265ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     */
266a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank    AccountManagerCallback<Bundle> mAccountManagerCallback = new AccountManagerCallback<Bundle>() {
267a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank        public void run(AccountManagerFuture<Bundle> future) {
268a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank            try {
269a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                Bundle bundle = future.getResult();
270a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                bundle.keySet();
271ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                AccountSetupOptions.this.runOnUiThread(new Runnable() {
272a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                    public void run() {
273d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank                        optionsComplete();
274a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                    }
275a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                });
276a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                return;
277a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank            } catch (OperationCanceledException e) {
278a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                Log.d(Email.LOG_TAG, "addAccount was canceled");
279a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank            } catch (IOException e) {
280a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                Log.d(Email.LOG_TAG, "addAccount failed: " + e);
281a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank            } catch (AuthenticatorException e) {
282a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                Log.d(Email.LOG_TAG, "addAccount failed: " + e);
283a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank            }
284a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank            showErrorDialog(R.string.account_setup_failed_dlg_auth_message,
285a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                    R.string.system_account_create_failed);
286a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank        }
287a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank    };
288a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank
289ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler    /**
290ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     * This is called if MailService.setupAccountManagerAccount() fails for some reason
291ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     */
292a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank    private void showErrorDialog(final int msgResId, final Object... args) {
293ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        runOnUiThread(new Runnable() {
294a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank            public void run() {
295a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                new AlertDialog.Builder(AccountSetupOptions.this)
29649518bb3605d6c8e3cc4801c452e4f8f63220f44Makoto Onuki                        .setIconAttribute(android.R.attr.alertDialogIcon)
297a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                        .setTitle(getString(R.string.account_setup_failed_dlg_title))
298a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                        .setMessage(getString(msgResId, args))
299a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                        .setCancelable(true)
300a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                        .setPositiveButton(
301a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                                getString(R.string.account_setup_failed_dlg_edit_details_action),
302a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                                new DialogInterface.OnClickListener() {
303a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                                    public void onClick(DialogInterface dialog, int which) {
304a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                                       finish();
305a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                                    }
306a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                                })
307a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank                        .show();
308a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank            }
309a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank        });
310a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank    }
3110b8b68cbebdba372c7302a207e2321cd80b384aeMarc Blank
312ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler    /**
313ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     * This is called after the account manager creates the new account.
314ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     */
315d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank    private void optionsComplete() {
316f020910461908681978a9e0f8f98b748853b0e39Andy Stadler        // If the account manager initiated the creation, report success at this point
317f020910461908681978a9e0f8f98b748853b0e39Andy Stadler        AccountAuthenticatorResponse authenticatorResponse =
318f020910461908681978a9e0f8f98b748853b0e39Andy Stadler                SetupData.getAccountAuthenticatorResponse();
319f020910461908681978a9e0f8f98b748853b0e39Andy Stadler        if (authenticatorResponse != null) {
320f020910461908681978a9e0f8f98b748853b0e39Andy Stadler            authenticatorResponse.onResult(null);
321f020910461908681978a9e0f8f98b748853b0e39Andy Stadler            SetupData.setAccountAuthenticatorResponse(null);
322f020910461908681978a9e0f8f98b748853b0e39Andy Stadler        }
323f020910461908681978a9e0f8f98b748853b0e39Andy Stadler
324d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank        // If we've got policies for this account, ask the user to accept.
325e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank        Account account = SetupData.getAccount();
326e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank        if ((account.mFlags & Account.FLAGS_SECURITY_HOLD) != 0) {
327e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank            Intent intent = AccountSecurity.actionUpdateSecurityIntent(this, account.mId);
328d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank            startActivityForResult(intent, AccountSetupOptions.REQUEST_CODE_ACCEPT_POLICIES);
329d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank            return;
330d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank        }
331d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank        saveAccountAndFinish();
332d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank    }
333d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank
3342959a7e073c87e2fa5fab42ec543b352a91cf187Andy Stadler    /**
335ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     * This is called after the AccountSecurity activity completes.
3362959a7e073c87e2fa5fab42ec543b352a91cf187Andy Stadler     */
337ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler    @Override
338ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler    public void onActivityResult(int requestCode, int resultCode, Intent data) {
339ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        saveAccountAndFinish();
340a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank    }
341a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank
342ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler    /**
343ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     * These are the final cleanup steps when creating an account:
344ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     *  Clear incomplete & security hold flags
345ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     *  Update account in DB
346ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     *  Enable email services
347ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     *  Enable exchange services
348ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     *  Move to final setup screen
349ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler     */
350ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler    private void saveAccountAndFinish() {
351ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        Utility.runAsync(new Runnable() {
352ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            @Override
353ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler            public void run() {
354ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                AccountSetupOptions context = AccountSetupOptions.this;
355ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                // Clear the incomplete/security hold flag now
356ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                Account account = SetupData.getAccount();
357ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                account.mFlags &= ~(Account.FLAGS_INCOMPLETE | Account.FLAGS_SECURITY_HOLD);
358ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                AccountSettingsUtils.commitSettings(context, account);
359ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                // Start up services based on new account(s)
360ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                Email.setServicesEnabledSync(context);
361ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                ExchangeUtils.startExchangeService(context);
362ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                // Move to final setup screen
363ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                AccountSetupNames.actionSetNames(context);
364ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler                finish();
365d6d874f8c6ce2580ef9ec2406fe411af45b2d92dMarc Blank            }
366ec9398e7c6dc7a016b68ea3009fd950f898763a0Andy Stadler        });
36796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
36896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
3699197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler    /**
3709197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler     * Enable an additional spinner using the arrays normally handled by preferences
3719197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler     */
3729197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler    private void enableEASSyncWindowSpinner() {
3739197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        // Show everything
3747fd78d8d6184384cd2393849a554cce58e71180aAndy Stadler        findViewById(R.id.account_sync_window_row).setVisibility(View.VISIBLE);
3759197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler
3769197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        // Generate spinner entries using XML arrays used by the preferences
3779197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        CharSequence[] windowValues = getResources().getTextArray(
3789197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler                R.array.account_settings_mail_window_values);
3799197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        CharSequence[] windowEntries = getResources().getTextArray(
3809197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler                R.array.account_settings_mail_window_entries);
381a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank
3829197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        // Now create the array used by the Spinner
3839197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        SpinnerOption[] windowOptions = new SpinnerOption[windowEntries.length];
3846854a4f24a0e93547fc7785553b7f53878a76e08Makoto Onuki        int defaultIndex = -1;
3859197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        for (int i = 0; i < windowEntries.length; i++) {
3866854a4f24a0e93547fc7785553b7f53878a76e08Makoto Onuki            final int value = Integer.valueOf(windowValues[i].toString());
3876854a4f24a0e93547fc7785553b7f53878a76e08Makoto Onuki            windowOptions[i] = new SpinnerOption(value, windowEntries[i].toString());
3886854a4f24a0e93547fc7785553b7f53878a76e08Makoto Onuki            if (value == SYNC_WINDOW_EAS_DEFAULT) {
3896854a4f24a0e93547fc7785553b7f53878a76e08Makoto Onuki                defaultIndex = i;
3906854a4f24a0e93547fc7785553b7f53878a76e08Makoto Onuki            }
3919197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        }
3929197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler
3939197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        ArrayAdapter<SpinnerOption> windowOptionsAdapter = new ArrayAdapter<SpinnerOption>(this,
3949197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler                android.R.layout.simple_spinner_item, windowOptions);
3959197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        windowOptionsAdapter
3969197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler                .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
3979197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler        mSyncWindowView.setAdapter(windowOptionsAdapter);
398a3c6c6ed294d5a1fb0662fdacc1388944487fdf2Marc Blank
399e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank        SpinnerOption.setSpinnerOptionValue(mSyncWindowView,
400e6cc662abc0b5fffe223cda5e980b4f05a4e91ddMarc Blank                SetupData.getAccount().getSyncLookback());
4016854a4f24a0e93547fc7785553b7f53878a76e08Makoto Onuki        if (defaultIndex >= 0) {
4026854a4f24a0e93547fc7785553b7f53878a76e08Makoto Onuki            mSyncWindowView.setSelection(defaultIndex);
4036854a4f24a0e93547fc7785553b7f53878a76e08Makoto Onuki        }
4049197f428946d5c77613b64a50c93a46e2acf62dcAndy Stadler    }
40596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project}
406