My authorization flow in the new Google Drive Android API is as follows:
- Menu: SELECT ACCOUNT
- connect();
- onConnectionFailed() result.startResolutionForResult() invokes AccountSelectDialog / DriveAuthorization
- onConnected() do your stuff
Works like a charm. Now repeating with the aim to switch accounts:
- Menu: SELECT ACCOUNT
- connect();
- onConnected()
Here, I have no chance to get to the AccountSelectDialog since I never get onConnectionFailed() with 'result' to invoke startResolutionForResult(). What am I missing this time?
Just call
mGoogleApiClient.clearDefaultAccountAndReconnect();
have a look at the docs.
This will call the onConnectionFailed
callback that will present the layout to choose among the available Google accounts:
@Override
public void onConnectionFailed(ConnectionResult connectionResult)
{
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(this, RESOLVE_CONNECTION_REQUEST_CODE);
} catch (IntentSender.SendIntentException e) {
// Unable to resolve, message user appropriately
}
} else {
GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), this, 0).show();
}
}
First, add the Plus.API:
mGoogleApiClient = new GoogleApiClient.Builder(this).addApi(Drive.API).addApi(Plus.API).addScope(Drive.SCOPE_APPFOLDER).addConnectionCallbacks(this).addOnConnectionFailedListener(this).build();
Then you can switch accounts like this:
public void onClick(View view) {
if (view.getId() == R.id.sign_out_button) {
if (mGoogleApiClient.isConnected()) {
Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
mGoogleApiClient.disconnect();
mGoogleApiClient.connect();
}
}
}
For more, see here.
I realize I made quite a mess by opening two SO questions about essentially the same topic. So, it is a good time to consolidate the answers. I was searching for direct getter / setter methods in GDAA but found only the 'setter' - setAccountName()) - SO question 21583828 (actually did not, but Burcu helped me).
On the other side, 'getter' can be substituted by getting the account name from "onActivityResult()" - SO question 21501829
And yet another SO question - this one - on the same topic has been resolved as well.
So the conclusion is:
- get account from 'onActivityResult()'
- set account in 'setAccountName()'
- keep your current account email around, so you can detect a new one (should user decide to switch) and reset Google Account Client if necessary.
UPDATE 2014-11-04:
Here is a wrapper that I use to persist and manage the Google accounts within my app.
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.google.android.gms.auth.GoogleAuthUtil;
public class GooAccMgr {
private static final String ACC_NAME = "account_name";
public static final int FAIL = -1;
public static final int UNCHANGED = 0;
public static final int CHANGED = +1;
private String mCurrEmail = null; // cache locally
public Account[] getAllAccnts(Context ctx) {
return AccountManager.get(acx(ctx)).getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
}
public Account getPrimaryAccnt(Context ctx) {
Account[] accts = getAllAccnts(ctx);
return accts == null || accts.length == 0 ? null : accts[0];
}
public Account getActiveAccnt(Context ctx) {
return email2Accnt(ctx, getActiveEmail(ctx));
}
public String getActiveEmail(Context ctx) {
if (mCurrEmail != null) {
return mCurrEmail;
}
mCurrEmail = ctx == null ? null : pfs(ctx).getString(ACC_NAME, null);
return mCurrEmail;
}
public Account email2Accnt(Context ctx, String emil) {
if (emil != null) {
Account[] accounts =
AccountManager.get(acx(ctx)).getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
for (Account account : accounts) {
if (emil.equalsIgnoreCase(account.name)) {
return account;
}
}
}
return null;
}
/**
* Stores a new email in persistent app storage, reporting result
* @param ctx activity context
* @param newEmail new email, optionally null
* @return FAIL, CHANGED or UNCHANGED (based on the following table)
* OLD NEW SAVED RESULT
* ERROR FAIL
* null null null FAIL
* null new new CHANGED
* old null old UNCHANGED
* old != new new CHANGED
* old == new new UNCHANGED
*/
public int setEmail(Context ctx, String newEmail) {
int result = FAIL; // 0 0
String prevEmail = getActiveEmail(ctx);
if ((prevEmail == null) && (newEmail != null)) {
result = CHANGED;
} else if ((prevEmail != null) && (newEmail == null)) {
result = UNCHANGED;
} else if ((prevEmail != null) && (newEmail != null)) {
result = prevEmail.equalsIgnoreCase(newEmail) ? UNCHANGED : CHANGED;
}
if (result == CHANGED) {
mCurrEmail = newEmail;
pfs(ctx).edit().putString(ACC_NAME, newEmail).apply();
}
return result;
}
private Context acx(Context ctx) {
return ctx == null ? null : ctx.getApplicationContext();
}
private SharedPreferences pfs(Context ctx) {
return ctx == null ? null : PreferenceManager.getDefaultSharedPreferences(acx(ctx));
}
}
Hat-tip to Alex Lockwood for initial inspiration. Unfortunately, I can't find reference to his original code.
It sounds like you are relying on the default account selection. In this setup, the user is prompted once to select an account, and this status is remembered.
If you want to provide account switching capabilities in your app, you need to instead launch the account picker from your own app and provide the account name selected when you instantiate the GoogleApiClient.
You could persist the last selected account name in shared preferences so you remember it until the next time the user switches accounts.
if you use GoogleApiClient, just call mGoogleApiClient.clearDefaultAccountAndReconnect()
.
if you use DriveClient with GoogleSignInAccount (drive library 16.0.0), try this.
// try connect Drive
fun startSignIn() {
val requiredScopes = HashSet<Scope>()
requiredScopes.add(Drive.SCOPE_FILE)
requiredScopes.add(Drive.SCOPE_APPFOLDER)
val account = GoogleSignIn.getLastSignedInAccount(this)
if (account != null && account.grantedScopes.containsAll(requiredScopes)) {
// TODO: Get DriveClient and DriveResourceClient
} else {
val option = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(Drive.SCOPE_FILE, Drive.SCOPE_APPFOLDER)
.build()
val client = GoogleSignIn.getClient(this, option)
startActivityForResult(client.signInIntent, REQUEST_CODE_SIGN_IN)
}
}
// try change account
fun changeAccount() {
val option = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.build()
val client = GoogleSignIn.getClient(activity, option)
client.signOut()
.addOnSuccessListener {
Log.d(TAG, "signOut success")
// Try again sign-in
startSignIn()
}
.addOnFailureListener {
Log.e(TAG, "signOut failed $it")
}
}
来源:https://stackoverflow.com/questions/21610239/how-do-i-switch-accounts-under-the-new-google-drive-android-api