0

I am trying to add code to my android app that gets information from the UI and appends to a file in google drive. I have gotten as far sign in and authorization, as well as querying the file by name. Most of the SO threads I have read are for the old API or REST API.

However, I want to open it in Read/Write, or Write Only mode. I have tried looking at the quickstart demos and the drive API, but none of them are helpful.

How can I get the driveId programatically? I have tried getting the ID from drive itself. Is there a way to build Metadata that gets the ID from the query?

If I use openFile(DriveId.decodeFromString(actual_id).asDriveFile() I get the following error:

java.lang.IllegalArgumentException: Invalid DriveId: **actual_id**

Is getting the file ID from the sharing link wrong: drive.google.com/open?id=some_id

If so, how can I achieve this?

private String id = "1fuTq1Q6MHrchgW7sZImjvSfpAShHhsbx";
private DriveFile file = DriveId.decodeFromString(id).asDriveFile();



private void getFile() {
        Query q = new Query.Builder().addFilter(Filters.and(Filters.eq(SearchableField.TITLE, "HelloWorld.txt"))).build();
}

private void appendFile() {

    Task<DriveContents> openTask = getResourceClient().openFile(file, DriveFile.MODE_READ_WRITE);

    openTask.continueWithTask(task -> {
       DriveContents driveContents = task.getResult();
        ParcelFileDescriptor pfd = driveContents.getParcelFileDescriptor();
        long bytesToSkip = pfd.getStatSize();
        try (InputStream in = new FileInputStream(pfd.getFileDescriptor())) {
            // Skip to end of file
            while (bytesToSkip > 0) {
                long skipped = in.skip(bytesToSkip);
                bytesToSkip -= skipped;
            }
        }
        try (OutputStream out = new FileOutputStream(pfd.getFileDescriptor())) {
            out.write("Hello world".getBytes());
        }
        // [START drive_android_commit_contents_with_metadata]
        MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
                .setStarred(true)
                .setLastViewedByMeDate(new Date())
                .build();
        Task<Void> commitTask =
                getResourceClient().commitContents(driveContents, changeSet);
        // [END drive_android_commit_contents_with_metadata]
        return commitTask;
    })
            .addOnSuccessListener(this,
                    aVoid -> {
                        //showMessage(getString(R.string.content_updated));
                        Log.i("DRIVE", "Sucess");
                        finish();
                    })
            .addOnFailureListener(this, e -> {
                Log.e(TAG, "Unable to update contents", e);
               // showMessage(getString(R.string.content_update_failed));
                finish();
    });
}

Also the file exists and the ID is valid.. Apparently enter image description here

mlizbeth
  • 303
  • 3
  • 18
  • 1
    If you happen to check this [SO post](https://stackoverflow.com/questions/33327219/drive-api-for-android-unable-to-access-the-file-created-by-same-app), it was pointed out that this is a limitation of the Drive API for android and they are switching to use Drive REST API. – MαπμQμαπkγVπ.0 Aug 14 '18 at 12:41
  • So this "feature" isn't documented by Google, even though the API says it's possible? – mlizbeth Aug 14 '18 at 13:19
  • Well within 30 minutes of tinkering, I was able to make a java REST app that grabs files and lists their name/ID. The code is way less dense and surprisingly makes more sense.. – mlizbeth Aug 14 '18 at 15:13

1 Answers1

1

According to the documentation for the GDAA (Google Drive Android API), it should be possible to download a file based on its ID alone by using asDriveFile().

To do that you need a query and then store the information in a Task<MetadataBuffer>, and then should be able to files.get(0).asDriveFile() in the method where you are attempting to download by FileId. But even when pulling the metadata and use the query method, you are greeted with IllegalArgumentException invalid DriveId (which IS THE SAME ID, so it was never invalid), But it STILL shows it as invalid. I got tired of wrestling with it and went to the REST API.

Things to note: The file you are downloading MUST BE: Doc/Spreadsheet/Slides, photo or apps script. You can choose the type of file you want to export it as. Here is the "truth table" for compatibility.

From this example it is easy enough to write your data and re-upload it. However, these files have a special encoding so you can't write the data directly.

Depending on what you need to accomplish, you can use the sheets api or apache poi

// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// [START drive_quickstart]
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.util.Collections;
import java.util.List;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.drive.Drive;
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 DriveQuickstart {
    private static final String APPLICATION_NAME = "Google Drive API Java Quickstart";
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private static final String TOKENS_DIRECTORY_PATH = "tokens";
    private static String fileId = "super_secret_string";
    private static final String OUTPUT = "super_secret_path";

    /**
     * Global instance of the scopes required by this quickstart.
     * If modifying these scopes, delete your previously saved credentials/ folder.
     */
    private static final List<String> SCOPES = Collections.singletonList(DriveScopes.DRIVE); //DONT USE THIS SCOPE IN PRODUCTION!
    private static final String CREDENTIALS_FILE_PATH = "/credentials.json";

    /**
     * Creates an authorized Credential object.
     * @param HTTP_TRANSPORT The network HTTP Transport.
     * @return An authorized Credential object.
     * @throws IOException If the credentials.json file cannot be found.
     */
    private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
        // Load client secrets.
        InputStream in = DriveQuickstart.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

        // Build flow and trigger user authorization request.
        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                .setAccessType("offline")
                .build();
        return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
    }

    public static void main(String... args) throws IOException, GeneralSecurityException {
        // Build a new authorized API client service.
        final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
        Drive service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
                .setApplicationName(APPLICATION_NAME)
                .build();

        // Print the names and IDs for up to 10 files.
        FileList result = service.files().list()
                .setPageSize(10)
                .setFields("nextPageToken, files(id, name)")
                .execute();
        List<File> files = result.getFiles();
        if (files == null || files.isEmpty()) {
            System.out.println("No files found.");
        } else {
            System.out.println("Files:");
            for (File file : files) {
                System.out.printf("%s (%s)\n", file.getName(), file.getId());
            }
        }
        //Download the file from it's known ID
        FileOutputStream fos = new FileOutputStream(OUTPUT);
        service.files().export(fileId, "text/plain").executeMediaAndDownloadTo(fos);
        //Append some data to the file
        FileWriter fw = new FileWriter(OUTPUT, true);
        BufferedWriter bw = new BufferedWriter(fw);
        bw.newLine();
        bw.write("Goodbye, World!");
        bw.newLine();
        bw.close();

    }
}
// [END drive_quickstart]
mlizbeth
  • 303
  • 3
  • 18