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