SetupDataFragment.java revision 06415a635f5f01d8e1620b29f44d68dc4dfdf435
1package com.android.email.activity.setup;
2
3import android.app.Fragment;
4import android.content.Context;
5import android.os.Bundle;
6import android.os.Parcel;
7import android.os.Parcelable;
8
9import com.android.email.service.EmailServiceUtils;
10import com.android.emailcommon.provider.Account;
11import com.android.emailcommon.provider.HostAuth;
12import com.android.emailcommon.provider.Policy;
13
14/**
15 * Headless fragment to hold setup data for the account setup or settings flows
16 */
17public class SetupDataFragment extends Fragment implements Parcelable {
18    // The "extra" name for the Bundle saved with SetupData
19    public static final String EXTRA_SETUP_DATA = "com.android.email.setupdata";
20
21    // NORMAL is the standard entry from the Email app; EAS and POP_IMAP are used when entering via
22    // Settings -> Accounts
23    public static final int FLOW_MODE_UNSPECIFIED = -1;
24    public static final int FLOW_MODE_NORMAL = 0;
25    public static final int FLOW_MODE_ACCOUNT_MANAGER = 1;
26    public static final int FLOW_MODE_EDIT = 3;
27    public static final int FLOW_MODE_FORCE_CREATE = 4;
28    // The following two modes are used to "pop the stack" and return from the setup flow.  We
29    // either return to the caller (if we're in an account type flow) or go to the message list
30    // TODO: figure out if we still care about these
31    public static final int FLOW_MODE_RETURN_TO_CALLER = 5;
32    public static final int FLOW_MODE_RETURN_TO_MESSAGE_LIST = 6;
33    public static final int FLOW_MODE_RETURN_NO_ACCOUNTS_RESULT = 7;
34    public static final int FLOW_MODE_NO_ACCOUNTS = 8;
35
36    // Mode bits for AccountSetupCheckSettings, indicating the type of check requested
37    public static final int CHECK_INCOMING = 1;
38    public static final int CHECK_OUTGOING = 2;
39    public static final int CHECK_AUTODISCOVER = 4;
40
41    private static final String SAVESTATE_FLOWMODE = "SetupDataFragment.flowMode";
42    private static final String SAVESTATE_ACCOUNT = "SetupDataFragment.account";
43    private static final String SAVESTATE_EMAIL = "SetupDataFragment.email";
44    private static final String SAVESTATE_CREDENTIAL = "SetupDataFragment.credential";
45    private static final String SAVESTATE_INCOMING_LOADED = "SetupDataFragment.incomingLoaded";
46    private static final String SAVESTATE_OUTGOING_LOADED = "SetupDataFragment.outgoingLoaded";
47    private static final String SAVESTATE_POLICY = "SetupDataFragment.policy";
48    private static final String SAVESTATE_INCOMING_PROTOCOL = "SetupDataFragment.incomingProtocol";
49    private static final String SAVESTATE_AM_PROTOCOL = "SetupDataFragment.amProtocol";
50
51    // All access will be through getters/setters
52    private int mFlowMode = FLOW_MODE_NORMAL;
53    private Account mAccount;
54    private String mEmail;
55    private Bundle mCredentialResults;
56    // These are used to track whether we've preloaded the login credentials into incoming/outgoing
57    // settings. Set them to 'true' by default, and false when we change the credentials or email
58    private boolean mIncomingCredLoaded = true;
59    private boolean mOutgoingCredLoaded = true;
60    // This is accessed off-thread in AccountCheckSettingsFragment
61    private volatile Policy mPolicy;
62    // Cache incoming protocol and service info here
63    private EmailServiceUtils.EmailServiceInfo mIncomingServiceInfo;
64    private String mIncomingProtocol;
65    // Protocol the user chose in the account manager "Add an account" screen
66    private String mAmProtocol;
67
68    public interface SetupDataContainer {
69        public SetupDataFragment getSetupData();
70    }
71
72    public SetupDataFragment() {
73        mPolicy = null;
74        setAccount(new Account());
75        mEmail = null;
76        mCredentialResults = null;
77    }
78
79    @Override
80    public void onSaveInstanceState(Bundle outState) {
81        super.onSaveInstanceState(outState);
82        outState.putInt(SAVESTATE_FLOWMODE, mFlowMode);
83        outState.putParcelable(SAVESTATE_ACCOUNT, mAccount);
84        outState.putString(SAVESTATE_EMAIL, mEmail);
85        outState.putParcelable(SAVESTATE_CREDENTIAL, mCredentialResults);
86        outState.putBoolean(SAVESTATE_INCOMING_LOADED, mIncomingCredLoaded);
87        outState.putBoolean(SAVESTATE_OUTGOING_LOADED, mOutgoingCredLoaded);
88        outState.putParcelable(SAVESTATE_POLICY, mPolicy);
89        outState.putString(SAVESTATE_INCOMING_PROTOCOL, mIncomingProtocol);
90        outState.putString(SAVESTATE_AM_PROTOCOL, mAmProtocol);
91    }
92
93    @Override
94    public void onCreate(Bundle savedInstanceState) {
95        super.onCreate(savedInstanceState);
96        if (savedInstanceState != null) {
97            mFlowMode = savedInstanceState.getInt(SAVESTATE_FLOWMODE);
98            setAccount((Account) savedInstanceState.getParcelable(SAVESTATE_ACCOUNT));
99            mEmail = savedInstanceState.getString(SAVESTATE_EMAIL);
100            mCredentialResults = savedInstanceState.getParcelable(SAVESTATE_CREDENTIAL);
101            mIncomingCredLoaded = savedInstanceState.getBoolean(SAVESTATE_INCOMING_LOADED);
102            mOutgoingCredLoaded = savedInstanceState.getBoolean(SAVESTATE_OUTGOING_LOADED);
103            mPolicy = savedInstanceState.getParcelable(SAVESTATE_POLICY);
104            mIncomingProtocol = savedInstanceState.getString(SAVESTATE_INCOMING_PROTOCOL);
105            mAmProtocol = savedInstanceState.getString(SAVESTATE_AM_PROTOCOL);
106        }
107        setRetainInstance(true);
108    }
109
110    // Getters and setters
111    public int getFlowMode() {
112        return mFlowMode;
113    }
114
115    public void setFlowMode(int flowMode) {
116        mFlowMode = flowMode;
117    }
118
119    public Account getAccount() {
120        return mAccount;
121    }
122
123    public void setAccount(Account account) {
124        mAccount = account;
125        mAccount.setTemporary(true);
126    }
127
128    public String getEmail() {
129        return mEmail;
130    }
131
132    public void setEmail(String email) {
133        mEmail = email;
134        mAccount.mEmailAddress = email;
135        mIncomingCredLoaded = false;
136        mOutgoingCredLoaded = false;
137    }
138
139    public Bundle getCredentialResults() {
140        return mCredentialResults;
141    }
142
143    public void setCredentialResults(Bundle credentialResults) {
144        mCredentialResults = credentialResults;
145        mIncomingCredLoaded = false;
146        mOutgoingCredLoaded = false;
147    }
148
149    public boolean isIncomingCredLoaded() {
150        return mIncomingCredLoaded;
151    }
152
153    public void setIncomingCredLoaded(boolean incomingCredLoaded) {
154        mIncomingCredLoaded = incomingCredLoaded;
155    }
156
157    public boolean isOutgoingCredLoaded() {
158        return mOutgoingCredLoaded;
159    }
160
161    public void setOutgoingCredLoaded(boolean outgoingCredLoaded) {
162        mOutgoingCredLoaded = outgoingCredLoaded;
163    }
164
165    public synchronized Policy getPolicy() {
166        return mPolicy;
167    }
168
169    public synchronized void setPolicy(Policy policy) {
170        mPolicy = policy;
171    }
172
173    /**
174     * Retrieve the service info for the incoming protocol
175     * @param context For resolving the service info, and possibly loading the {@link HostAuth}
176     * @return service info object
177     */
178    public EmailServiceUtils.EmailServiceInfo getIncomingServiceInfo(Context context) {
179        if (mIncomingServiceInfo == null) {
180            mIncomingServiceInfo = EmailServiceUtils.getServiceInfo(context,
181                    getIncomingProtocol(context));
182        }
183        return mIncomingServiceInfo;
184    }
185
186    /**
187     * Retrieve the protocol as previously set in setIncomingProtocol, but don't attempt to look at
188     * {@link #mAccount#hostAuthRecv }
189     * @return Protocol string
190     */
191    public String getIncomingProtocol() {
192        return mIncomingProtocol;
193    }
194
195    /**
196     * Retrieve the protocol as previously set in setIncomingProtocol, or from
197     * {@link #mAccount#hostAuthRecv}. Try not to call this on the main thread if it's unlikely that
198     * the hostauth isn't already loaded.
199     * @param context context to possibly load the {@link HostAuth} from the provider
200     * @return Protocol string
201     */
202    public String getIncomingProtocol(Context context) {
203        if (mIncomingProtocol != null) {
204            return mIncomingProtocol;
205        }
206
207        final HostAuth recvAuth = mAccount.getOrCreateHostAuthRecv(context);
208        return recvAuth.mProtocol;
209    }
210
211    public void setIncomingProtocol(final Context context, final String protocol) {
212        final HostAuth recvAuth = mAccount.getOrCreateHostAuthRecv(context);
213        recvAuth.setConnection(protocol, recvAuth.mAddress, recvAuth.mPort, recvAuth.mFlags);
214        mIncomingProtocol = protocol;
215        mIncomingServiceInfo = null;
216    }
217
218    public String getClientCert(Context context) {
219        final HostAuth recvAuth = mAccount.getOrCreateHostAuthRecv(context);
220        return recvAuth.mClientCertAlias;
221    }
222
223    public String getAmProtocol() {
224        return mAmProtocol;
225    }
226
227    public void setAmProtocol(String amProtocol) {
228        mAmProtocol = amProtocol;
229    }
230
231    // Parcelable methods
232    @Override
233    public int describeContents() {
234        return 0;
235    }
236
237    public static final Parcelable.Creator<SetupDataFragment> CREATOR =
238            new Parcelable.Creator<SetupDataFragment>() {
239                @Override
240                public SetupDataFragment createFromParcel(Parcel in) {
241                    return new SetupDataFragment(in);
242                }
243
244                @Override
245                public SetupDataFragment[] newArray(int size) {
246                    return new SetupDataFragment[size];
247                }
248            };
249
250    @Override
251    public void writeToParcel(Parcel dest, int flags) {
252        dest.writeInt(mFlowMode);
253        dest.writeParcelable(mAccount, 0);
254        dest.writeString(mEmail);
255        dest.writeParcelable(mCredentialResults, 0);
256        dest.writeBooleanArray(new boolean[] {mIncomingCredLoaded, mOutgoingCredLoaded});
257        dest.writeParcelable(mPolicy, 0);
258    }
259
260    public SetupDataFragment(Parcel in) {
261        final ClassLoader loader = getClass().getClassLoader();
262        mFlowMode = in.readInt();
263        setAccount((Account) in.readParcelable(loader));
264        mEmail = in.readString();
265        mCredentialResults = in.readParcelable(loader);
266        final boolean[] credsLoaded = in.createBooleanArray();
267        mIncomingCredLoaded = credsLoaded[0];
268        mOutgoingCredLoaded = credsLoaded[1];
269        mPolicy = in.readParcelable(loader);
270    }
271
272    @Override
273    public String toString() {
274        final StringBuilder sb = new StringBuilder("SetupData");
275        sb.append(":acct=");
276        sb.append(mAccount == null ? "none" :mAccount.mId);
277        if (mEmail != null) {
278            sb.append(":user=");
279            sb.append(mEmail);
280        }
281        if (mCredentialResults != null) {
282            sb.append(":cred=");
283            sb.append(mCredentialResults.toString());
284        }
285        sb.append(":policy=");
286        sb.append(mPolicy == null ? "none" : "exists");
287        return sb.toString();
288    }
289
290}
291