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 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_DISPLAY_NAME_COLUMN = 1;
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);
}
public boolean isTemporary() {
return mTemporary;
}
public void setTemporary(boolean temporary) {
mTemporary = temporary;
}
private static long getId(Uri u) {
return Long.parseLong(u.getPathSegments().get(1));
}

View File

@ -71,7 +71,7 @@ public class SetupDataFragment extends Fragment implements Parcelable {
public SetupDataFragment() {
mPolicy = null;
mAccount = new Account();
setAccount(new Account());
mEmail = null;
mCredentialResults = null;
}
@ -83,7 +83,7 @@ public class SetupDataFragment extends Fragment implements Parcelable {
public SetupDataFragment(int flowMode, Account account) {
this(flowMode);
mAccount = account;
setAccount(account);
}
@Override
@ -105,7 +105,7 @@ public class SetupDataFragment extends Fragment implements Parcelable {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mFlowMode = savedInstanceState.getInt(SAVESTATE_FLOWMODE);
mAccount = savedInstanceState.getParcelable(SAVESTATE_ACCOUNT);
setAccount((Account) savedInstanceState.getParcelable(SAVESTATE_ACCOUNT));
mEmail = savedInstanceState.getString(SAVESTATE_EMAIL);
mCredentialResults = savedInstanceState.getParcelable(SAVESTATE_CREDENTIAL);
mIncomingCredLoaded = savedInstanceState.getBoolean(SAVESTATE_INCOMING_LOADED);
@ -132,6 +132,7 @@ public class SetupDataFragment extends Fragment implements Parcelable {
public void setAccount(Account account) {
mAccount = account;
mAccount.setTemporary(true);
}
public String getEmail() {
@ -269,7 +270,7 @@ public class SetupDataFragment extends Fragment implements Parcelable {
public SetupDataFragment(Parcel in) {
final ClassLoader loader = getClass().getClassLoader();
mFlowMode = in.readInt();
mAccount = in.readParcelable(loader);
setAccount((Account) in.readParcelable(loader));
mEmail = in.readString();
mCredentialResults = in.readParcelable(loader);
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.
*
* @param account The account of the store.
* @param context For all the usual context-y stuff
* @return an initialized store of the appropriate class
* @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);
// An existing account might have been deleted
if (hostAuth == null) return null;
Store store = sStores.get(hostAuth);
if (store == null) {
Context appContext = context.getApplicationContext();
Class<? extends Store> klass = sStoreClasses.get(hostAuth.mProtocol);
if (klass == null) {
klass = ServiceStore.class;
}
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);
if (!account.isTemporary()) {
Store store = sStores.get(hostAuth);
if (store == null) {
store = createInstanceInternal(account, context, true);
} else {
// Make sure the account object is up to date (according to the caller, at least)
store.mAccount = account;
}
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;
}

View File

@ -91,7 +91,7 @@ public class AuthenticationCache {
private CacheEntry getEntry(Context context, Account account) {
CacheEntry entry;
if (account.isSaved()) {
if (account.isSaved() && !account.isTemporary()) {
entry = mCache.get(account.mId);
if (entry == null) {
LogUtils.d(Logging.LOG_TAG, "initializing entry from database");
@ -102,7 +102,7 @@ public class AuthenticationCache {
mCache.put(account.mId, entry);
}
} 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.
final HostAuth hostAuth = account.getOrCreateHostAuthRecv(context);
final Credential credential = hostAuth.getCredential(context);
@ -157,5 +157,6 @@ public class AuthenticationCache {
entry.mRefreshToken = "";
entry.mExpirationTime = 0;
saveEntry(context, entry);
mCache.remove(entry.mAccountId);
}
}