Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Drive SDK Activity Not Found Exception

I am trying to implement Stephen Wylie's Google Drive example (here). Here is my code:

package com.googledrive.googledriveapp;
// For Google Drive / Play Services
// Version 1.1 - Added new comments & removed dead code
// Stephen Wylie - 10/20/2012
import java.io.IOException;
import java.util.ArrayList;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.google.android.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.UserRecoverableAuthException;
import com.google.android.gms.common.AccountPicker;
import com.google.api.client.auth.oauth2.BearerToken;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.android2.AndroidHttp;
import com.google.api.client.googleapis.extensions.android2.auth.GoogleAccountManager;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.json.JsonHttpRequest;
import com.google.api.client.http.json.JsonHttpRequestInitializer;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.Drive.Apps.List;
import com.google.api.services.drive.Drive.Files;
import com.google.api.services.drive.DriveRequest;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.FileList;

public class MainActivity extends Activity {
    private static final int CHOOSE_ACCOUNT=0;
    private static String accountName;
    private static int REQUEST_TOKEN=0;
    private Button btn_drive;
    private Context ctx = this;
    private Activity a = this;

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        // set up the GUI layout
        setContentView(R.layout.activity_main);
        // set the variables to access the GUI controls
        btn_drive = (Button) findViewById(R.id.btn_drive);
            btn_drive.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                chooseAccount();
            }
            });
    }

    public void chooseAccount() {
        Intent intent = AccountPicker.newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null, null, null, null);
        startActivityForResult(intent, CHOOSE_ACCOUNT);
    }

    // Fetch the access token asynchronously.
    void getAndUseAuthTokenInAsyncTask(Account account) {
        AsyncTask<Account, String, String> task = new AsyncTask<Account, String, String>() {
            ProgressDialog progressDlg;
            AsyncTask<Account, String, String> me = this;

            @Override
            protected void onPreExecute() {
                progressDlg = new ProgressDialog(ctx, ProgressDialog.STYLE_SPINNER);
                progressDlg.setMax(100);
                progressDlg.setTitle("Validating...");
                progressDlg.setMessage("Verifying the login data you entered...\n\nThis action will time out after 10 seconds.");
                progressDlg.setCancelable(false);
                progressDlg.setIndeterminate(false);
                progressDlg.setOnCancelListener(new android.content.DialogInterface.OnCancelListener() {
                    public void onCancel(DialogInterface d) {
                        progressDlg.dismiss();
                        me.cancel(true);
                    }
                });
                progressDlg.show();
            }

            @Override
            protected String doInBackground(Account... params) {
                return getAccessToken(params[0]);
            }

            @Override
            protected void onPostExecute(String s) {
                if (s == null) {
                    // Wait for the extra intent
                } else {
                    accountName = s;
                    getDriveFiles();
                }
                progressDlg.dismiss();
            }
        };
        task.execute(account);
    }

    /**
     * Fetches the token from a particular Google account chosen by the user.  DO NOT RUN THIS DIRECTLY.  It must be run asynchronously inside an AsyncTask.
     * @param activity
     * @param account
     * @return
     */
    private String getAccessToken(Account account) {
        try {
            return GoogleAuthUtil.getToken(ctx, account.name, "oauth2:" + DriveScopes.DRIVE_READONLY);  // IMPORTANT: DriveScopes must be changed depending on what level of access you want
        } catch (UserRecoverableAuthException e) {
            // Start the Approval Screen intent, if not run from an Activity, add the Intent.FLAG_ACTIVITY_NEW_TASK flag.
            a.startActivityForResult(e.getIntent(), REQUEST_TOKEN);
            e.printStackTrace();
            return null;
        } catch (GoogleAuthException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    private Drive getDriveService() {
        HttpTransport ht = AndroidHttp.newCompatibleTransport();             // Makes a transport compatible with both Android 2.2- and 2.3+
        JacksonFactory jf = new JacksonFactory();                            // You need a JSON parser to help you out with the API response
        Credential credential = new Credential(BearerToken.authorizationHeaderAccessMethod()).setAccessToken(accountName);
        HttpRequestFactory rf = ht.createRequestFactory(credential);
        Drive.Builder b = new Drive.Builder(ht, jf, null);
        b.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {

            @Override
            public void initialize(JsonHttpRequest request) throws IOException {
                DriveRequest driveRequest = (DriveRequest) request;
                driveRequest.setPrettyPrint(true);
                driveRequest.setOauthToken(accountName);
            }
        });
        return b.build();
    }

    /**
     * Obtains a list of all files on the signed-in user's Google Drive account.
     */
    private void getDriveFiles() {
        Drive service = getDriveService();
        Log.d("SiteTrack", "FUNCTION getDriveFiles()");
        Files.List request;
        try {
            request = service.files().list(); // .setQ("mimeType=\"text/plain\"");
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        do {
            FileList files;
            try {
                Log.d("SiteTrack", request.toString());
                files = request.execute();
            } catch (IOException e) {
                e.printStackTrace();
                Log.d("SiteTrack", "Exception");
                return;
            }
            ArrayList<File> fileList = (ArrayList<File>) files.getItems();
            Log.d("SiteTrack", "Files found: " + files.getItems().size());
            for (File f : fileList) {
                String fileId = f.getId();
                String title = f.getTitle();
                Log.d("SiteTrack", "File " + fileId + ": " + title);
            }
            request.setPageToken(files.getNextPageToken());
        } while (request.getPageToken() != null && request.getPageToken().length() >= 0);
    }

    protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        if (requestCode == CHOOSE_ACCOUNT && resultCode == RESULT_OK) {
            accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
            GoogleAccountManager gam = new GoogleAccountManager(this);
            getAndUseAuthTokenInAsyncTask(gam.getAccountByName(accountName));
            Log.d("SiteTrack", "CHOOSE_ACCOUNT");
        } else if (requestCode == REQUEST_TOKEN && resultCode == RESULT_OK) {
            accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
            Log.d("SiteTrack", "REQUEST_TOKEN");
        }
    }   
}

Here is my manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.googledrive.googledriveapp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="android.app.ActivityGroup" />
        </activity>
    </application>
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.INTERNET" />
</manifest>

Here is my activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btn_drive"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Connect to Google Drive" />
</LinearLayout>

And here is the LogCat error I receive. It occurs when the button is pressed:

10-28 00:25:28.637: E/AndroidRuntime(842): android.content.ActivityNotFoundException: No Activity found to handle Intent { act=com.google.android.gms.common.account.CHOOSE_ACCOUNT (has extras) }
10-28 00:25:28.637: E/AndroidRuntime(842):  at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1512)
10-28 00:25:28.637: E/AndroidRuntime(842):  at android.app.Instrumentation.execStartActivity(Instrumentation.java:1384)
10-28 00:25:28.637: E/AndroidRuntime(842):  at android.app.Activity.startActivityForResult(Activity.java:3190)
10-28 00:25:28.637: E/AndroidRuntime(842):  at com.googledrive.googledriveapp.MainActivity.chooseAccount(MainActivity.java:67)
10-28 00:25:28.637: E/AndroidRuntime(842):  at com.googledrive.googledriveapp.MainActivity$1.onClick(MainActivity.java:60)
10-28 00:25:28.637: E/AndroidRuntime(842):  at android.view.View.performClick(View.java:3511)
10-28 00:25:28.637: E/AndroidRuntime(842):  at android.view.View$PerformClick.run(View.java:14105)
10-28 00:25:28.637: E/AndroidRuntime(842):  at android.os.Handler.handleCallback(Handler.java:605)
10-28 00:25:28.637: E/AndroidRuntime(842):  at android.os.Handler.dispatchMessage(Handler.java:92)
10-28 00:25:28.637: E/AndroidRuntime(842):  at android.os.Looper.loop(Looper.java:137)
10-28 00:25:28.637: E/AndroidRuntime(842):  at android.app.ActivityThread.main(ActivityThread.java:4424)
10-28 00:25:28.637: E/AndroidRuntime(842):  at java.lang.reflect.Method.invokeNative(Native Method)
10-28 00:25:28.637: E/AndroidRuntime(842):  at java.lang.reflect.Method.invoke(Method.java:511)
10-28 00:25:28.637: E/AndroidRuntime(842):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
10-28 00:25:28.637: E/AndroidRuntime(842):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
10-28 00:25:28.637: E/AndroidRuntime(842):  at dalvik.system.NativeStart.main(Native Method)

Can anyone help out?

like image 307
John Roberts Avatar asked Oct 28 '12 00:10

John Roberts


People also ask

How do I enable Google Drive SDK?

Go to the Google API Console. Select a project. In the sidebar on the left, expand APIs & auth and select APIs. In the displayed list of available APIs, click the Drive API link and click Enable API.

How do I fix Google Drive file not found?

The notFound error occurs when the user doesn't have read access to a file, or the file doesn't exist. To fix this error: Inform the user they don't have read access to the file or the file doesn't exist. Instruct the user to contact the file's owner and request permission to the file.

What is http error 403 in Google Drive?

This error is usually labeled as the http error 403. There may be several reasons why you are seeing this error message. It may be related to expired or cached browser cookies, a corrupted Google Drive download, and more.


2 Answers

We've been doing some experimenting, and our current theory is that the new Google OAuth Library depends on having the latest version of Google Play.

We found that if your device still has the Android Marketplace, or an older Google Play we couldn't get OAuth to work.

So you might try opening the Android Marketplace or Google Play App to kick off an upgrade.

Open the Android Marketplace, Accept the Upgrade to Google Play.
Close the Marketplace, and open the Google Play App. Accept the Terms of Service for Google Play. Wait a few seconds, sacrifice a chicken, and then you should be able to run Google OAuth.

EDIT: Looks like Google Provides some guidance on what your app should do if your users are missing the correct Google Play version. See: https://developer.android.com/google/play-services/setup.html#ensure

like image 74
Joseph Lee Avatar answered Oct 18 '22 02:10

Joseph Lee


Google Drive API seems (acording to the Google people) to only works on a real Device, in the Emulator it will crash with this error.

So my Advice, try on a real device.

like image 30
Frank Avatar answered Oct 18 '22 00:10

Frank