1 package com.android.email.activity.setup;
2 
3 import android.app.Fragment;
4 import android.content.Context;
5 import android.os.Bundle;
6 import android.os.Parcel;
7 import android.os.Parcelable;
8 
9 import com.android.email.service.EmailServiceUtils;
10 import com.android.email.setup.AuthenticatorSetupIntentHelper;
11 import com.android.emailcommon.provider.Account;
12 import com.android.emailcommon.provider.HostAuth;
13 import com.android.emailcommon.provider.Policy;
14 
15 /**
16  * Headless fragment to hold setup data for the account setup or settings flows
17  */
18 public 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 {
getSetupData()62         public SetupDataFragment getSetupData();
63     }
64 
SetupDataFragment()65     public SetupDataFragment() {
66         mPolicy = null;
67         setAccount(new Account());
68         mEmail = null;
69         mCredentialResults = null;
70     }
71 
72     @Override
onSaveInstanceState(Bundle outState)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
onCreate(Bundle savedInstanceState)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
getFlowMode()104     public int getFlowMode() {
105         return mFlowMode;
106     }
107 
setFlowMode(int flowMode)108     public void setFlowMode(int flowMode) {
109         mFlowMode = flowMode;
110     }
111 
getAccount()112     public Account getAccount() {
113         return mAccount;
114     }
115 
setAccount(Account account)116     public void setAccount(Account account) {
117         mAccount = account;
118         mAccount.setTemporary(true);
119     }
120 
getEmail()121     public String getEmail() {
122         return mEmail;
123     }
124 
setEmail(String email)125     public void setEmail(String email) {
126         mEmail = email;
127         mAccount.mEmailAddress = email;
128         mIncomingCredLoaded = false;
129         mOutgoingCredLoaded = false;
130     }
131 
getCredentialResults()132     public Bundle getCredentialResults() {
133         return mCredentialResults;
134     }
135 
setCredentialResults(Bundle credentialResults)136     public void setCredentialResults(Bundle credentialResults) {
137         mCredentialResults = credentialResults;
138         mIncomingCredLoaded = false;
139         mOutgoingCredLoaded = false;
140     }
141 
isIncomingCredLoaded()142     public boolean isIncomingCredLoaded() {
143         return mIncomingCredLoaded;
144     }
145 
setIncomingCredLoaded(boolean incomingCredLoaded)146     public void setIncomingCredLoaded(boolean incomingCredLoaded) {
147         mIncomingCredLoaded = incomingCredLoaded;
148     }
149 
isOutgoingCredLoaded()150     public boolean isOutgoingCredLoaded() {
151         return mOutgoingCredLoaded;
152     }
153 
setOutgoingCredLoaded(boolean outgoingCredLoaded)154     public void setOutgoingCredLoaded(boolean outgoingCredLoaded) {
155         mOutgoingCredLoaded = outgoingCredLoaded;
156     }
157 
getPolicy()158     public synchronized Policy getPolicy() {
159         return mPolicy;
160     }
161 
setPolicy(Policy policy)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      */
getIncomingServiceInfo(Context context)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      */
getIncomingProtocol()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      */
getIncomingProtocol(Context context)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 
setIncomingProtocol(final Context context, final String protocol)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 
getClientCert(Context context)211     public String getClientCert(Context context) {
212         final HostAuth recvAuth = mAccount.getOrCreateHostAuthRecv(context);
213         return recvAuth.mClientCertAlias;
214     }
215 
getAmProtocol()216     public String getAmProtocol() {
217         return mAmProtocol;
218     }
219 
setAmProtocol(String amProtocol)220     public void setAmProtocol(String amProtocol) {
221         mAmProtocol = amProtocol;
222     }
223 
224     // Parcelable methods
225     @Override
describeContents()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
writeToParcel(Parcel dest, int flags)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 
SetupDataFragment(Parcel in)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
toString()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