AccountSetupOutgoing.java revision 2b0c619f1edd9fd89dc06bf35d99ece91f415f1e
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.Account; 20import com.android.email.Preferences; 21import com.android.email.R; 22import com.android.email.Utility; 23 24import android.app.Activity; 25import android.content.Intent; 26import android.os.Bundle; 27import android.text.Editable; 28import android.text.TextWatcher; 29import android.text.method.DigitsKeyListener; 30import android.view.View; 31import android.view.ViewGroup; 32import android.view.View.OnClickListener; 33import android.widget.AdapterView; 34import android.widget.ArrayAdapter; 35import android.widget.Button; 36import android.widget.CheckBox; 37import android.widget.CompoundButton; 38import android.widget.EditText; 39import android.widget.Spinner; 40import android.widget.CompoundButton.OnCheckedChangeListener; 41 42import java.net.URI; 43import java.net.URISyntaxException; 44 45public class AccountSetupOutgoing extends Activity implements OnClickListener, 46 OnCheckedChangeListener { 47 private static final String EXTRA_ACCOUNT = "account"; 48 49 private static final String EXTRA_MAKE_DEFAULT = "makeDefault"; 50 51 private static final int smtpPorts[] = { 52 25, 465, 465, 25, 25 53 }; 54 55 private static final String smtpSchemes[] = { 56 "smtp", "smtp+ssl", "smtp+ssl+", "smtp+tls", "smtp+tls+" 57 }; 58 59 private EditText mUsernameView; 60 private EditText mPasswordView; 61 private EditText mServerView; 62 private EditText mPortView; 63 private CheckBox mRequireLoginView; 64 private ViewGroup mRequireLoginSettingsView; 65 private Spinner mSecurityTypeView; 66 private Button mNextButton; 67 private Account mAccount; 68 private boolean mMakeDefault; 69 70 public static void actionOutgoingSettings(Activity fromActivity, Account account, 71 boolean makeDefault) { 72 Intent i = new Intent(fromActivity, AccountSetupOutgoing.class); 73 i.putExtra(EXTRA_ACCOUNT, account); 74 i.putExtra(EXTRA_MAKE_DEFAULT, makeDefault); 75 fromActivity.startActivity(i); 76 } 77 78 public static void actionEditOutgoingSettings(Activity fromActivity, Account account) { 79 Intent i = new Intent(fromActivity, AccountSetupOutgoing.class); 80 i.setAction(Intent.ACTION_EDIT); 81 i.putExtra(EXTRA_ACCOUNT, account); 82 fromActivity.startActivity(i); 83 } 84 85 @Override 86 public void onCreate(Bundle savedInstanceState) { 87 super.onCreate(savedInstanceState); 88 setContentView(R.layout.account_setup_outgoing); 89 90 mUsernameView = (EditText)findViewById(R.id.account_username); 91 mPasswordView = (EditText)findViewById(R.id.account_password); 92 mServerView = (EditText)findViewById(R.id.account_server); 93 mPortView = (EditText)findViewById(R.id.account_port); 94 mRequireLoginView = (CheckBox)findViewById(R.id.account_require_login); 95 mRequireLoginSettingsView = (ViewGroup)findViewById(R.id.account_require_login_settings); 96 mSecurityTypeView = (Spinner)findViewById(R.id.account_security_type); 97 mNextButton = (Button)findViewById(R.id.next); 98 99 mNextButton.setOnClickListener(this); 100 mRequireLoginView.setOnCheckedChangeListener(this); 101 102 SpinnerOption securityTypes[] = { 103 new SpinnerOption(0, getString(R.string.account_setup_incoming_security_none_label)), 104 new SpinnerOption(1, 105 getString(R.string.account_setup_incoming_security_ssl_optional_label)), 106 new SpinnerOption(2, getString(R.string.account_setup_incoming_security_ssl_label)), 107 new SpinnerOption(3, 108 getString(R.string.account_setup_incoming_security_tls_optional_label)), 109 new SpinnerOption(4, getString(R.string.account_setup_incoming_security_tls_label)), 110 }; 111 112 ArrayAdapter<SpinnerOption> securityTypesAdapter = new ArrayAdapter<SpinnerOption>(this, 113 android.R.layout.simple_spinner_item, securityTypes); 114 securityTypesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 115 mSecurityTypeView.setAdapter(securityTypesAdapter); 116 117 /* 118 * Updates the port when the user changes the security type. This allows 119 * us to show a reasonable default which the user can change. 120 */ 121 mSecurityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 122 public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3) { 123 updatePortFromSecurityType(); 124 } 125 126 public void onNothingSelected(AdapterView<?> arg0) { 127 } 128 }); 129 130 /* 131 * Calls validateFields() which enables or disables the Next button 132 * based on the fields' validity. 133 */ 134 TextWatcher validationTextWatcher = new TextWatcher() { 135 public void afterTextChanged(Editable s) { 136 validateFields(); 137 } 138 139 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 140 } 141 142 public void onTextChanged(CharSequence s, int start, int before, int count) { 143 } 144 }; 145 mUsernameView.addTextChangedListener(validationTextWatcher); 146 mPasswordView.addTextChangedListener(validationTextWatcher); 147 mServerView.addTextChangedListener(validationTextWatcher); 148 mPortView.addTextChangedListener(validationTextWatcher); 149 150 /* 151 * Only allow digits in the port field. 152 */ 153 mPortView.setKeyListener(DigitsKeyListener.getInstance("0123456789")); 154 155 mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT); 156 mMakeDefault = (boolean)getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false); 157 158 /* 159 * If we're being reloaded we override the original account with the one 160 * we saved 161 */ 162 if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) { 163 mAccount = (Account)savedInstanceState.getSerializable(EXTRA_ACCOUNT); 164 } 165 166 try { 167 URI uri = new URI(mAccount.getSenderUri()); 168 String username = null; 169 String password = null; 170 if (uri.getUserInfo() != null) { 171 String[] userInfoParts = uri.getUserInfo().split(":", 2); 172 username = userInfoParts[0]; 173 if (userInfoParts.length > 1) { 174 password = userInfoParts[1]; 175 } 176 } 177 178 if (username != null) { 179 mUsernameView.setText(username); 180 mRequireLoginView.setChecked(true); 181 } 182 183 if (password != null) { 184 mPasswordView.setText(password); 185 } 186 187 for (int i = 0; i < smtpSchemes.length; i++) { 188 if (smtpSchemes[i].equals(uri.getScheme())) { 189 SpinnerOption.setSpinnerOptionValue(mSecurityTypeView, i); 190 } 191 } 192 193 if (uri.getHost() != null) { 194 mServerView.setText(uri.getHost()); 195 } 196 197 if (uri.getPort() != -1) { 198 mPortView.setText(Integer.toString(uri.getPort())); 199 } else { 200 updatePortFromSecurityType(); 201 } 202 } catch (URISyntaxException use) { 203 /* 204 * We should always be able to parse our own settings. 205 */ 206 throw new Error(use); 207 } 208 209 validateFields(); 210 } 211 212 @Override 213 public void onSaveInstanceState(Bundle outState) { 214 super.onSaveInstanceState(outState); 215 outState.putSerializable(EXTRA_ACCOUNT, mAccount); 216 } 217 218 /** 219 * Preflight the values in the fields and decide if it makes sense to enable the "next" button 220 * NOTE: Does it make sense to extract & combine with similar code in AccountSetupIncoming? 221 */ 222 private void validateFields() { 223 boolean enabled = 224 Utility.requiredFieldValid(mServerView) && Utility.requiredFieldValid(mPortView); 225 226 if (enabled && mRequireLoginView.isChecked()) { 227 enabled = (Utility.requiredFieldValid(mUsernameView) 228 && Utility.requiredFieldValid(mPasswordView)); 229 } 230 231 if (enabled) { 232 try { 233 URI uri = getUri(); 234 } catch (URISyntaxException use) { 235 enabled = false; 236 } 237 } 238 mNextButton.setEnabled(enabled); 239 Utility.setCompoundDrawablesAlpha(mNextButton, enabled ? 255 : 128); 240 } 241 242 private void updatePortFromSecurityType() { 243 int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value; 244 mPortView.setText(Integer.toString(smtpPorts[securityType])); 245 } 246 247 @Override 248 public void onActivityResult(int requestCode, int resultCode, Intent data) { 249 if (resultCode == RESULT_OK) { 250 if (Intent.ACTION_EDIT.equals(getIntent().getAction())) { 251 mAccount.save(Preferences.getPreferences(this)); 252 finish(); 253 } else { 254 AccountSetupOptions.actionOptions(this, mAccount, mMakeDefault); 255 finish(); 256 } 257 } 258 } 259 260 /** 261 * Attempt to create a URI from the fields provided. Throws URISyntaxException if there's 262 * a problem with the user input. 263 * @return a URI built from the account setup fields 264 */ 265 private URI getUri() throws URISyntaxException { 266 int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value; 267 String userInfo = null; 268 if (mRequireLoginView.isChecked()) { 269 userInfo = mUsernameView.getText().toString().trim() + ":" 270 + mPasswordView.getText().toString().trim(); 271 } 272 URI uri = new URI( 273 smtpSchemes[securityType], 274 userInfo, 275 mServerView.getText().toString().trim(), 276 Integer.parseInt(mPortView.getText().toString().trim()), 277 null, null, null); 278 279 return uri; 280 } 281 282 private void onNext() { 283 try { 284 URI uri = getUri(); 285 mAccount.setSenderUri(uri.toString()); 286 } catch (URISyntaxException use) { 287 /* 288 * It's unrecoverable if we cannot create a URI from components that 289 * we validated to be safe. 290 */ 291 throw new Error(use); 292 } 293 AccountSetupCheckSettings.actionCheckSettings(this, mAccount, false, true); 294 } 295 296 public void onClick(View v) { 297 switch (v.getId()) { 298 case R.id.next: 299 onNext(); 300 break; 301 } 302 } 303 304 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 305 mRequireLoginSettingsView.setVisibility(isChecked ? View.VISIBLE : View.GONE); 306 validateFields(); 307 } 308} 309