Fix OAuth when changing credentials from settings

b/15521401

Change-Id: I7909389943c8e3eefbef0699f1c7c9c338282ca5
This commit is contained in:
Tony Mantler 2014-06-09 15:28:11 -07:00
parent 0f1d3a8f11
commit 994c282d80
4 changed files with 57 additions and 26 deletions

View File

@ -149,6 +149,10 @@ public final class Account extends EmailContent implements Parcelable {
public transient HostAuth mHostAuthSend; public transient HostAuth mHostAuthSend;
public transient Policy mPolicy; public transient Policy mPolicy;
// Marks this account as being a temporary entry, so we know to use it directly and not go
// through the database or any caches
private transient boolean mTemporary;
public static final int CONTENT_ID_COLUMN = 0; public static final int CONTENT_ID_COLUMN = 0;
public static final int CONTENT_DISPLAY_NAME_COLUMN = 1; public static final int CONTENT_DISPLAY_NAME_COLUMN = 1;
public static final int CONTENT_EMAIL_ADDRESS_COLUMN = 2; public static final int CONTENT_EMAIL_ADDRESS_COLUMN = 2;
@ -253,6 +257,14 @@ public final class Account extends EmailContent implements Parcelable {
mPingDuration = cursor.getLong(CONTENT_PING_DURATION_COLUMN); mPingDuration = cursor.getLong(CONTENT_PING_DURATION_COLUMN);
} }
public boolean isTemporary() {
return mTemporary;
}
public void setTemporary(boolean temporary) {
mTemporary = temporary;
}
private static long getId(Uri u) { private static long getId(Uri u) {
return Long.parseLong(u.getPathSegments().get(1)); return Long.parseLong(u.getPathSegments().get(1));
} }

View File

@ -71,7 +71,7 @@ public class SetupDataFragment extends Fragment implements Parcelable {
public SetupDataFragment() { public SetupDataFragment() {
mPolicy = null; mPolicy = null;
mAccount = new Account(); setAccount(new Account());
mEmail = null; mEmail = null;
mCredentialResults = null; mCredentialResults = null;
} }
@ -83,7 +83,7 @@ public class SetupDataFragment extends Fragment implements Parcelable {
public SetupDataFragment(int flowMode, Account account) { public SetupDataFragment(int flowMode, Account account) {
this(flowMode); this(flowMode);
mAccount = account; setAccount(account);
} }
@Override @Override
@ -105,7 +105,7 @@ public class SetupDataFragment extends Fragment implements Parcelable {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (savedInstanceState != null) { if (savedInstanceState != null) {
mFlowMode = savedInstanceState.getInt(SAVESTATE_FLOWMODE); mFlowMode = savedInstanceState.getInt(SAVESTATE_FLOWMODE);
mAccount = savedInstanceState.getParcelable(SAVESTATE_ACCOUNT); setAccount((Account) savedInstanceState.getParcelable(SAVESTATE_ACCOUNT));
mEmail = savedInstanceState.getString(SAVESTATE_EMAIL); mEmail = savedInstanceState.getString(SAVESTATE_EMAIL);
mCredentialResults = savedInstanceState.getParcelable(SAVESTATE_CREDENTIAL); mCredentialResults = savedInstanceState.getParcelable(SAVESTATE_CREDENTIAL);
mIncomingCredLoaded = savedInstanceState.getBoolean(SAVESTATE_INCOMING_LOADED); mIncomingCredLoaded = savedInstanceState.getBoolean(SAVESTATE_INCOMING_LOADED);
@ -132,6 +132,7 @@ public class SetupDataFragment extends Fragment implements Parcelable {
public void setAccount(Account account) { public void setAccount(Account account) {
mAccount = account; mAccount = account;
mAccount.setTemporary(true);
} }
public String getEmail() { public String getEmail() {
@ -269,7 +270,7 @@ public class SetupDataFragment extends Fragment implements Parcelable {
public SetupDataFragment(Parcel in) { public SetupDataFragment(Parcel in) {
final ClassLoader loader = getClass().getClassLoader(); final ClassLoader loader = getClass().getClassLoader();
mFlowMode = in.readInt(); mFlowMode = in.readInt();
mAccount = in.readParcelable(loader); setAccount((Account) in.readParcelable(loader));
mEmail = in.readString(); mEmail = in.readString();
mCredentialResults = in.readParcelable(loader); mCredentialResults = in.readParcelable(loader);
final boolean[] credsLoaded = in.createBooleanArray(); final boolean[] credsLoaded = in.createBooleanArray();

View File

@ -77,6 +77,7 @@ public abstract class Store {
* a critical problem. However, it is something we should consider fixing. * a critical problem. However, it is something we should consider fixing.
* *
* @param account The account of the store. * @param account The account of the store.
* @param context For all the usual context-y stuff
* @return an initialized store of the appropriate class * @return an initialized store of the appropriate class
* @throws MessagingException If the store cannot be obtained or if the account is invalid. * @throws MessagingException If the store cannot be obtained or if the account is invalid.
*/ */
@ -89,27 +90,43 @@ public abstract class Store {
HostAuth hostAuth = account.getOrCreateHostAuthRecv(context); HostAuth hostAuth = account.getOrCreateHostAuthRecv(context);
// An existing account might have been deleted // An existing account might have been deleted
if (hostAuth == null) return null; if (hostAuth == null) return null;
Store store = sStores.get(hostAuth); if (!account.isTemporary()) {
if (store == null) { Store store = sStores.get(hostAuth);
Context appContext = context.getApplicationContext(); if (store == null) {
Class<? extends Store> klass = sStoreClasses.get(hostAuth.mProtocol); store = createInstanceInternal(account, context, true);
if (klass == null) { } else {
klass = ServiceStore.class; // Make sure the account object is up to date (according to the caller, at least)
} store.mAccount = account;
try {
// invoke "newInstance" class method
Method m = klass.getMethod("newInstance", Account.class, Context.class);
store = (Store)m.invoke(null, account, appContext);
} catch (Exception e) {
LogUtils.d(Logging.LOG_TAG, String.format(
"exception %s invoking method %s#newInstance(Account, Context) for %s",
e.toString(), klass.getName(), account.mDisplayName));
throw new MessagingException("Can't instantiate Store for " + account.mDisplayName);
}
// Don't cache this unless it's we've got a saved HostAuth
if (hostAuth.mId != EmailContent.NOT_SAVED) {
sStores.put(hostAuth, store);
} }
return store;
} else {
return createInstanceInternal(account, context, false);
}
}
private synchronized static Store createInstanceInternal(final Account account,
final Context context, final boolean cacheInstance)
throws MessagingException {
Context appContext = context.getApplicationContext();
final HostAuth hostAuth = account.getOrCreateHostAuthRecv(context);
Class<? extends Store> klass = sStoreClasses.get(hostAuth.mProtocol);
if (klass == null) {
klass = ServiceStore.class;
}
final Store store;
try {
// invoke "newInstance" class method
Method m = klass.getMethod("newInstance", Account.class, Context.class);
store = (Store)m.invoke(null, account, appContext);
} catch (Exception e) {
LogUtils.d(Logging.LOG_TAG, String.format(
"exception %s invoking method %s#newInstance(Account, Context) for %s",
e.toString(), klass.getName(), account.mDisplayName));
throw new MessagingException("Can't instantiate Store for " + account.mDisplayName);
}
// Don't cache this unless it's we've got a saved HostAuth
if (hostAuth.mId != EmailContent.NOT_SAVED && cacheInstance) {
sStores.put(hostAuth, store);
} }
return store; return store;
} }

View File

@ -91,7 +91,7 @@ public class AuthenticationCache {
private CacheEntry getEntry(Context context, Account account) { private CacheEntry getEntry(Context context, Account account) {
CacheEntry entry; CacheEntry entry;
if (account.isSaved()) { if (account.isSaved() && !account.isTemporary()) {
entry = mCache.get(account.mId); entry = mCache.get(account.mId);
if (entry == null) { if (entry == null) {
LogUtils.d(Logging.LOG_TAG, "initializing entry from database"); LogUtils.d(Logging.LOG_TAG, "initializing entry from database");
@ -102,7 +102,7 @@ public class AuthenticationCache {
mCache.put(account.mId, entry); mCache.put(account.mId, entry);
} }
} else { } else {
// This account is not yet saved, just create a temporary entry. Don't store // This account is temporary, just create a temporary entry. Don't store
// it in the cache, it won't be findable because we don't yet have an account Id. // it in the cache, it won't be findable because we don't yet have an account Id.
final HostAuth hostAuth = account.getOrCreateHostAuthRecv(context); final HostAuth hostAuth = account.getOrCreateHostAuthRecv(context);
final Credential credential = hostAuth.getCredential(context); final Credential credential = hostAuth.getCredential(context);
@ -157,5 +157,6 @@ public class AuthenticationCache {
entry.mRefreshToken = ""; entry.mRefreshToken = "";
entry.mExpirationTime = 0; entry.mExpirationTime = 0;
saveEntry(context, entry); saveEntry(context, entry);
mCache.remove(entry.mAccountId);
} }
} }