GoogleAccountCredential - [ERROR] the name must not be empty: null - despite permissions

2.7k views Asked by At

I've been working on an app that sends a small bit of data back to a Google Sheet at certain points, however I can't get it to work properly:

public void SheetUpdate() {
    GoogleAccountCredential mCredential;

    Sheets mService;
    final String[] SCOPES = { SheetsScopes.SPREADSHEETS };

    mCredential = GoogleAccountCredential.usingOAuth2(getApplicationContext(), Arrays.asList(SCOPES))
            .setBackOff(new ExponentialBackOff())
            .setSelectedAccountName("[email protected]");

    Log.e("DEBUG", "SheetUpdate: " + mCredential.getSelectedAccountName());

    HttpTransport transport = AndroidHttp.newCompatibleTransport();
    JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();

    mService = new Sheets.Builder(transport, jsonFactory, mCredential)
            .setApplicationName("Listeau")
            .build();

    /*
    String range = "[Sheet Name]![Start]:[End]";

    mService.spreadsheets().values().update(enumId, range, valueRange)
            .setValueInputOption("RAW")
            .execute();
    */

    ValueRange values = new ValueRange();
    values.set("EMAIL", "[email protected]");
    values.set("AUTH", "[INSERT DATE]");
    values.set("SUB", "[INSERT DATE + MONTH]");

    try {
        mService.spreadsheets().values().append("1meAAvjdPmghn6wl_IKc-_NJx_M85I_yqsn4Nwm_j_X0", "Users", values)
                .setValueInputOption("RAW")
                .execute();
    } catch(IOException e) {
        Log.e("BUG", "SheetUpdate: IOException");
    }
}

And in my manifest I have:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>

The error I receive points to mCredential as having it's name unset (null), which is being caught when mService.execute is called. I have manually (just to try and pinpoint the issue) allowed the permissions in the Settings-Apps menu, as well as tried it on Jellybean, but all claim the same issue.

[EDIT] Here's the full error output: `

E/AndroidRuntime: FATAL EXCEPTION: main
                  java.lang.RuntimeException: Unable to start activity ComponentInfo{com.pybuspr.listeriafoodusa/com.pybuspr.listeau.Master}: java.lang.IllegalArgumentException: the name must not be empty: null
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
                      at android.app.ActivityThread.access$600(ActivityThread.java:130)
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
                      at android.os.Handler.dispatchMessage(Handler.java:99)
                      at android.os.Looper.loop(Looper.java:137)
                      at android.app.ActivityThread.main(ActivityThread.java:4745)
                      at java.lang.reflect.Method.invokeNative(Native Method)
                      at java.lang.reflect.Method.invoke(Method.java:511)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
                      at dalvik.system.NativeStart.main(Native Method)
                   Caused by: java.lang.IllegalArgumentException: the name must not be empty: null
                      at android.accounts.Account.<init>(Account.java:48)
                      at com.google.android.gms.auth.zze.getToken(Unknown Source)
                      at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
                      at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential.getToken(GoogleAccountCredential.java:269)
                      at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential$RequestHandler.intercept(GoogleAccountCredential.java:294)
                      at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:868)
                      at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
                      at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
                      at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
                      at com.pybuspr.listeau.Master.SheetUpdate(Master.java:167)
                      at com.pybuspr.listeau.Master.onCreate(Master.java:48)
                      at android.app.Activity.performCreate(Activity.java:5008)
                      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084) 
                      at android.app.ActivityThread.access$600(ActivityThread.java:130) 
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195) 
                      at android.os.Handler.dispatchMessage(Handler.java:99) 
                      at android.os.Looper.loop(Looper.java:137) 
                      at android.app.ActivityThread.main(ActivityThread.java:4745) 
                      at java.lang.reflect.Method.invokeNative(Native Method) 
                      at java.lang.reflect.Method.invoke(Method.java:511) 
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
                      at dalvik.system.NativeStart.main(Native Method)

 `

2

There are 2 answers

1
Rob Pridham On

Your execute() call goes via the GoogleAccountCredential object you created, and that is failing internally.

Looking at the code for Account.java, which is open source, you can see that the name being passed in is null. The caller, GoogleAuthUtil, is a closed source part of the Play Services library but we can have a good guess at what's going on. It tries to get the Google account from the phone's settings and fails to find a match.

As you already suspect, permissions are a factor here, and I think this is the cause of your failure. When targeting Android 6 and above, declaring permissions in the manifest can be insufficient, and in your case, GET_ACCOUNTS is affected by that. See here.

You need to request permissions at runtime (and cleanly handle the case where they are refused by the user). See here for how to do that. Alternatively provided you don't have any relevant dependencies, you could decrease your target level to 5.1 or lower, and for now at least, it will use the older permission model.

0
Noor Hossain On

Today I got the same Error. But At last I have succeeded. I described here what I did, so that this helps anyone.

So, The reason is : mCredential.getSelectedAccountName() == null

so, I have called this way that if the api call is success or not :

 private void getResultsFromApi() {
        if (! isGooglePlayServicesAvailable()) {
            acquireGooglePlayServices();
        } else if (mCredential.getSelectedAccountName() == null) {
            chooseAccount();
        } else if (! isDeviceOnline()) {
            mOutputText.setText("No network connection available.");
        } else {

            Toast.makeText(this, "API CALL SUCCESS", Toast.LENGTH_SHORT).show();

          }
    }

And When I get the above message API CALL SUCCESS, then I call the readData or Append Data Function. And then data read or append Successfull.

So, Double Check your Codes, Initializations, Implementations, permissions etc. that mCredential.getSelectedAccountName() != null is success.