3

Now that Google is deprecating the Google Drive Android API, I'm in the process of migrating my code to the Drive REST API.

I've got almost everything working, but I'm not able to replicate the functionality that creates a File Picker allowing the user the ability to choose which folder they want to save the file in their Google Drive. I am able to successfully copy a file to the user's root folder of their Google Drive, but I would prefer to create a picker that allows the user the ability to place it where they want it.

I have a file picker created to choose a file to download from Google Drive using the sample app that Google provided, but unfortunately they don't provide an example for folder choosing. Also, I was able to find documentation for creating a file picker for web applications, but not for Android apps.

I know that I can select the name of a folder to insert the file into, but how do I create a picker to allow the user to choose the folder (and name the file) using the REST API? This should be easy, and I'd like to avoid using third-party libraries.

Thank you!

1 Answer 1

4

This question is a bit old, so you may have figured it out already. But I just had the same problem, so perhaps also others are interested.

The issue here is that the Google Drive REST API uses IDs to identify files and folders. The API does not provide file or directory pickers, which is why you are using Android's built-in pickers. For instance, to allow the user to select a name and destination folder for a new file, you can use this intent:

Intent createDirectoryPickerIntent(String fileName, String mimeType) {
    Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType(mimeType);
    intent.putExtra(Intent.EXTRA_TITLE, fileName);
    return intent;
}

and create it in your activity:

public void openDirectoryPicker() {
    if (mDriveServiceHelper != null) {
        Intent pickerIntent = mDriveServiceHelper.createDirectoryPickerIntent("fileName", "text/plain");
        startActivityForResult(pickerIntent, REQUEST_CODE_OPEN_DIR);
    }
}

(Remember to delete the empty file in case writing the actual content in the second step fails.)

The file pickers identify files by URI and don't know anything about file IDs. Querying the files by name in order to get the id of the new file may fail as there may be duplicates in another or even the same folder. This is why Google recommends to use other means to access the files:

For clients that use the Android API's file picker (e.g. by calling DriveClient#newOpenFileActivityIntentSender), we recommend using Storage Access Framework (SAF) which accesses the Drive Android app's content provider. The sample app demonstrates how to initiate the file picker Intent and process the data it returns. (Google Drive Android API Deprecation Guide)

The sample app provides, as you stated, an example for reading a file in openFileUsingStorageAccessFramework(...). You can do the same for writing to the file you created with above directory picker. The URI is provided by the intent.

In your activity:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent resultData) {
    switch (requestCode) {
        case REQUEST_CODE_SIGN_IN:
            //...
        }
            break;
        case REQUEST_CODE_OPEN_DIR:
            if (resultCode == RESULT_OK && resultData != null) {
                Uri uri = resultData.getData();
                if (uri != null && mDriveServiceHelper != null) {
                    mDriveServiceHelper.writeToFileUsingStorageAccessFramework(this, getContentResolver(), uri, "some content")
                        .addOnSuccessListener(Void -> {
                            Log.v(TAG, "success");
                        })
                        .addOnFailureListener(exception -> {
                            Log.e(TAG, "Unable to write to file.", exception);
                        });
                }
            } else {
                Log.v(TAG, "Unable to write to file.");
            }
            break;
    }
    super.onActivityResult(requestCode, resultCode, resultData);
}

and in the DriveServiceHelper very similar to the sample app:

Task<Void> writeToFileUsingStorageAccessFramework(Context context, ContentResolver contentResolver, Uri uri, String content) {
    return Tasks.call(mExecutor, () -> {
        // Retrieve the document's display name from its metadata.
        String name;
        try (Cursor cursor = contentResolver.query(uri, null, null, null, null)) {
            if (cursor != null && cursor.moveToFirst()) {
                int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                name = cursor.getString(nameIndex);
            } else {
                throw new IOException("Empty cursor returned for file.");
            }
        }

        // Write content to the file, e.g.
        try (OutputStream outputStream = contentResolver.openOutputStream(uri);) {
            if (outputStream != null) {
                outputStream.write(content.getBytes());
                outputStream.close();
            }
        }

        return null;
    });
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks so much for the detailed answer. I was still facing this challenge, so your answer was not too late. Thanks for helping out a newby Android developer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.