Following the "Five minute quick start" documentation for uploading a file from an Android device to Google Drive, I've written a test application that successfully uploads a file but my attempt at copying the relevant code to a larger application doesn't upload a file because its Google Account Picker is always getting canceled:

  • the onActivityResult() result code is 0 (i.e., RESULT_CANCELED),
  • the onActivityResult() intent argument is null, and
  • the logcat (shown below) reveals that "Activity is launching as a new task, so cancelling activity result."

04-22 02:04:25.098: D/alsa_ucm(162): snd_use_case_set(): uc_mgr 0x40e59388 identifier _verb value HiFi Lowlatency
04-22 02:04:25.098: D/alsa_ucm(162): Set mixer controls for Speaker enable 1
04-22 02:04:25.098: D/ACDB-LOADER(162): ACDB -> send_afe_cal
04-22 02:04:25.098: I/ActivityManager(526): START u0 {act=com.google.android.gms.common.account.CHOOSE_ACCOUNT cmp=com.google.android.gms/.common.account.AccountPickerActivity (has extras)} from pid 3484
04-22 02:04:25.098: W/ActivityManager(526): Activity is launching as a new task, so cancelling activity result.
04-22 02:04:25.108: D/alsa_ucm(162): Set mixer controls for HiFi Lowlatency enable 1
04-22 02:04:25.108: D/ALSAModule(162): Device value returned is hw:0,14
04-22 02:04:25.118: D/ALSAModule(162): setHardwareParams: reqBuffSize 1024 channels 2 sampleRate 48000
04-22 02:04:25.118: D/ALSAModule(162): setHardwareParams: buffer_size 2048, period_size 1024, period_cnt 2
04-22 02:04:25.188: D/dalvikvm(526): GC_FOR_ALLOC freed 565K, 15% free 18562K/21684K, paused 71ms, total 71ms
04-22 02:04:25.248: D/overlay(159): Unset pipe=VG0 dpy=0; Unset pipe=VG1 dpy=0; Unset pipe=RGB1 dpy=0
04-22 02:04:25.248: W/InputMethodManagerService(526): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@41ebd7e0 attribute=null, token = android.os.BinderProxy@42018140
04-22 02:04:27.991: D/dalvikvm(526): GC_FOR_ALLOC freed 422K, 15% free 18564K/21684K, paused 65ms, total 66ms
04-22 02:04:28.011: I/ActivityManager(526): No longer want com.google.android.marvin.talkback (pid 5301): empty #17
04-22 02:04:28.241: D/overlay(159): Set pipe=RGB1 dpy=0; Set pipe=VG0 dpy=0; Set pipe=VG1 dpy=0;
04-22 02:04:28.672: D/overlay(159): Unset pipe=VG0 dpy=0; Unset pipe=VG1 dpy=0; Unset pipe=RGB1 dpy=0;

The code that launches the Google Account Picker is exactly the same in both applications but the picker gets canceled only in the larger application.

// Handle item selection
case R.id.action_select_account:
    mCredential = GoogleAccountCredential.usingOAuth2(this, DriveScopes.DRIVE);
    Intent intent2 = mCredential.newChooseAccountIntent();
    showToast("intent extra: " + intent2.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)); // TODO: remove after test
    startActivityForResult(intent2, REQUEST_ACCOUNT_PICKER);
    return true;
default:
    return false;

The test application and the larger application are both debug versions, including the same jars (shown below), and running on the same device (Nexus 4, OS 4.2.2) but, as suggested in the five minute quickstart, each application has its own client ID generated by Google APIs Console.

enter image description here

The result of this cancellation is that the onActivityResult() runs as soon as the Google Account Picker gets drawn, well before an account is selected.

UPDATE:
After an approximately equal amount of trial and error, it turns out that removing the following from AndroidManifest.xml fixed the problem.

android:launchMode="singleInstance"

My initial question of why now shifts to why does the Google Account Picker in Android need to create multiple instances?

Thanks,
Greg

有帮助吗?

解决方案 2

As described in the question's update, the account picker started working when I removed singleInstance launchMode from AndroidManifest.xml. I don't know if this single instance launch mode behavior is a bug or a lack of documentation, but I submitted it to the Android Issue Tracker: issue 54656

其他提示

If you use singleInstance you permit no other activities to be part of its task. Use singleTask instead.

As stated on http://developer.android.com/guide/topics/manifest/activity-element.html#lmode a few paragraphs down.

The "singleTask" and "singleInstance" modes also differ from each other in only one respect: A "singleTask" activity allows other activities to be part of its task. It's always at the root of its task, but other activities (necessarily "standard" and "singleTop" activities) can be launched into that task. A "singleInstance" activity, on the other hand, permits no other activities to be part of its task. It's the only activity in the task. If it starts another activity, that activity is assigned to a different task — as if FLAG_ACTIVITY_NEW_TASK was in the intent.

For some reason, the intent returned by account manager has singleTop set, which always causes your onActivityResult to fail immediately and return a 0 resultCode (Activity.RESULT_CANCELLED) or whatever. I had to zero-out the intent flags to prevent this

// prevent running AccountPicker as SingleTop which fails and calls onActivityResult immediately otherwise
intent.setFlags(0);
startActivityForResult(intent, AccountManagerUtils.GOOGLE_AUTH_REQUEST_CODE);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top