AccountSetupExchange.java revision 60c7502b6777be550aaace9e9d780a9f84c8b03f
1/* 2 * Copyright (C) 2009 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.R; 20import com.android.email.Utility; 21import com.android.email.provider.EmailContent; 22import com.android.email.provider.EmailContent.Account; 23 24import android.app.Activity; 25import android.content.Intent; 26import android.os.Bundle; 27import android.text.Editable; 28import android.text.TextWatcher; 29import android.view.View; 30import android.view.View.OnClickListener; 31import android.widget.Button; 32import android.widget.CheckBox; 33import android.widget.CompoundButton; 34import android.widget.EditText; 35import android.widget.CompoundButton.OnCheckedChangeListener; 36 37import java.net.URI; 38import java.net.URISyntaxException; 39 40/** 41 * Provides generic setup for Exchange accounts. The following fields are supported: 42 * 43 * Email Address (from previous setup screen) 44 * Server 45 * Domain 46 * Requires SSL? 47 * User (login) 48 * Password 49 */ 50public class AccountSetupExchange extends Activity implements OnClickListener, 51 OnCheckedChangeListener { 52 private static final String EXTRA_ACCOUNT = "account"; 53 private static final String EXTRA_MAKE_DEFAULT = "makeDefault"; 54 private static final String EXTRA_EAS_FLOW = "easFlow"; 55 56 private EditText mUsernameView; 57 private EditText mPasswordView; 58 private EditText mServerView; 59 private CheckBox mSslSecurityView; 60 private CheckBox mTrustCertificatesView; 61 62 private Button mNextButton; 63 private Account mAccount; 64 private boolean mMakeDefault; 65 66 public static void actionIncomingSettings(Activity fromActivity, Account account, 67 boolean makeDefault, boolean easFlowMode) { 68 Intent i = new Intent(fromActivity, AccountSetupExchange.class); 69 i.putExtra(EXTRA_ACCOUNT, account); 70 i.putExtra(EXTRA_MAKE_DEFAULT, makeDefault); 71 i.putExtra(EXTRA_EAS_FLOW, easFlowMode); 72 fromActivity.startActivity(i); 73 } 74 75 public static void actionEditIncomingSettings(Activity fromActivity, Account account) 76 { 77 Intent i = new Intent(fromActivity, AccountSetupExchange.class); 78 i.setAction(Intent.ACTION_EDIT); 79 i.putExtra(EXTRA_ACCOUNT, account); 80 fromActivity.startActivity(i); 81 } 82 83 /** 84 * For now, we'll simply replicate outgoing, for the purpose of satisfying the 85 * account settings flow. 86 */ 87 public static void actionEditOutgoingSettings(Activity fromActivity, Account account) 88 { 89 Intent i = new Intent(fromActivity, AccountSetupExchange.class); 90 i.setAction(Intent.ACTION_EDIT); 91 i.putExtra(EXTRA_ACCOUNT, account); 92 fromActivity.startActivity(i); 93 } 94 95 @Override 96 public void onCreate(Bundle savedInstanceState) { 97 super.onCreate(savedInstanceState); 98 setContentView(R.layout.account_setup_exchange); 99 100 mUsernameView = (EditText) findViewById(R.id.account_username); 101 mPasswordView = (EditText) findViewById(R.id.account_password); 102 mServerView = (EditText) findViewById(R.id.account_server); 103 mSslSecurityView = (CheckBox) findViewById(R.id.account_ssl); 104 mSslSecurityView.setOnCheckedChangeListener(this); 105 mTrustCertificatesView = (CheckBox) findViewById(R.id.account_trust_certificates); 106 107 mNextButton = (Button)findViewById(R.id.next); 108 mNextButton.setOnClickListener(this); 109 110 /* 111 * Calls validateFields() which enables or disables the Next button 112 * based on the fields' validity. 113 */ 114 TextWatcher validationTextWatcher = new TextWatcher() { 115 public void afterTextChanged(Editable s) { 116 validateFields(); 117 } 118 119 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 120 } 121 122 public void onTextChanged(CharSequence s, int start, int before, int count) { 123 } 124 }; 125 mUsernameView.addTextChangedListener(validationTextWatcher); 126 mPasswordView.addTextChangedListener(validationTextWatcher); 127 mServerView.addTextChangedListener(validationTextWatcher); 128 129 mAccount = (EmailContent.Account) getIntent().getParcelableExtra(EXTRA_ACCOUNT); 130 mMakeDefault = getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false); 131 132 /* 133 * If we're being reloaded we override the original account with the one 134 * we saved 135 */ 136 if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) { 137 mAccount = (EmailContent.Account) savedInstanceState.getParcelable(EXTRA_ACCOUNT); 138 } 139 140 try { 141 URI uri = new URI(mAccount.getStoreUri(this)); 142 String username = null; 143 String password = null; 144 if (uri.getUserInfo() != null) { 145 String[] userInfoParts = uri.getUserInfo().split(":", 2); 146 username = userInfoParts[0]; 147 if (userInfoParts.length > 1) { 148 password = userInfoParts[1]; 149 } 150 } 151 152 if (username != null) { 153 // Add a backslash to the start of the username as an affordance 154 mUsernameView.setText("\\" + username); 155 } 156 157 if (password != null) { 158 mPasswordView.setText(password); 159 } 160 161 if (uri.getScheme().startsWith("eas")) { 162 // any other setup from mAccount can go here 163 } else { 164 throw new Error("Unknown account type: " + mAccount.getStoreUri(this)); 165 } 166 167 if (uri.getHost() != null) { 168 mServerView.setText(uri.getHost()); 169 } 170 171 boolean ssl = uri.getScheme().contains("ssl"); 172 mSslSecurityView.setChecked(ssl); 173 mTrustCertificatesView.setChecked(uri.getScheme().contains("tssl")); 174 mTrustCertificatesView.setVisibility(ssl ? View.VISIBLE : View.GONE); 175 176 } catch (URISyntaxException use) { 177 /* 178 * We should always be able to parse our own settings. 179 */ 180 throw new Error(use); 181 } 182 183 validateFields(); 184 } 185 186 @Override 187 public void onSaveInstanceState(Bundle outState) { 188 super.onSaveInstanceState(outState); 189 outState.putParcelable(EXTRA_ACCOUNT, mAccount); 190 } 191 192 /** 193 * Check the values in the fields and decide if it makes sense to enable the "next" button 194 * NOTE: Does it make sense to extract & combine with similar code in AccountSetupIncoming? 195 */ 196 private void validateFields() { 197 boolean enabled = Utility.requiredFieldValid(mUsernameView) 198 && Utility.requiredFieldValid(mPasswordView) 199 && Utility.requiredFieldValid(mServerView); 200 if (enabled) { 201 try { 202 URI uri = getUri(); 203 } catch (URISyntaxException use) { 204 enabled = false; 205 } 206 } 207 mNextButton.setEnabled(enabled); 208 Utility.setCompoundDrawablesAlpha(mNextButton, enabled ? 255 : 128); 209 } 210 211 @Override 212 public void onActivityResult(int requestCode, int resultCode, Intent data) { 213 if (resultCode == RESULT_OK) { 214 if (Intent.ACTION_EDIT.equals(getIntent().getAction())) { 215 // TODO Review carefully to make sure this is bulletproof 216 if (mAccount.isSaved()) { 217 mAccount.update(this, mAccount.toContentValues()); 218 } else { 219 mAccount.save(this); 220 } 221 finish(); 222 } else { 223 // Go directly to end - there is no 2nd screen for incoming settings 224 boolean easFlowMode = getIntent().getBooleanExtra(EXTRA_EAS_FLOW, false); 225 AccountSetupOptions.actionOptions(this, mAccount, mMakeDefault, easFlowMode); 226 finish(); 227 } 228 } 229 } 230 231 /** 232 * Attempt to create a URI from the fields provided. Throws URISyntaxException if there's 233 * a problem with the user input. 234 * @return a URI built from the account setup fields 235 */ 236 private URI getUri() throws URISyntaxException { 237 boolean sslRequired = mSslSecurityView.isChecked(); 238 boolean trustCertificates = mTrustCertificatesView.isChecked(); 239 String scheme = (sslRequired) ? (trustCertificates ? "eas+tssl+" : "eas+ssl+") : "eas"; 240 String userName = mUsernameView.getText().toString().trim(); 241 // Remove a leading backslash, if there is one, since we now automatically put one at 242 // the start of the username field 243 if (userName.startsWith("\\")) { 244 userName = userName.substring(1); 245 } 246 String userInfo = userName + ":" + mPasswordView.getText().toString().trim(); 247 String host = mServerView.getText().toString().trim(); 248 String path = null; 249 250 URI uri = new URI( 251 scheme, 252 userInfo, 253 host, 254 0, 255 path, 256 null, 257 null); 258 259 return uri; 260 } 261 262 /** 263 * Note, in EAS, store & sender are the same, so we always populate them together 264 */ 265 private void onNext() { 266 try { 267 URI uri = getUri(); 268 mAccount.setStoreUri(this, uri.toString()); 269 mAccount.setSenderUri(this, uri.toString()); 270 } catch (URISyntaxException use) { 271 /* 272 * It's unrecoverable if we cannot create a URI from components that 273 * we validated to be safe. 274 */ 275 throw new Error(use); 276 } 277 278 AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, false); 279 } 280 281 public void onClick(View v) { 282 switch (v.getId()) { 283 case R.id.next: 284 onNext(); 285 break; 286 } 287 } 288 289 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 290 if (buttonView.getId() == R.id.account_ssl) { 291 mTrustCertificatesView.setVisibility(isChecked ? View.VISIBLE : View.GONE); 292 } 293 } 294} 295