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