Can someone provide an up-to-date Android guide for Google Drive REST API v3?

Before answering this question I want you to know that I got the code from here (https://ammar.lanui.online/integrate-google-drive-rest-api-on-android-app-bc4ddbd90820) and the documentation from Google was not much helpful for me. So this solution is from limited resources available to me.

I need the drive to upload and download files from my app. In drive I have to create a folder and I have to upload file from my app to that folder and download a file from the folder to my device. This code was working fine for me.

I believe that you must have completed Google login. If you don’t, go checkout this video (https://youtu.be/t-yZUqthDMM) .

To interact with the Drive API, you need to enable the Drive API service for your app. You can do this in Google Developer Console.

To enable the Drive API, complete these steps:

Go to the Google API Console.

  1. Select a project.

  2. In the sidebar on the left, expand APIs & auth and select APIs.

  3. In the displayed list of available APIs, click the Drive API link and click Enable API.

If you completed it, then go to OAuth Consent screen in console and add the two scopes for drive and save it.

In your project add the dependencies below.

implementation 'com.google.android.gms:play-services-auth:17.0.0'// for google sign in

// for drive integration
implementation 'com.google.android.gms:play-services-auth:16.0.1'
implementation 'com.google.http-client:google-http-client-gson:1.26.0'
implementation('com.google.api-client:google-api-client-android:1.26.0') {
exclude group: 'org.apache.httpcomponents'
}
implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25.0') 
{
exclude group: 'org.apache.httpcomponents'
} 

And inside android tag, in the same gradle file, add the packaging options.

packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
}

In your Manifest file, add the required permissions

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Here I am storing the downloaded file in external storage. So that’s why I added the permissions for External storage READ and WRITE

After Google sign In, ask permission to access Google drive. The code for it is given below.

private void checkForGooglePermissions() {

    if (!GoogleSignIn.hasPermissions(
            GoogleSignIn.getLastSignedInAccount(getApplicationContext()),
            ACCESS_DRIVE_SCOPE,
            SCOPE_EMAIL)) {
        GoogleSignIn.requestPermissions(
                MainActivity.this,
                RC_AUTHORIZE_DRIVE,
                GoogleSignIn.getLastSignedInAccount(getApplicationContext()),
                ACCESS_DRIVE_SCOPE,
                SCOPE_EMAIL);
    } else {
        Toast.makeText(this, "Permission to access Drive and Email has been granted", Toast.LENGTH_SHORT).show();
        driveSetUp();

    }

}

The variables ACCESS_DRIVE_SCOPE and SCOPE_EMAIL are,

Scope ACCESS_DRIVE_SCOPE = new Scope(Scopes.DRIVE_FILE);
Scope SCOPE_EMAIL = new Scope(Scopes.EMAIL);

After having permission and Sign In we have our GoogleSignInAccount object. With this object, create an object of GoogleAccountCredential, from which we can generate an object of Drive. The Drive object is what we needed for the communication between Google Drive.

private void driveSetUp() {

GoogleSignInAccount mAccount = GoogleSignIn.getLastSignedInAccount(MainActivity.this);

GoogleAccountCredential credential =
        GoogleAccountCredential.usingOAuth2(
                getApplicationContext(), Collections.singleton(Scopes.DRIVE_FILE));
credential.setSelectedAccount(mAccount.getAccount());
googleDriveService =
        new com.google.api.services.drive.Drive.Builder(
                AndroidHttp.newCompatibleTransport(),
                new GsonFactory(),
                credential)
                .setApplicationName("GoogleDriveIntegration 3")
                .build();
mDriveServiceHelper = new DriveServiceHelper(googleDriveService);
}

Here you can see I created an object of DriveServiceHelper class and passed the object of Drive(googleDriveSrvice) along with it.
DriveServiceHelper class is given below. I got it from here.( https://github.com/gsuitedevs/android-samples/blob/master/drive/deprecation/app/src/main/java/com/google/android/gms/drive/sample/driveapimigration/DriveServiceHelper.java?source=post_page—–bc4ddbd90820———————-). You can use that one. I made some changes in that class for myself.

public class DriveServiceHelper {

private final Executor mExecutor = Executors.newSingleThreadExecutor();
private final Drive mDriveService;
private final String TAG = "DRIVE_TAG";


public DriveServiceHelper(Drive driveService) {

    mDriveService = driveService;
}

/**
 * Creates a text file in the user's My Drive folder and returns its file ID.
 */
public Task<GoogleDriveFileHolder> createFile(String folderId, String filename) {
    return Tasks.call(mExecutor, () -> {
        GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();

        List<String> root;
        if (folderId == null) {

            root = Collections.singletonList("root");

        } else {

            root = Collections.singletonList(folderId);
        }
        File metadata = new File()
                .setParents(root)
                .setMimeType("text/plain")
                .setName(filename);

        File googleFile = mDriveService.files().create(metadata).execute();
        if (googleFile == null) {

            throw new IOException("Null result when requesting file creation.");
        }
        googleDriveFileHolder.setId(googleFile.getId());
        return googleDriveFileHolder;
    });
}


// TO CREATE A FOLDER

public Task<GoogleDriveFileHolder> createFolder(String folderName, @Nullable String folderId) {
    return Tasks.call(mExecutor, () -> {

        GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();

        List<String> root;
        if (folderId == null) {

            root = Collections.singletonList("root");

        } else {

            root = Collections.singletonList(folderId);
        }
        File metadata = new File()
                .setParents(root)
                .setMimeType("application/vnd.google-apps.folder")
                .setName(folderName);

        File googleFile = mDriveService.files().create(metadata).execute();
        if (googleFile == null) {
            throw new IOException("Null result when requesting file creation.");
        }
        googleDriveFileHolder.setId(googleFile.getId());
        return googleDriveFileHolder;
    });
}


public Task<Void> downloadFile(java.io.File targetFile, String fileId) {
    return Tasks.call(mExecutor, () -> {

        // Retrieve the metadata as a File object.
        OutputStream outputStream = new FileOutputStream(targetFile);
        mDriveService.files().get(fileId).executeMediaAndDownloadTo(outputStream);
        return null;
    });
}

public Task<Void> deleteFolderFile(String fileId) {

    return Tasks.call(mExecutor, () -> {

        // Retrieve the metadata as a File object.
        if (fileId != null) {
            mDriveService.files().delete(fileId).execute();
        }

        return null;

    });
}

// TO LIST FILES

public List<File> listDriveImageFiles() throws IOException{

    FileList result;
    String pageToken = null;
    do {
        result = mDriveService.files().list()
/*.setQ("mimeType="image/png" or mimeType="text/plain"")This si to list both image and text files. Mind the type of image(png or jpeg).setQ("mimeType="image/png" or mimeType="text/plain"") */
                .setSpaces("drive")
                .setFields("nextPageToken, files(id, name)")
                .setPageToken(pageToken)
                .execute();

        pageToken = result.getNextPageToken();
    } while (pageToken != null);

    return result.getFiles();
}

// TO UPLOAD A FILE ONTO DRIVE

public Task<GoogleDriveFileHolder> uploadFile(final java.io.File localFile, 
final String mimeType, @Nullable final String folderId) {
    return Tasks.call(mExecutor, new Callable<GoogleDriveFileHolder>() {
        @Override
        public GoogleDriveFileHolder call() throws Exception {
            // Retrieve the metadata as a File object.

            List<String> root;
            if (folderId == null) {
                root = Collections.singletonList("root");
            } else {

                root = Collections.singletonList(folderId);
            }

            File metadata = new File()
                    .setParents(root)
                    .setMimeType(mimeType)
                    .setName(localFile.getName());

            FileContent fileContent = new FileContent(mimeType, localFile);

            File fileMeta = mDriveService.files().create(metadata, 
fileContent).execute();
            GoogleDriveFileHolder googleDriveFileHolder = new 
GoogleDriveFileHolder();
            googleDriveFileHolder.setId(fileMeta.getId());
            googleDriveFileHolder.setName(fileMeta.getName());
            return googleDriveFileHolder;
        }
    });
}
}

Remember the fact that whenever you create a file or folder or if you upload a file, the drive will give a unique id for it and you can access it. So it’s not the file name that is unique in here, it’s the id of the file. Hence if you upload or create a file of same name multiple times it will be saved in the folder multiple times. So if you want to replace a file with another file of the same name. First delete the file and save/ upload it.
To create a file, specify the folder id and file name to be created.

The GoogleDriveHolder class is given below.

public class GoogleDriveFileHolder {

private String id;
private String name;
private DateTime modifiedTime;
private long size;
private DateTime createdTime;
private Boolean starred;


public DateTime getCreatedTime() {
    return createdTime;
}

public void setCreatedTime(DateTime createdTime) {
    this.createdTime = createdTime;
}

public Boolean getStarred() {
    return starred;
}

public void setStarred(Boolean starred) {
    this.starred = starred;
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public DateTime getModifiedTime() {
    return modifiedTime;
}

public void setModifiedTime(DateTime modifiedTime) {
    this.modifiedTime = modifiedTime;
}

public long getSize() {
    return size;
}

public void setSize(long size) {
    this.size = size;
}
}

From your activity you have to call these methods. Like in the codes given below.

To create a folder

public void createFolderInDrive(View view) {

Log.i(TAG, "Creating a Folder...");
mDriveServiceHelper.createFolder("My Foder", null)
        .addOnSuccessListener(new OnSuccessListener<GoogleDriveFileHolder>() {
            @Override
            public void onSuccess(GoogleDriveFileHolder googleDriveFileHolder) {

                Gson gson = new Gson();
                Log.i(TAG, "onSuccess of Folder creation: " + gson.toJson(googleDriveFileHolder));
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {

                Log.i(TAG, "onFailure of Folder creation: " + e.getMessage());
            }
        });
}

To List files

public void listFilesInDrive(View view) {

Log.i(TAG, "Listing Files...");
new MyAsyncTask().execute();

}

To list the files, you can’t do it from your main thread because it will cause a deadlock. You have to do it in doInBackground() method of Asynctask. Here is my class.

public class MyAsyncTask extends AsyncTask<Void, Void, List<File>> {

List<File> fileList;

@Override
protected List<File> doInBackground(Void... voids) {

    try {

        fileList = mDriveServiceHelper.listDriveImageFiles();

    } catch (IOException e) {

        Log.i(TAG, "IO Exception while fetching file list");
    }

    return fileList;

}

@Override
protected void onPostExecute(List<File> files) {
    super.onPostExecute(files);

    if (files.size() == 0){

        Log.i(TAG, "No Files");
    }
    for (File file : files) {

        Log.i(TAG, "\nFound file: File Name :" +
                file.getName() + " File Id :" + file.getId());
    }
}
}

To Upload a file

To upload a file into Drive folder, specify the folder id , mime type of file to be uploaded and the file itself.
Here I select an Image from gallery and uploaded it into drive.

public void uploadFile(View view) {

if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PICK_IMAGE);

} else {
    Intent i = new Intent(
            Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

    startActivityForResult(i, RESULT_LOAD_IMAGE);
}
}

In onActivityResult

else if (requestCode == RESULT_LOAD_IMAGE) {

if (resultCode == RESULT_OK) {

    Uri selectedImage = data.getData();
    String[] filePathColumn = {MediaStore.Images.Media.DATA};

    Cursor cursor = getContentResolver().query(selectedImage,
            filePathColumn, null, null, null);
    cursor.moveToFirst();

    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
    String picturePath = cursor.getString(columnIndex);
    cursor.close();

    uploadImageIntoDrive(BitmapFactory.decodeFile(picturePath));

} else {

    Toast.makeText(this, "Did not select any image", Toast.LENGTH_SHORT).show();
}

uploadImageIntoDrive() method,

private void uploadImageIntoDrive(Bitmap bitmap) {

try {

    if (bitmap == null) {

        Log.i(TAG, "Bitmap is null");
        return;
    }
    java.io.File file = new java.io.File(getApplicationContext().getFilesDir(), "FirstFile");
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
    byte[] bitmapdata = bos.toByteArray();

    //write the bytes in file
    FileOutputStream fos = new FileOutputStream(file);
    fos.write(bitmapdata);
    fos.flush();
    fos.close();

    mDriveServiceHelper.uploadFile(file, "image/jpeg", "MY_FOLDER_ID")
            .addOnSuccessListener(new OnSuccessListener<GoogleDriveFileHolder>() {
                @Override
                public void onSuccess(GoogleDriveFileHolder googleDriveFileHolder) {

                    Log.i(TAG, "Successfully Uploaded. File Id :" + googleDriveFileHolder.getId());
                }
            })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {

                    Log.i(TAG, "Failed to Upload. File Id :" + e.getMessage());
                }
            });
} catch (Exception e) {

    Log.i(TAG, "Exception : " + e.getMessage());
}

}

To Download a file

To download a file, specify the id of the file and the target file into which the downloading file has to be stored.

public void downloadFile(View view) {

java.io.File file = new java.io.File(getExternalFilesDir(null), "DemoFile2.jpg");
mDriveServiceHelper.downloadFile(file, "MY_FILE_ID")
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {

                Log.i(TAG, "Downloaded the file");
                long file_size = file.length() / 1024;
                Log.i(TAG, "file Size :" + file_size);
                Log.i(TAG, "file Path :" + file.getAbsolutePath());
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {

                Log.i(TAG, "Failed to Download the file, Exception :" + e.getMessage());
            }
        });
}

To Delete a file.

public void deleteFile(View view) {

mDriveServiceHelper.deleteFolderFile("MY_FILE_OR_FOLDER_ID")
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {

                Log.i(TAG, "onSuccess of Deleting File ");
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {

                Log.i(TAG, "onFailure on Deleting File Exception : " + e.getMessage());
            }
        });
}

I am not an experienced guy. The reason I posted this code is somebody will find it useful and can bring up their own changes to it and post it here. Because there is not much reference for Drive Rest API integration for Android right now.

Thank You.

Leave a Comment