googleworkspace / android-samples

Android samples for Google Workspace APIs
Apache License 2.0
635 stars 410 forks source link

Can't get fileId of selected file from google drive . #106

Closed himanshiThakur closed 5 years ago

himanshiThakur commented 5 years ago

Method to open file , here i can only access name and content

private void openFileFromFilePicker(Uri uri) {

    if (mDriveServiceHelper != null) {

        Log.d(TAG, "Opening " + uri.getPath());

        mDriveServiceHelper.openFileUsingStorageAccessFramework(getContentResolver(), uri)
                .addOnSuccessListener(nameAndContent -> {
                    String name = nameAndContent.first;
                    String content = nameAndContent.second;

                    mFileTitleEditText.setText(name);
                    mDocContentEditText.setText(content);

                    // Files opened through SAF cannot be modified, except by retrieving the
                    // fileId from its metadata and updating it via the REST API. To modify
                    // files not created by your app, you will need to request the Drive
                    // Full Scope and submit your app to Google for review.
                    setReadOnlyMode();
                })
                .addOnFailureListener(exception ->
                        Log.e(TAG, "Unable to open file from picker.", exception));
    }
}

Comment : Files opened through SAF cannot be modified, except by retrieving the // fileId from its metadata and updating it via the REST API. To modify // files not created by your app, you will need to request the Drive // Full Scope and submit your app to Google for review.

Please guide me here . How can we get fileId here . I need fileId to download the selected file .

sqrrrl commented 5 years ago

Rich, could you take a look? Thanks.

rbstarbuck commented 5 years ago

Hmm, it appears that the FileId column is not exposed to third parties by the Drive content provider. My apologies, I didn't realize that this was a 1P-only field. It appears that the proposed workaround for modifying files opened with SAF will not work for external developers. I talked to someone on the Drive app team, this is intentional for security reasons and they will not be exposing the FileId.

sqrrrl commented 5 years ago

Filed a bug internally to update the migration guide. Will also have to remove the comment from the sample too, so leaving this open.

sqrrrl commented 5 years ago

I take it this means there really isn't a migration path from the picker component in the deprecated API. That leaves using the full drive scope and rolling your own UI as the only alternative.

himanshiThakur commented 5 years ago

i want to download the selected file from drive , but until i don't have fileId i can't download file . I am stuck here , now i can't add google drive as option to upload bills in my app . Is there any possible solution for this ?

rbstarbuck commented 5 years ago

You should still be able to download metadata and contents for files obtained via SAF, you just can't modify or upload.

himanshiThakur commented 5 years ago

By using this method
public Task<Pair<String, String>> openFileUsingStorageAccessFramework(ContentResolver contentResolver, Uri uri) { I can only access name and content (in string) of selected file not fileId . And to download file fileID is required. Method to download file : String fileId = "1ZdR3L3qP4Bkq8noWLJHSr_iBau0DNT4Kli4SxNc2YEo"; OutputStream outputStream = new ByteArrayOutputStream(); driveService.files().export(fileId, "application/pdf") .executeMediaAndDownloadTo(outputStream);

rbstarbuck commented 5 years ago

Please take a look at the DriveServiceHelper#openFileUsingStorageAccessFramework for an example of how to access metadata and stream file contents. You won't be able to get the FileID, but you can retrieve most other metadata and file contents using the mechanism displayed there.

himanshiThakur commented 5 years ago

Requirement in my app : upload any doc, file like resume or any bill which user selected , from google drive to server . but using #openFileUsingStorageAccessFramework i can only get file name . How i am suppose to upload that file, doc on our server unless i didn't get the fileID .

aleripe commented 5 years ago

The migration guide still shows incomplete and misleading information. You decided to deprecate the Android API without providing any feasible alternative. This way Android development is going nowhere, we developers can't rewrite our apps every six months without any Google support. I'm really really disappointed.

adityabhaskar commented 5 years ago

Hi folks,

Since this comment confirms that this sample does not work as a Drive Picker sample, I would suggest highlighting this in a warning at top of the readme.md.

I wasted half a day struggling to get a fileId using this sample's code before discovering this issue. A notice on top of the readme warning not to use this sample for a Drive Picker would help others avoid wasting time.

Cheers!

Adi

rbstarbuck commented 5 years ago

Just updated the comment in the sample app, thanks for the heads-up.

rbstarbuck commented 5 years ago

Hmm and, just realized that the migration guide on developers.google.com wasn't updated. Just sent a request to have the modified guide published to our developer page, but it won't be handled until Monday at the earliest.

adityabhaskar commented 5 years ago

Thank you, @rbstarbuck!

Is there a process for convincing the Drive/GSuite team on bringing back a native picker functionality?

Perhaps by apps passing an intent to the Drive app, specifying the details (file/folder, mime-type, user and app's auth token), and receiving the chosen file's base details (similar to the files.list or files.get in the Rest API). This would be far preferable to the current scenario of each app implementing its own Drive Picker.

More than the effort, this would reduce the vulnerability by not having to require the DRIVE_FULL permission when DRIVE_FILE would suffice. Implementing the picker ourselves would require DRIVE_FULL just to use the files.list endpoint.

Cheers!

Adi

shroff commented 5 years ago

Our app needs access to drive file ids to associate them with internal objects.

Is the best/recommended approach really to roll our own drive file picker? It doesn't seem like the best idea in terms of consistency, security, and of course effort involved.

I suppose we could make a copy of the file but that has some obvious issues, not to mention the fact that it doesn't account for virtual files.

Any chance of a first party picker? If not then any other alternatives?

rbstarbuck commented 5 years ago

Unfortunately, there is currently no alternative to implementing your own file picker if the SAF picker doesn't supply the necessary functionality. There were security vulnerabilities in the early versions of Android content providers, so we can't expose create/modify functionality through SAF. Eventually, the minSdk for Drive will move past those vulnerable versions and we'll be able to add those functions. But that won't be for a few years. We didn't receive approval for providing a first-party picker as the point of deprecation was to destaff the project as part of a Drive reorg. Sorry :(

shroff commented 5 years ago

Gotcha, thanks for the clarification @rbstarbuck

mattlaabs commented 5 years ago

@rbstarbuck wrote

so we can't expose create/modify functionality through SAF

I don't understand how read access to the driveId is a problem there? Or would it be at least possible to get the driveId on Android OS versions which have these vulnerabilities fixed?

Kshitij1792 commented 4 years ago

Not sure if it has been resolved by now or not.

But a workaround could be to get the name of the file from the StorageAccessFramework and then fire the search(fileName) query on drive using proper mimeType to get the Drive->fileId of that file. This would save you from the burden of rolling out your own FilePicker as well as having to require the DRIVE_FULL permission when DRIVE_FILE would suffice.

I used it to download a .zip file using the SAF implementation given on the migration page. Using the fileName returned by SAF and mimeType='application/zip', fired the search query to find it's Drive->fileID. Here is some code.

private String mSearchedZipFileId; private File mSearchedZipFile;

public Task<String> searchZipFile(String zipFileName) {
    return Tasks.call(mExecutor, () -> {
        String pageToken = null;
        do {
            FileList result = mDriveService.files().list()
                    .setQ("mimeType='application/zip'")
                    .setSpaces("drive")
                    .setFields("nextPageToken, files(id, name)")
                    .setPageToken(pageToken)
                    .execute();
            for (File file : result.getFiles()) {
                System.out.printf("Found file: %s (%s)\n",  file.getName(), file.getId());
                if (file.getName().equals(zipFileName)){
                    mSearchedZipFile = file;
                    Log.e(TAG, "searchZipFile: ID="+file.getId() );
                    break;
                }
            }
            pageToken = result.getNextPageToken();
        } while (pageToken != null);
        return mSearchedZipFile.getId();
    });
}

Hope this helps.