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