I'm using google drive in my app. I'm able to upload data in Google drive App folder and getting the file id. My Question is, how to download it from appDataFolder by using FileId
This is how i'm getting the file ids
private List<String> getDataFromApi() throws IOException {
List<String> fileInfo = new ArrayList<String>();
FileList lst = mService.files().list()
.setSpaces("appDataFolder")
.execute();
FileList result = mService.files().list()
.setSpaces("appDataFolder")
.setFields("nextPageToken, files(id, name, mimeType)")
.execute();
List<File> files = result.getFiles();
if (files != null) {
for (File file : files) {
fileInfo.add(String.format("%s (%s) %s\n",
file.getName(), file.getId(), file.getMimeType()));
}
}
return fileInfo;
}
I'm using v3 of google drive services.
compile('com.google.apis:google-api-services-drive:v3-rev102-1.23.0') {
exclude group: 'org.apache.httpcomponents'
}
Thanks In Advance
Finally I got My answer. Hope this will help to others also for downloading from appDataFolder . Here I'm downloading and saving the file into SD card folder name Spectors. And passing the value of File type of com.google.api.services.api.drive.model.File.
private void downloadFile(boolean useDirectDownload, File uploadedFile)
throws IOException {
java.io.File direct = new java.io.File(Environment.getExternalStorageDirectory()
+ "/Spectors");
if (!direct.exists()) {
direct.mkdirs();
}
java.io.File parentDir = new java.io.File(direct.getAbsolutePath());
if (!parentDir.exists() && !parentDir.mkdirs()) {
throw new IOException("Unable to create parent directory");
}
OutputStream out = new FileOutputStream(new java.io.File(parentDir, uploadedFile.getName()+".zip"));
com.google.api.services.drive.Drive.Files.Get files = mService.files().get(uploadedFile.getId());
files.executeMediaAndDownloadTo(out);
Log.e(TAG, "downloadFile:2 " + files.toString() + "\n"+uploadedFile.getFileExtension() );
}
you can also apply following approach to download the content from app folder
get files from app folder by the following code
private void listFiles() {
Query query =
new Query.Builder()
.addFilter(Filters.or(Filters.eq(SearchableField.MIME_TYPE, "text/html"),
Filters.eq(SearchableField.MIME_TYPE, "text/plain")))
.build();
getDriveResourceClient()
.query(query)
.addOnSuccessListener(this,
new OnSuccessListener<MetadataBuffer>() {
#Override
public void onSuccess(MetadataBuffer metadataBuffer) {
//mResultsAdapter.append(metadataBuffer);
for (int i = 0; i <metadataBuffer.getCount() ; i++) {
retrieveContents(metadataBuffer.get(i).getDriveId().asDriveFile());
}
}
}
)
.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG, "Error retrieving files", e);
MainActivity.this.finish();
}
});
}
to download the content the the following code
private void retrieveContents(DriveFile file) {
// [START drive_android_open_file]
Task<DriveContents> openFileTask =
getDriveResourceClient().openFile(file, DriveFile.MODE_READ_ONLY);
// [END drive_android_open_file]
// [START drive_android_read_contents]
openFileTask
.continueWithTask(task -> {
DriveContents contents = task.getResult();
// Process contents...
// [START_EXCLUDE]
// [START drive_android_read_as_string]
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(contents.getInputStream()))) {
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append("\n");
}
showMessage(getString(R.string.content_loaded));
mFileContents.setText(builder.toString());
}
// [END drive_android_read_as_string]
// [END_EXCLUDE]
// [START drive_android_discard_contents]
Task<Void> discardTask = getDriveResourceClient().discardContents(contents);
// [END drive_android_discard_contents]
return discardTask;
})
.addOnFailureListener(e -> {
// Handle failure
// [START_EXCLUDE]
Log.e(TAG, "Unable to read contents", e);
showMessage(getString(R.string.read_failed));
finish();
// [END_EXCLUDE]
});
// [END drive_android_read_contents]
}
Related
Myself and many others have been struggling with setting up the Google Drive REST API v3 to work with Android apps. This mainly stems from the fact that the official Google documentation is missing a proper quick start guide for Android and we are left with finding scraps of (outdated and/or confusing) information dotted around - but what is needed is a complete up to date guide aimed at beginners to get us up and running so that they can open and edit files on their Drive, including how to set up credentials, dependencies, and manifests.
So I am asking if anyone would be willing to create such a guide, or can point to such a guide that has already been made that is a) relevant to the latest version of Google Drive API REST v3 detailed here and b) covers ALL above aspects that a beginner would need to be get started?
The guidelines posted by ArtOfWarfare here are absolutely perfect and exactly what I'm looking for - but are unfortunately out of date by several years. Can anyone provide an up-to-date version of this guide? Thank you kindly.
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.
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.
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.
I need that as well. I managed to build something that works though not optimal from these links :
Google guides for REST API v3
Google Github demo project for migration to REST after deprecation of the other method
Documentation for REST API v3
My main remaining problem now is to find a file/folder picker. The one in the demo project uses SAF which does not allow to retrieve the ID of the file you picked (Oo !!!)
The article that I referred to while trying to figure out how to use the Drive REST API was on this page
I'm pretty new to Android, but here's how I get the list of files' IDs. Hope this helps you
create a method that returns a list of Files (do not mix them up with java.io.Files).
They are instances of com.google.api.services.drive.model.File;
The method below is a part of DriveServiceHelper class from the deprecation tutorial on github. Check the source files to see how mExecutor and mDriveService instances get created
public Task<FileList> queryFiles() {
return Tasks.call(mExecutor, () ->
mDriveService.files().list().setSpaces("drive").execute());
}
then you can iterate the list and get IDs of each file
for (File file : fileList.getFiles()) {
file.getId()
}
Once you get the ID, you can remove or update files
here's an example of a method for removing duplicate files your app will create each time you make an upload to google drive:
private void mQuery(String name) {
if (mDriveServiceHelper != null) {
Log.d(TAG, "Querying for files.");
mDriveServiceHelper.queryFiles()
.addOnSuccessListener(fileList -> {
for (File file : fileList.getFiles()) {
if(file.getName().equals(name))
mDriveServiceHelper.deleteFolderFile(file.getId()).addOnSuccessListener(v-> Log.d(TAG, "removed file "+file.getName())).
addOnFailureListener(v-> Log.d(TAG, "File was not removed: "+file.getName()));
}
})
.addOnFailureListener(exception -> Log.e(TAG, "Unable to query files.", exception));
}
}
and here's the deleteFolderFile method from DriveServiceHelper class
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;
});
}
NB! this is not the best approach if you need to perform a query on a large list of files. It's just a draft to help you get an idea. At least mQuery func can be improved by utilizing a binary search algorithm to look up a particular file in a list.
I created one project in which I have used the "Android Google DRIVE API V3" to create a folder, upload file, delete file, and download file feature in it.
The Complete android app with the code is present at https://github.com/prateekbangre/GoogleDrive_demo
Is Folder present:
public Task<String> isFolderPresent() {
return Tasks.call(mExecutor, () -> {
FileList result = mDriveService.files().list().setQ("mimeType='application/vnd.google-apps.folder' and trashed=false").execute();
for (File file : result.getFiles()) {
if (file.getName().equals(FOLDER_NAME))
return file.getId();
}
return "";
});
}
Create a folder:
public Task<String> createFolder() {
return Tasks.call(mExecutor, () -> {
File metadata = new File()
.setParents(Collections.singletonList("root"))
.setMimeType(FOLDER_MIME_TYPE)
.setName(FOLDER_NAME);
File googleFolder = mDriveService.files().create(metadata).execute();
if (googleFolder == null) {
throw new IOException("Null result when requesting Folder creation.");
}
return googleFolder.getId();
});
}
Get Files list:
public Task<ArrayList<GoogleDriveFileHolder>> getFolderFileList() {
ArrayList<GoogleDriveFileHolder> fileList = new ArrayList<>();
if (folderId.isEmpty()){
Log.e(TAG, "getFolderFileList: folder id not present" );
isFolderPresent().addOnSuccessListener(id -> folderId=id)
.addOnFailureListener(exception -> Log.e(TAG, "Couldn't create file.", exception));
}
return Tasks.call(mExecutor, () -> {
FileList result = mDriveService.files().list()
.setQ("mimeType = '" + SHEET_MIME_TYPE + "' and trashed=false and parents = '" + folderId + "' ")
.setSpaces("drive")
.execute();
for (int i = 0; i < result.getFiles().size(); i++) {
GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();
googleDriveFileHolder.setId(result.getFiles().get(i).getId());
googleDriveFileHolder.setName(result.getFiles().get(i).getName());
fileList.add(googleDriveFileHolder);
}
Log.e(TAG, "getFolderFileList: folderFiles: "+fileList );
return fileList;
});
}
Upload files to google drive:
public Task<Boolean> uploadFileToGoogleDrive(String path) {
if (folderId.isEmpty()){
Log.e(TAG, "uploadFileToGoogleDrive: folder id not present" );
isFolderPresent().addOnSuccessListener(id -> folderId=id)
.addOnFailureListener(exception -> Log.e(TAG, "Couldn't create file.", exception));
}
return Tasks.call(mExecutor, () -> {
Log.e(TAG, "uploadFileToGoogleDrive: path: "+path );
java.io.File filePath = new java.io.File(path);
File fileMetadata = new File();
fileMetadata.setName(filePath.getName());
fileMetadata.setParents(Collections.singletonList(folderId));
fileMetadata.setMimeType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
FileContent mediaContent = new FileContent("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", filePath);
File file = mDriveService.files().create(fileMetadata, mediaContent)
.setFields("id")
.execute();
System.out.println("File ID: " + file.getId());
return false;
});
}
Download File from google drive:
public Task<Boolean> downloadFile(final java.io.File fileSaveLocation, final String fileId) {
return Tasks.call(mExecutor, new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
// Retrieve the metadata as a File object.
OutputStream outputStream = new FileOutputStream(fileSaveLocation);
mDriveService.files().get(fileId).executeMediaAndDownloadTo(outputStream);
return true;
}
});
}
Delete File:
public Task<Boolean> deleteFolderFile(final String fileId) {
return Tasks.call(mExecutor, new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
// Retrieve the metadata as a File object.
if (fileId != null) {
mDriveService.files().delete(fileId).execute();
return true;
}
return false;
}
});
}
Above is the code same sample.
Myself and many others have been struggling with setting up the Google Drive REST API v3 to work with Android apps. This mainly stems from the fact that the official Google documentation is missing a proper quick start guide for Android and we are left with finding scraps of (outdated and/or confusing) information dotted around - but what is needed is a complete up to date guide aimed at beginners to get us up and running so that they can open and edit files on their Drive, including how to set up credentials, dependencies, and manifests.
So I am asking if anyone would be willing to create such a guide, or can point to such a guide that has already been made that is a) relevant to the latest version of Google Drive API REST v3 detailed here and b) covers ALL above aspects that a beginner would need to be get started?
The guidelines posted by ArtOfWarfare here are absolutely perfect and exactly what I'm looking for - but are unfortunately out of date by several years. Can anyone provide an up-to-date version of this guide? Thank you kindly.
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.
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.
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.
I need that as well. I managed to build something that works though not optimal from these links :
Google guides for REST API v3
Google Github demo project for migration to REST after deprecation of the other method
Documentation for REST API v3
My main remaining problem now is to find a file/folder picker. The one in the demo project uses SAF which does not allow to retrieve the ID of the file you picked (Oo !!!)
The article that I referred to while trying to figure out how to use the Drive REST API was on this page
I'm pretty new to Android, but here's how I get the list of files' IDs. Hope this helps you
create a method that returns a list of Files (do not mix them up with java.io.Files).
They are instances of com.google.api.services.drive.model.File;
The method below is a part of DriveServiceHelper class from the deprecation tutorial on github. Check the source files to see how mExecutor and mDriveService instances get created
public Task<FileList> queryFiles() {
return Tasks.call(mExecutor, () ->
mDriveService.files().list().setSpaces("drive").execute());
}
then you can iterate the list and get IDs of each file
for (File file : fileList.getFiles()) {
file.getId()
}
Once you get the ID, you can remove or update files
here's an example of a method for removing duplicate files your app will create each time you make an upload to google drive:
private void mQuery(String name) {
if (mDriveServiceHelper != null) {
Log.d(TAG, "Querying for files.");
mDriveServiceHelper.queryFiles()
.addOnSuccessListener(fileList -> {
for (File file : fileList.getFiles()) {
if(file.getName().equals(name))
mDriveServiceHelper.deleteFolderFile(file.getId()).addOnSuccessListener(v-> Log.d(TAG, "removed file "+file.getName())).
addOnFailureListener(v-> Log.d(TAG, "File was not removed: "+file.getName()));
}
})
.addOnFailureListener(exception -> Log.e(TAG, "Unable to query files.", exception));
}
}
and here's the deleteFolderFile method from DriveServiceHelper class
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;
});
}
NB! this is not the best approach if you need to perform a query on a large list of files. It's just a draft to help you get an idea. At least mQuery func can be improved by utilizing a binary search algorithm to look up a particular file in a list.
I created one project in which I have used the "Android Google DRIVE API V3" to create a folder, upload file, delete file, and download file feature in it.
The Complete android app with the code is present at https://github.com/prateekbangre/GoogleDrive_demo
Is Folder present:
public Task<String> isFolderPresent() {
return Tasks.call(mExecutor, () -> {
FileList result = mDriveService.files().list().setQ("mimeType='application/vnd.google-apps.folder' and trashed=false").execute();
for (File file : result.getFiles()) {
if (file.getName().equals(FOLDER_NAME))
return file.getId();
}
return "";
});
}
Create a folder:
public Task<String> createFolder() {
return Tasks.call(mExecutor, () -> {
File metadata = new File()
.setParents(Collections.singletonList("root"))
.setMimeType(FOLDER_MIME_TYPE)
.setName(FOLDER_NAME);
File googleFolder = mDriveService.files().create(metadata).execute();
if (googleFolder == null) {
throw new IOException("Null result when requesting Folder creation.");
}
return googleFolder.getId();
});
}
Get Files list:
public Task<ArrayList<GoogleDriveFileHolder>> getFolderFileList() {
ArrayList<GoogleDriveFileHolder> fileList = new ArrayList<>();
if (folderId.isEmpty()){
Log.e(TAG, "getFolderFileList: folder id not present" );
isFolderPresent().addOnSuccessListener(id -> folderId=id)
.addOnFailureListener(exception -> Log.e(TAG, "Couldn't create file.", exception));
}
return Tasks.call(mExecutor, () -> {
FileList result = mDriveService.files().list()
.setQ("mimeType = '" + SHEET_MIME_TYPE + "' and trashed=false and parents = '" + folderId + "' ")
.setSpaces("drive")
.execute();
for (int i = 0; i < result.getFiles().size(); i++) {
GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();
googleDriveFileHolder.setId(result.getFiles().get(i).getId());
googleDriveFileHolder.setName(result.getFiles().get(i).getName());
fileList.add(googleDriveFileHolder);
}
Log.e(TAG, "getFolderFileList: folderFiles: "+fileList );
return fileList;
});
}
Upload files to google drive:
public Task<Boolean> uploadFileToGoogleDrive(String path) {
if (folderId.isEmpty()){
Log.e(TAG, "uploadFileToGoogleDrive: folder id not present" );
isFolderPresent().addOnSuccessListener(id -> folderId=id)
.addOnFailureListener(exception -> Log.e(TAG, "Couldn't create file.", exception));
}
return Tasks.call(mExecutor, () -> {
Log.e(TAG, "uploadFileToGoogleDrive: path: "+path );
java.io.File filePath = new java.io.File(path);
File fileMetadata = new File();
fileMetadata.setName(filePath.getName());
fileMetadata.setParents(Collections.singletonList(folderId));
fileMetadata.setMimeType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
FileContent mediaContent = new FileContent("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", filePath);
File file = mDriveService.files().create(fileMetadata, mediaContent)
.setFields("id")
.execute();
System.out.println("File ID: " + file.getId());
return false;
});
}
Download File from google drive:
public Task<Boolean> downloadFile(final java.io.File fileSaveLocation, final String fileId) {
return Tasks.call(mExecutor, new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
// Retrieve the metadata as a File object.
OutputStream outputStream = new FileOutputStream(fileSaveLocation);
mDriveService.files().get(fileId).executeMediaAndDownloadTo(outputStream);
return true;
}
});
}
Delete File:
public Task<Boolean> deleteFolderFile(final String fileId) {
return Tasks.call(mExecutor, new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
// Retrieve the metadata as a File object.
if (fileId != null) {
mDriveService.files().delete(fileId).execute();
return true;
}
return false;
}
});
}
Above is the code same sample.
Using the bellow snippet I am able to access folder which I have already created with the same app. I am using 'com.google.android.gms:play-services-drive:9.0.0' library and referring google drive sample on github. using the sample CreateFolderInFolderActivity.java I am able to create folder inside an existing folder. Instead of creating folder I need to create a file inside existing folder.
public class CreateFileInsideFolderActivity extends BaseDemoActivity {
private static final String TAG = "CreateFileActivity";
#Override
public void onConnected(Bundle connectionHint) {
super.onConnected(connectionHint);
Drive.DriveApi
.fetchDriveId(getGoogleApiClient(), "0B_cMuo4-XwcAZ3IzSG1jajFlWk0")
.setResultCallback(idCallback);
}
final ResultCallback<DriveApi.DriveIdResult> idCallback = new ResultCallback<DriveApi.DriveIdResult>() {
#Override
public void onResult(DriveApi.DriveIdResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Cannot find DriveId. Are you authorized to view this file?");
return;
}
DriveId driveId = result.getDriveId();
//showMessage("driveid" + driveId.getResourceId());
final DriveFolder folder = driveId.asDriveFolder();
//
// How to upload a file to this folder
//
}
Thanks #pinoyyid
I fount an example from wiki.workassis that I am sharing here. If anyone have better solution please share with me
#Override
public void onConnected(Bundle connectionHint) {
super.onConnected(connectionHint);
Drive.DriveApi.newDriveContents(getGoogleApiClient()).setResultCallback(driveContentsCallback);
}
In result call back
final private ResultCallback<DriveApi.DriveContentsResult> driveContentsCallback = new ResultCallback<DriveApi.DriveContentsResult>() {
#Override
public void onResult(DriveApi.DriveContentsResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Error while trying to create new file contents");
return;
}
final DriveContents driveContents = result.getDriveContents();
// Perform I/O off the UI thread.
new Thread() {
#Override
public void run() {
OutputStream outputStream = driveContents.getOutputStream();
try {
InputStream inputStream = getContentResolver().openInputStream(imageUri);
if (inputStream != null) {
byte[] data = new byte[1024];
while (inputStream.read(data) != -1) {
outputStream.write(data);
}
inputStream.close();
}
outputStream.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle("New file")
.setMimeType("image/jpg")
.setStarred(true).build();
DriveApi.DriveIdResult exFolderResult = Drive.DriveApi
.fetchDriveId(getGoogleApiClient(), ExistingFolderID)
.await();
if (!exFolderResult.getStatus().isSuccess()) {
showMessage("Cannot find DriveId. Are you authorized to view this file?");
return;
}
DriveId driveId = exFolderResult.getDriveId();
//showMessage("driveid" + driveId.getResourceId());
final DriveFolder folder = driveId.asDriveFolder();
// create a file on root folder
folder.createFile(getGoogleApiClient(), changeSet, driveContents)
.setResultCallback(fileCallback);
}
}.start();
}
};
I am using the default file picker for getting Image url
refer : http://wiki.workassis.com/google-drive-android-api-upload-file-to-existing-folder/
for file picker : http://wiki.workassis.com/android-create-a-file-picker/
I'm trying using the Google API for Android to create a file, search, download and delete in the app folder.
But i'm getting some problems...
If i use the 'getRootFolder()' to save my file everything works. But, if i use 'getAppFolder()' nothing works.
Example:
The user download my app, my app search if exist any created file.
If nothing return the app create a new file in AppFolder.
If the user uninstall the app and download again, the app can't reach the file.
I try 'requestSync' but nothing happens. I trying using the Listening for Changes and Receiving completion Events, they return 'Success' but still not sync the AppFolder.
I saw some similar problems, but none works for me.
If i use the 'getRootFolder()' everything works great...
Can you guys help?
Here some Code Examples:
OnConnected:
#Override
public void onConnected(Bundle connectionHint) {
super.onConnected(connectionHint);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
if (sharedPreferences.getBoolean("automaticBackup", true)) {
String FILE_PATH = this.getDatabasePath(DataHelper.DATABASE_NAME).getPath();
String extension = MimeTypeMap.getFileExtensionFromUrl(FILE_PATH);
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
file = new File(FILE_PATH);
if (hasInternetAccess()) {
if (sharedPreferences.getBoolean("firstUse", true)) {
Drive.DriveApi.query(getGoogleApiClient(), query).setResultCallback(restoreCallBack);
final SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean("firstUse", false);
editor.apply();
} else {
// delete existing backup
Drive.DriveApi.query(getGoogleApiClient(), query).setResultCallback(checkIfFileExists);
}
}
}
}
Here i check if file exist, true delete, false create a new one:
final private ResultCallback<DriveApi.MetadataBufferResult> checkIfFileExists = new ResultCallback<DriveApi.MetadataBufferResult>() {
private DriveId fileId;
#Override
public void onResult(#NonNull DriveApi.MetadataBufferResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Problem while checking if file exists...");
return;
}
MetadataBuffer metadata = result.getMetadataBuffer();
if (metadata.getCount() > 0) {
fileId = metadata.get(0).getDriveId();
if (fileId != null) {
Drive.DriveApi.fetchDriveId(getGoogleApiClient(), fileId.getResourceId()).setResultCallback(deleteFile);
}
} else {
Log.d(TAG, "No backup file found");
// create new contents resource
Drive.DriveApi.newDriveContents(getGoogleApiClient()).setResultCallback(createBackupCallBack);
}
}
};
Here the code to delete:
final private ResultCallback<DriveApi.DriveIdResult> deleteFile = new ResultCallback<DriveApi.DriveIdResult>() {
#Override
public void onResult(#NonNull DriveApi.DriveIdResult driveIdResult) {
final DriveId driveId = driveIdResult.getDriveId();
try {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
DriveId fileId = DriveId.decodeFromString(driveId.encodeToString());
DriveFile driveFile = fileId.asDriveFile();
com.google.android.gms.common.api.Status deleteStatus = driveFile.delete(getGoogleApiClient()).await();
if (!deleteStatus.isSuccess()) {
Log.e(TAG, "Unable to delete the old backup");
return null;
}
sharedPreferences.edit().remove(driveId.toString()).apply();
Log.d(TAG, "Removed old backup.");
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// create new contents resource
Drive.DriveApi.newDriveContents(getGoogleApiClient()).setResultCallback(createBackupCallBack);
}
}.execute().get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}
};
Upload the file to Drive:
final private ResultCallback<DriveApi.DriveContentsResult> createBackupCallBack = new
ResultCallback<DriveApi.DriveContentsResult>() {
#Override
public void onResult(#NonNull DriveApi.DriveContentsResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Error while trying to create new file contents");
return;
}
final DriveContents driveContents = result.getDriveContents();
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
OutputStream outputStream = driveContents.getOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
try {
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file));
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
outputStream.close();
inputStream.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle(DataHelper.DATABASE_NAME)
.setMimeType(type)
.setStarred(true).build();
Drive.DriveApi.getAppFolder(getGoogleApiClient())
.createFile(getGoogleApiClient(), changeSet, driveContents)
.setResultCallback(fileCallback);
return null;
}
}.execute();
}
};
Result Call Back from upload:
final private ResultCallback<DriveApi.MetadataBufferResult> restoreCallBack = new ResultCallback<DriveApi.MetadataBufferResult>() {
DriveId driveId;
#Override
public void onResult(#NonNull DriveApi.MetadataBufferResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Problem while restoring...");
}
MetadataBuffer metadata = result.getMetadataBuffer();
if (metadata.getCount() > 0) {
File fileBD = getDatabasePath(DataHelper.DATABASE_NAME);
boolean deleted = fileBD.delete();
Log.d("DELETED", deleted + "");
driveId = metadata.get(0).getDriveId();
Drive.DriveApi.fetchDriveId(getGoogleApiClient(), driveId.getResourceId()).setResultCallback(idCallback);
} else {
Log.d(TAG, "No backup file found!");
}
}
};
It may be permission issue. Adding drive.appfolder authorization scopes to GoogleApiClient may solve your problem. For example:
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_APPFOLDER) // required to access app folder
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.build();
mGoogleApiClient.connect();
Found a solution, you need to sync with the drive before querying the AppFolder.
Use this after connecting to the drive:
Drive.DriveApi.requestSync(mGoogleApiClient).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
}
});
I have spent too much time on this so I would like to ask about it. I want to create and upload google spreadsheet using android. I know that I should use Drive API to do this. I know how to create file using this API(even excel file) but when setMimeType is set to application/vnd.google-apps.spreadsheet I receive an error on the device: Error while trying to create the file.
#Override
public void onConnected(Bundle connectionHint) {
super.onConnected(connectionHint);
// create new contents resource
Drive.DriveApi.newDriveContents(getGoogleApiClient())
.setResultCallback(driveContentsCallback);
}
final private ResultCallback<DriveContentsResult> driveContentsCallback = new
ResultCallback<DriveContentsResult>() {
#Override
public void onResult(DriveContentsResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Error while trying to create new file contents");
return;
}
final DriveContents driveContents = result.getDriveContents();
// Perform I/O off the UI thread.
new Thread() {
#Override
public void run() {
// write content to DriveContents
OutputStream outputStream = driveContents.getOutputStream();
Writer writer = new OutputStreamWriter(outputStream);
try {
writer.write("Hello World!");
writer.write("Hello World!");
writer.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle("Orders")
.setMimeType("application/vnd.google-apps.spreadsheet")
.setStarred(true).build();
// create a file on root folder
Drive.DriveApi.getRootFolder(getGoogleApiClient())
.createFile(getGoogleApiClient(), changeSet, driveContents)
.setResultCallback(fileCallback);
}
}.start();
}
};
final private ResultCallback<DriveFileResult> fileCallback = new
ResultCallback<DriveFileResult>() {
#Override
public void onResult(DriveFileResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Error while trying to create the file");
return;
}
showMessage("Created a file with content: " + result.getDriveFile().getDriveId());
storeId(result.getDriveFile().getDriveId());
kill_activity();
}
};v
The GDAA does not currently support creation Google Docs files. You will have to use the Google Drive REST API in your Android application to do this.
#user3212019, You can upload a excel spread sheet in google drive from your android app, just follow as below.
I think you aware of Quick Start on Google Android site.
Now create a excel sheet by using jxl jar library
Now follow the Start Integrating Google Sign-In and Integrate Google SignIn with Drive scope (Drive.SCOPE_FILE) in your app.
Now final and last copy paste below activity code in your activity and then give a excel sheet path in saveFileToDrive(file_path) method.
public class UploadFileInGoogleDriveActivity extends Activity {
private static final String TAG = "tejadroid-quickstart";
private static final int REQUEST_CODE_SIGN_IN = 0;
private GoogleSignInClient mGoogleSignInClient;
private DriveClient mDriveClient;
private DriveResourceClient mDriveResourceClient;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
signIn();
}
/**
* Start sign in activity.
*/
private void signIn() {
Log.i(TAG, "Start sign in");
mGoogleSignInClient = buildGoogleSignInClient();
startActivityForResult(mGoogleSignInClient.getSignInIntent(), REQUEST_CODE_SIGN_IN);
}
/**
* Build a Google SignIn client.
*/
private GoogleSignInClient buildGoogleSignInClient() {
GoogleSignInOptions signInOptions =
new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(Drive.SCOPE_FILE)
.build();
return GoogleSignIn.getClient(this, signInOptions);
}
#Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_CODE_SIGN_IN:
Log.i(TAG, "Sign in request code");
// Called after user is signed in.
if (resultCode == RESULT_OK) {
Log.i(TAG, "Signed in successfully.");
// Use the last signed in account here since it already have a Drive scope.
mDriveClient = Drive.getDriveClient(this, GoogleSignIn.getLastSignedInAccount(this));
// Build a drive resource client.
mDriveResourceClient =
Drive.getDriveResourceClient(this, GoogleSignIn.getLastSignedInAccount(this));
// Excel Sheet path from SD card
final String filePath = "/storage/emulated/0/Expense Manager/ExpenseReport/ExpenseDiary.xls";
saveFileToDrive(filePath);
}
break;
}
}
/**
* Create a new file and save it to Drive.
*/
private void saveFileToDrive(final String filePath) {
// Start by creating a new contents, and setting a callback.
Log.i(TAG, "Creating new contents.");
mDriveResourceClient
.createContents()
.continueWithTask(
new Continuation<DriveContents, Task<Void>>() {
#Override
public Task<Void> then(#NonNull Task<DriveContents> task) throws Exception {
return createFileIntentSender(task.getResult(), new File(filePath));
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Failed to create new contents.", e);
}
});
}
/**
* Creates an {#link IntentSender} to start a dialog activity with configured {#link
* CreateFileActivityOptions} for user to create a new photo in Drive.
*/
private Task<Void> createFileIntentSender(DriveContents driveContents, File file) throws Exception {
Log.i(TAG, "New contents created.");
OutputStream outputStream = driveContents.getOutputStream();
InputStream in = new FileInputStream(file);
try {
try {
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
outputStream.write(buf, 0, len);
}
} finally {
outputStream.close();
}
} finally {
in.close();
}
// Create the initial metadata - MIME type and title.
// Note that the user will be able to change the title later.
MetadataChangeSet metadataChangeSet =
new MetadataChangeSet.Builder()
.setMimeType("application/vnd.ms-excel")
.setTitle("ExcelSheet.xls")
.build();
// Set up options to configure and display the create file activity.
CreateFileActivityOptions createFileActivityOptions =
new CreateFileActivityOptions.Builder()
.setInitialMetadata(metadataChangeSet)
.setInitialDriveContents(driveContents)
.build();
return mDriveClient
.newCreateFileActivityIntentSender(createFileActivityOptions)
.continueWith(
new Continuation<IntentSender, Void>() {
#Override
public Void then(#NonNull Task<IntentSender> task) throws Exception {
startIntentSenderForResult(task.getResult(), REQUEST_CODE_CREATOR, null, 0, 0, 0);
return null;
}
});
}
}
Just debug app and look in to Google Drive there your file exist in root folder of drive.