AccountSetupNames.java revision cc0185f07c9198008d8dc685ae9979f3e35e8539
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 android.app.Activity; 20import android.content.ContentValues; 21import android.content.Context; 22import android.content.Intent; 23import android.net.Uri; 24import android.os.AsyncTask; 25import android.os.Bundle; 26import android.provider.ContactsContract.Profile; 27import android.text.Editable; 28import android.text.TextUtils; 29import android.text.TextWatcher; 30import android.text.method.TextKeyListener; 31import android.text.method.TextKeyListener.Capitalize; 32import android.view.View; 33import android.view.View.OnClickListener; 34import android.widget.Button; 35import android.widget.EditText; 36 37import com.android.email.R; 38import com.android.email.activity.ActivityHelper; 39import com.android.email.activity.UiUtilities; 40import com.android.email.provider.AccountBackupRestore; 41import com.android.email.service.EmailServiceUtils; 42import com.android.email.service.EmailServiceUtils.EmailServiceInfo; 43import com.android.emailcommon.provider.Account; 44import com.android.emailcommon.provider.EmailContent.AccountColumns; 45import com.android.emailcommon.utility.EmailAsyncTask; 46import com.android.emailcommon.utility.Utility; 47 48/** 49 * Final screen of setup process. Collect account nickname and/or username. 50 */ 51public class AccountSetupNames extends AccountSetupActivity implements OnClickListener { 52 private static final int REQUEST_SECURITY = 0; 53 54 private static final Uri PROFILE_URI = Profile.CONTENT_URI; 55 56 private EditText mDescription; 57 private EditText mName; 58 private Button mNextButton; 59 private boolean mRequiresName = true; 60 61 public static void actionSetNames(Activity fromActivity) { 62 fromActivity.startActivity(new ForwardingIntent(fromActivity, AccountSetupNames.class)); 63 } 64 65 @Override 66 public void onCreate(Bundle savedInstanceState) { 67 super.onCreate(savedInstanceState); 68 ActivityHelper.debugSetWindowFlags(this); 69 setContentView(R.layout.account_setup_names); 70 mDescription = (EditText) UiUtilities.getView(this, R.id.account_description); 71 mName = (EditText) UiUtilities.getView(this, R.id.account_name); 72 View accountNameLabel = UiUtilities.getView(this, R.id.account_name_label); 73 mNextButton = (Button) UiUtilities.getView(this, R.id.next); 74 mNextButton.setOnClickListener(this); 75 76 TextWatcher validationTextWatcher = new TextWatcher() { 77 @Override 78 public void afterTextChanged(Editable s) { 79 validateFields(); 80 } 81 82 @Override 83 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 84 } 85 86 @Override 87 public void onTextChanged(CharSequence s, int start, int before, int count) { 88 } 89 }; 90 mName.addTextChangedListener(validationTextWatcher); 91 mName.setKeyListener(TextKeyListener.getInstance(false, Capitalize.WORDS)); 92 93 Account account = SetupData.getAccount(); 94 if (account == null) { 95 throw new IllegalStateException("unexpected null account"); 96 } 97 if (account.mHostAuthRecv == null) { 98 throw new IllegalStateException("unexpected null hostauth"); 99 } 100 int flowMode = SetupData.getFlowMode(); 101 102 if (flowMode != SetupData.FLOW_MODE_FORCE_CREATE 103 && flowMode != SetupData.FLOW_MODE_EDIT) { 104 String accountEmail = account.mEmailAddress; 105 mDescription.setText(accountEmail); 106 107 // Move cursor to the end so it's easier to erase in case the user doesn't like it. 108 mDescription.setSelection(accountEmail.length()); 109 } 110 111 // Remember whether we're an EAS account, since it doesn't require the user name field 112 EmailServiceInfo info = 113 EmailServiceUtils.getServiceInfo(this, account.mHostAuthRecv.mProtocol); 114 if (!info.usesSmtp) { 115 mRequiresName = false; 116 mName.setVisibility(View.GONE); 117 accountNameLabel.setVisibility(View.GONE); 118 } else { 119 if (account != null && account.getSenderName() != null) { 120 mName.setText(account.getSenderName()); 121 } else if (flowMode != SetupData.FLOW_MODE_FORCE_CREATE 122 && flowMode != SetupData.FLOW_MODE_EDIT) { 123 // Attempt to prefill the name field from the profile if we don't have it, 124 prefillNameFromProfile(); 125 } 126 } 127 128 // Make sure the "done" button is in the proper state 129 validateFields(); 130 131 // Proceed immediately if in account creation mode 132 if (flowMode == SetupData.FLOW_MODE_FORCE_CREATE) { 133 onNext(); 134 } 135 } 136 137 private void prefillNameFromProfile() { 138 new EmailAsyncTask<Void, Void, String>(null) { 139 @Override 140 protected String doInBackground(Void... params) { 141 String[] projection = new String[] { Profile.DISPLAY_NAME }; 142 return Utility.getFirstRowString( 143 AccountSetupNames.this, PROFILE_URI, projection, null, null, null, 0); 144 } 145 146 @Override 147 public void onSuccess(String result) { 148 // Views can only be modified on the main thread. 149 mName.setText(result); 150 } 151 }.executeParallel((Void[]) null); 152 } 153 154 /** 155 * Implements OnClickListener 156 */ 157 @Override 158 public void onClick(View v) { 159 switch (v.getId()) { 160 case R.id.next: 161 onNext(); 162 break; 163 } 164 } 165 166 /** 167 * Check input fields for legal values and enable/disable next button 168 */ 169 private void validateFields() { 170 boolean enableNextButton = true; 171 // Validation is based only on the "user name" field, not shown for EAS accounts 172 if (mRequiresName) { 173 String userName = mName.getText().toString().trim(); 174 if (TextUtils.isEmpty(userName)) { 175 enableNextButton = false; 176 mName.setError(getString(R.string.account_setup_names_user_name_empty_error)); 177 } else { 178 mName.setError(null); 179 } 180 } 181 mNextButton.setEnabled(enableNextButton); 182 } 183 184 /** 185 * Block the back key if we are currently processing the "next" key" 186 */ 187 @Override 188 public void onBackPressed() { 189 if (mNextButton.isEnabled()) { 190 finishActivity(); 191 } 192 } 193 194 private void finishActivity() { 195 if (SetupData.getFlowMode() == SetupData.FLOW_MODE_NO_ACCOUNTS) { 196 AccountSetupBasics.actionAccountCreateFinishedWithResult(this); 197 } else if (SetupData.getFlowMode() != SetupData.FLOW_MODE_NORMAL) { 198 AccountSetupBasics.actionAccountCreateFinishedAccountFlow(this); 199 } else { 200 Account account = SetupData.getAccount(); 201 if (account != null) { 202 AccountSetupBasics.actionAccountCreateFinished(this, account.mId); 203 } else { 204 // Safety check here; If mAccount is null (due to external issues or bugs) 205 // just rewind back to Welcome, which can handle any configuration of accounts 206 //*** 207 //Welcome.actionStart(this); 208 } 209 } 210 finish(); 211 } 212 213 /** 214 * After clicking the next button, we'll start an async task to commit the data 215 * and other steps to finish the creation of the account. 216 */ 217 private void onNext() { 218 mNextButton.setEnabled(false); // Protect against double-tap. 219 220 // Update account object from UI 221 Account account = SetupData.getAccount(); 222 String description = mDescription.getText().toString().trim(); 223 if (!TextUtils.isEmpty(description)) { 224 account.setDisplayName(description); 225 } 226 account.setSenderName(mName.getText().toString().trim()); 227 228 // Launch async task for final commit work 229 // Sicne it's a write task, use the serial executor so even if we ran the task twice 230 // with different values the result would be consistent. 231 new FinalSetupTask(account).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); 232 } 233 234 /** 235 * Final account setup work is handled in this AsyncTask: 236 * Commit final values to provider 237 * Trigger account backup 238 * Check for security hold 239 * 240 * When this completes, we return to UI thread for the following steps: 241 * If security hold, dispatch to AccountSecurity activity 242 * Otherwise, return to AccountSetupBasics for conclusion. 243 * 244 * TODO: If there was *any* indication that security might be required, we could at least 245 * force the DeviceAdmin activation step, without waiting for the initial sync/handshake 246 * to fail. 247 * TODO: If the user doesn't update the security, don't go to the MessageList. 248 */ 249 private class FinalSetupTask extends AsyncTask<Void, Void, Boolean> { 250 251 private final Account mAccount; 252 private final Context mContext; 253 254 public FinalSetupTask(Account account) { 255 mAccount = account; 256 mContext = AccountSetupNames.this; 257 } 258 259 @Override 260 protected Boolean doInBackground(Void... params) { 261 // Update the account in the database 262 ContentValues cv = new ContentValues(); 263 cv.put(AccountColumns.DISPLAY_NAME, mAccount.getDisplayName()); 264 cv.put(AccountColumns.SENDER_NAME, mAccount.getSenderName()); 265 mAccount.update(mContext, cv); 266 267 // Update the backup (side copy) of the accounts 268 AccountBackupRestore.backup(AccountSetupNames.this); 269 270 return Account.isSecurityHold(mContext, mAccount.mId); 271 } 272 273 @Override 274 protected void onPostExecute(Boolean isSecurityHold) { 275 if (!isCancelled()) { 276 if (isSecurityHold) { 277 Intent i = AccountSecurity.actionUpdateSecurityIntent( 278 AccountSetupNames.this, mAccount.mId, false); 279 startActivityForResult(i, REQUEST_SECURITY); 280 } else { 281 finishActivity(); 282 } 283 } 284 } 285 } 286 287 /** 288 * Handle the eventual result from the security update activity 289 * 290 * TODO: If the user doesn't update the security, don't go to the MessageList. 291 */ 292 @Override 293 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 294 switch (requestCode) { 295 case REQUEST_SECURITY: 296 finishActivity(); 297 } 298 super.onActivityResult(requestCode, resultCode, data); 299 } 300 301} 302