AccountSetupNames.java revision e6cc662abc0b5fffe223cda5e980b4f05a4e91dd
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.AccountBackupRestore;
20import com.android.email.R;
21import com.android.email.Utility;
22import com.android.email.activity.Welcome;
23import com.android.email.provider.EmailContent.Account;
24import com.android.email.provider.EmailContent.AccountColumns;
25import com.android.email.provider.EmailContent.HostAuth;
26
27import android.app.Activity;
28import android.content.ContentUris;
29import android.content.ContentValues;
30import android.content.Intent;
31import android.database.Cursor;
32import android.os.AsyncTask;
33import android.os.Bundle;
34import android.text.Editable;
35import android.text.TextWatcher;
36import android.text.method.TextKeyListener;
37import android.text.method.TextKeyListener.Capitalize;
38import android.view.View;
39import android.view.View.OnClickListener;
40import android.widget.Button;
41import android.widget.EditText;
42
43public class AccountSetupNames extends AccountSetupActivity implements OnClickListener {
44    private static final int REQUEST_SECURITY = 0;
45
46    private EditText mDescription;
47    private EditText mName;
48    private Button mDoneButton;
49    private boolean mEasAccount = false;
50
51    private CheckAccountStateTask mCheckAccountStateTask;
52
53    private static final int ACCOUNT_INFO_COLUMN_FLAGS = 0;
54    private static final int ACCOUNT_INFO_COLUMN_SECURITY_FLAGS = 1;
55    private static final String[] ACCOUNT_INFO_PROJECTION = new String[] {
56            AccountColumns.FLAGS, AccountColumns.SECURITY_FLAGS };
57
58    public static void actionSetNames(Activity fromActivity) {
59        fromActivity.startActivity(new Intent(fromActivity, AccountSetupNames.class));
60    }
61
62    @Override
63    public void onCreate(Bundle savedInstanceState) {
64        super.onCreate(savedInstanceState);
65        setContentView(R.layout.account_setup_names);
66        mDescription = (EditText)findViewById(R.id.account_description);
67        mName = (EditText)findViewById(R.id.account_name);
68        mDoneButton = (Button)findViewById(R.id.done);
69        mDoneButton.setOnClickListener(this);
70
71        TextWatcher validationTextWatcher = new TextWatcher() {
72            public void afterTextChanged(Editable s) {
73                validateFields();
74            }
75
76            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
77            }
78
79            public void onTextChanged(CharSequence s, int start, int before, int count) {
80            }
81        };
82        mName.addTextChangedListener(validationTextWatcher);
83        mName.setKeyListener(TextKeyListener.getInstance(false, Capitalize.WORDS));
84
85        Account account = SetupData.getAccount();
86        // Shouldn't happen, but it could
87        if (account == null) {
88            onBackPressed();
89            return;
90        }
91        // Get the hostAuth for receiving
92        HostAuth hostAuth = HostAuth.restoreHostAuthWithId(this, account.mHostAuthKeyRecv);
93        if (hostAuth == null) {
94            onBackPressed();
95            return;
96        }
97
98        // Remember whether we're an EAS account, since it doesn't require the user name field
99        mEasAccount = hostAuth.mProtocol.equals("eas");
100        if (mEasAccount) {
101            mName.setVisibility(View.GONE);
102            findViewById(R.id.account_name_label).setVisibility(View.GONE);
103        }
104        /*
105         * Since this field is considered optional, we don't set this here. If
106         * the user fills in a value we'll reset the current value, otherwise we
107         * just leave the saved value alone.
108         */
109        // mDescription.setText(mAccount.getDescription());
110        if (account != null && account.getSenderName() != null) {
111            mName.setText(account.getSenderName());
112        }
113
114        // Make sure the "done" button is in the proper state
115        validateFields();
116    }
117
118    @Override
119    protected void onDestroy() {
120        super.onDestroy();
121
122        if (mCheckAccountStateTask != null &&
123                mCheckAccountStateTask.getStatus() != CheckAccountStateTask.Status.FINISHED) {
124            mCheckAccountStateTask.cancel(true);
125            mCheckAccountStateTask = null;
126        }
127    }
128
129    /**
130     * TODO: Validator should also trim the name string before checking it.
131     */
132    private void validateFields() {
133        if (!mEasAccount) {
134            mDoneButton.setEnabled(Utility.isTextViewNotEmpty(mName));
135        }
136        Utility.setCompoundDrawablesAlpha(mDoneButton, mDoneButton.isEnabled() ? 255 : 128);
137    }
138
139    @Override
140    public void onBackPressed() {
141        if (SetupData.getFlowMode() != SetupData.FLOW_MODE_NORMAL) {
142            AccountSetupBasics.actionAccountCreateFinishedAccountFlow(this);
143        } else {
144            Account account = SetupData.getAccount();
145            if (account != null) {
146                AccountSetupBasics.actionAccountCreateFinished(this, account.mId);
147            } else {
148                // Safety check here;  If mAccount is null (due to external issues or bugs)
149                // just rewind back to Welcome, which can handle any configuration of accounts
150                Welcome.actionStart(this);
151            }
152        }
153        finish();
154    }
155
156    /**
157     * After having a chance to input the display names, we normally jump directly to the
158     * inbox for the new account.  However if we're in EAS flow mode (externally-launched
159     * account creation) we simply "pop" here which should return us to the Accounts activities.
160     *
161     * TODO: Validator should also trim the description string before checking it.
162     */
163    private void onNext() {
164        Account account = SetupData.getAccount();
165        if (Utility.isTextViewNotEmpty(mDescription)) {
166            account.setDisplayName(mDescription.getText().toString());
167        }
168        String name = mName.getText().toString();
169        account.setSenderName(name);
170        ContentValues cv = new ContentValues();
171        cv.put(AccountColumns.DISPLAY_NAME, account.getDisplayName());
172        cv.put(AccountColumns.SENDER_NAME, name);
173        account.update(this, cv);
174        // Update the backup (side copy) of the accounts
175        AccountBackupRestore.backupAccounts(this);
176
177        // Before proceeding, launch an AsyncTask to test the account for any syncing problems,
178        // and if there's a problem, bring up the UI to update the security level.
179        mCheckAccountStateTask = new CheckAccountStateTask(account.mId);
180        mCheckAccountStateTask.execute();
181    }
182
183    public void onClick(View v) {
184        switch (v.getId()) {
185            case R.id.done:
186                onNext();
187                break;
188        }
189    }
190
191    /**
192     * This async task is launched just before exiting.  It's a last chance test, before leaving
193     * this activity, for the account being in a "hold" state, and gives the user a chance to
194     * update security, enter a device PIN, etc. for a more seamless account setup experience.
195     *
196     * TODO: If there was *any* indication that security might be required, we could at least
197     * force the DeviceAdmin activation step, without waiting for the initial sync/handshake
198     * to fail.
199     * TODO: If the user doesn't update the security, don't go to the MessageList.
200     */
201    private class CheckAccountStateTask extends AsyncTask<Void, Void, Boolean> {
202
203        private long mAccountId;
204
205        public CheckAccountStateTask(long accountId) {
206            mAccountId = accountId;
207        }
208
209        @Override
210        protected Boolean doInBackground(Void... params) {
211            Cursor c = AccountSetupNames.this.getContentResolver().query(
212                    ContentUris.withAppendedId(Account.CONTENT_URI, mAccountId),
213                    ACCOUNT_INFO_PROJECTION, null, null, null);
214            try {
215                if (c.moveToFirst()) {
216                    int flags = c.getInt(ACCOUNT_INFO_COLUMN_FLAGS);
217                    int securityFlags = c.getInt(ACCOUNT_INFO_COLUMN_SECURITY_FLAGS);
218                    if ((flags & Account.FLAGS_SECURITY_HOLD) != 0) {
219                        return Boolean.TRUE;
220                    }
221                }
222            } finally {
223                c.close();
224            }
225
226            return Boolean.FALSE;
227        }
228
229        @Override
230        protected void onPostExecute(Boolean isSecurityHold) {
231            if (!isCancelled()) {
232                if (isSecurityHold) {
233                    Intent i = AccountSecurity.actionUpdateSecurityIntent(
234                            AccountSetupNames.this, mAccountId);
235                    AccountSetupNames.this.startActivityForResult(i, REQUEST_SECURITY);
236                } else {
237                    onBackPressed();
238                }
239            }
240        }
241    }
242
243    /**
244     * Handle the eventual result from the security update activity
245     *
246     * TODO: If the user doesn't update the security, don't go to the MessageList.
247     */
248    @Override
249    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
250        switch (requestCode) {
251            case REQUEST_SECURITY:
252                onBackPressed();
253        }
254        super.onActivityResult(requestCode, resultCode, data);
255    }
256
257}
258