AccountSetupExchange.java revision 1a5e1e159352f6e21bde878eebca3e3a1896045c
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.SecurityPolicy.PolicySet;
21import com.android.email.Utility;
22import com.android.email.provider.EmailContent.Account;
23import com.android.email.provider.EmailContent.HostAuth;
24import com.android.email.service.EmailServiceProxy;
25
26import android.app.Activity;
27import android.content.Intent;
28import android.os.Bundle;
29import android.os.Parcelable;
30import android.view.View;
31import android.view.View.OnClickListener;
32import android.widget.Button;
33
34/**
35 * Provides generic setup for Exchange accounts.  The following fields are supported:
36 *
37 *  Email Address   (from previous setup screen)
38 *  Server
39 *  Domain
40 *  Requires SSL?
41 *  User (login)
42 *  Password
43 *
44 * There are two primary paths through this activity:
45 *   Edit existing:
46 *     Load existing values from account into fields
47 *     When user clicks 'next':
48 *       Confirm not a duplicate account
49 *       Try new values (check settings)
50 *       If new values are OK:
51 *         Write new values (save to provider)
52 *         finish() (pop to previous)
53 *
54 *   Creating New:
55 *     Try Auto-discover to get details from server
56 *     If Auto-discover reports an authentication failure:
57 *       finish() (pop to previous, to re-enter username & password)
58 *     If Auto-discover succeeds:
59 *       write server's account details into account
60 *     Load values from account into fields
61 *     Confirm not a duplicate account
62 *     Try new values (check settings)
63 *     If new values are OK:
64 *       Write new values (save to provider)
65 *       Proceed to options screen
66 *       finish() (removes self from back stack)
67 *
68 * TODO: The manifest for this activity has it ignore config changes, because
69 * we don't want to restart on every orientation - this would launch autodiscover again.
70 * Do not attempt to define orientation-specific resources, they won't be loaded.
71 * What we really need here is a more "sticky" way to prevent that problem.
72 */
73public class AccountSetupExchange extends AccountSetupActivity
74        implements OnClickListener, AccountSetupExchangeFragment.Callback {
75
76    /* package */ AccountSetupExchangeFragment mFragment;
77    private Button mNextButton;
78
79    public static void actionIncomingSettings(Activity fromActivity, int mode, Account acct) {
80        SetupData.init(mode, acct);
81        fromActivity.startActivity(new Intent(fromActivity, AccountSetupExchange.class));
82    }
83
84    public static void actionEditIncomingSettings(Activity fromActivity, int mode, Account acct) {
85        actionIncomingSettings(fromActivity, mode, acct);
86    }
87
88    /**
89     * For now, we'll simply replicate outgoing, for the purpose of satisfying the
90     * account settings flow.
91     */
92    public static void actionEditOutgoingSettings(Activity fromActivity, int mode, Account acct) {
93        actionIncomingSettings(fromActivity, mode, acct);
94    }
95
96    @Override
97    public void onCreate(Bundle savedInstanceState) {
98        super.onCreate(savedInstanceState);
99        setContentView(R.layout.account_setup_exchange);
100
101        mFragment = (AccountSetupExchangeFragment) findFragmentById(R.id.setup_exchange_fragment);
102        mNextButton = (Button)findViewById(R.id.next);
103        mNextButton.setOnClickListener(this);
104
105        mFragment.setCallback(this);
106
107        startAutoDiscover();
108    }
109
110    /**
111     * If the conditions are right, launch the autodiscover activity.  If it succeeds (even
112     * partially) it will prefill the setup fields and we can proceed as if the user entered them.
113     *
114     * Conditions for skipping:
115     *  Editing existing account
116     *  AutoDiscover blocked (used for unit testing only)
117     *  Username or password not entered yet
118     */
119    private void startAutoDiscover() {
120        if (SetupData.getFlowMode() == SetupData.FLOW_MODE_EDIT
121                || !SetupData.isAllowAutodiscover()) {
122            return;
123        }
124
125        Account account = SetupData.getAccount();
126        // If we've got a username and password and we're NOT editing, try autodiscover
127        String username = account.mHostAuthRecv.mLogin;
128        String password = account.mHostAuthRecv.mPassword;
129        Intent intent = getIntent();
130        if (username != null && password != null) {
131            AccountSetupCheckSettings.actionAutoDiscover(this, account.mEmailAddress, password);
132        }
133    }
134
135    /**
136     * There are three cases handled here, so we split out into separate sections.
137     * 1.  Validate existing account (edit)
138     * 2.  Validate new account
139     * 3.  Autodiscover for new account
140     *
141     * For each case, there are two or more paths for success or failure.
142     */
143    @Override
144    public void onActivityResult(int requestCode, int resultCode, Intent data) {
145        if (requestCode == AccountSetupCheckSettings.REQUEST_CODE_VALIDATE) {
146            if (SetupData.getFlowMode() == SetupData.FLOW_MODE_EDIT) {
147                doActivityResultValidateExistingAccount(resultCode, data);
148            } else {
149                doActivityResultValidateNewAccount(resultCode, data);
150            }
151        } else if (requestCode == AccountSetupCheckSettings.REQUEST_CODE_AUTO_DISCOVER) {
152            doActivityResultAutoDiscoverNewAccount(resultCode, data);
153        }
154    }
155
156    /**
157     * Process activity result when validating existing account.  If OK, save and finish;
158     * otherwise simply remain in activity for further editing.
159     */
160    private void doActivityResultValidateExistingAccount(int resultCode, Intent data) {
161        if (resultCode == RESULT_OK) {
162            mFragment.saveSettingsAfterEdit();
163            finish();
164        }
165    }
166
167    /**
168     * Process activity result when validating new account
169     */
170    private void doActivityResultValidateNewAccount(int resultCode, Intent data) {
171        if (resultCode == RESULT_OK) {
172            // Go directly to next screen
173            PolicySet ps = null;
174            if ((data != null) && data.hasExtra(EmailServiceProxy.VALIDATE_BUNDLE_POLICY_SET)) {
175                ps = (PolicySet)data.getParcelableExtra(
176                        EmailServiceProxy.VALIDATE_BUNDLE_POLICY_SET);
177            }
178            AccountSetupOptions.actionOptions(this);
179            finish();
180        } else if (resultCode == AccountSetupCheckSettings.RESULT_SECURITY_REQUIRED_USER_CANCEL) {
181            finish();
182        }
183        // else (resultCode not OK) - just return into this activity for further editing
184    }
185
186    /**
187     * Process activity result when provisioning new account via autodiscovery
188     */
189    private void doActivityResultAutoDiscoverNewAccount(int resultCode, Intent data) {
190        // If authentication failed, exit immediately (to re-enter credentials)
191        if (resultCode == AccountSetupCheckSettings.RESULT_AUTO_DISCOVER_AUTH_FAILED) {
192            finish();
193            return;
194        }
195
196        // If data was returned, populate the account & populate the UI fields and validate it
197        if (data != null) {
198            Parcelable p = data.getParcelableExtra("HostAuth");
199            if (p != null) {
200                HostAuth hostAuth = (HostAuth)p;
201                boolean valid = mFragment.setHostAuthFromAutodiscover(hostAuth);
202                if (valid) {
203                    // "click" next to launch server verification
204                    mFragment.onNext();
205                }
206            }
207        }
208        // Otherwise, proceed into this activity for manual setup
209    }
210
211    public void onClick(View v) {
212        switch (v.getId()) {
213            case R.id.next:
214                mFragment.onNext();
215                break;
216        }
217    }
218
219    /**
220     * Implements AccountServerBaseFragment.Callback
221     */
222    public void onProceedNext(int checkMode) {
223        AccountSetupCheckSettings.actionCheckSettings(this, checkMode);
224    }
225
226    /**
227     * Implements AccountServerBaseFragment.Callback
228     */
229    public void onEnableProceedButtons(boolean enabled) {
230        mNextButton.setEnabled(enabled);
231        // Dim the next button's icon to 50% if the button is disabled.
232        // TODO this can probably be done with a stateful drawable. (check android:state_enabled)
233        Utility.setCompoundDrawablesAlpha(mNextButton, enabled ? 255 : 128);
234    }
235}
236