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