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 { 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