Ion Android and wrong URL - android

I'm using Ion library for Android https://github.com/koush/ion
I download files from server and when I pass the url for file that is not on the server it is saved on sd card anyway. To be clear, let's assume I have following url: https://example.com/img/img_3.jpg but there is no such file. So actually this url is 404 Not Found, but ion creates a file img_3.jpg on my SD card. When I open the image it is blank. I've tried to check if downloaded file is empty, but it's not. So is there any possibility to forbid ion to download from not existing URL.
Here is my code:
private void executeDownload(final FilesToDownload downloadFiles) {
if (downloading != null && !downloading.isCancelled()) {
resetDownload();
return;
}
FileAndDirName fileAndDir = downloadFiles.popFileAndDirName();
final int size = downloadFiles.getFilesAndDirSize();
final String fileName = fileAndDir.getFileName();
final String dirName = fileAndDir.getDirName();
String url = mServerUrl + dirName + "/" + fileName;
File dir = new File(root.getAbsolutePath() + "/seatconnect/" + dirName);
if (!dir.exists()) {
dir.mkdirs();
}
final File destinationFile = new File(dir, fileName);
downloading = Ion.with(getActivity())
.load(url)
// attach the percentage report to a progress bar.
// can also attach to a ProgressDialog with progressDialog.
.progressBar(mProgressBar)
.progressDialog(mProgressDialog)
// callbacks on progress can happen on the UI thread
// via progressHandler. This is useful if you need to update a TextView.
// Updates to TextViews MUST happen on the UI thread.
.progressHandler(new ProgressCallback() {
#Override
public void onProgress(long downloaded, long total) {
// mProgressDialog.setProgress((int) downloaded);
}
})
// write to a file
.write(destinationFile)
// run a callback on completion
.setCallback(new FutureCallback<File>() {
#Override
public void onCompleted(Exception e, File result) {
resetDownload();
if (e != null) {
Toast.makeText(getActivity(), "Error downloading file " + fileName, Toast.LENGTH_SHORT).show();
// return;
} else {
Toast.makeText(getActivity(), "File download complete " + fileName, Toast.LENGTH_SHORT).show();
}
if (result.exists() && result.length() == 0) {
String message = result.delete() ? "Deleted empty file " : "The file is not empty ";
message += fileName;
Log.d(TAG, message);
}
if (size != 0) {
mProgressDialog.show();
executeDownload(downloadFiles);
return;
}
mProgressBar.setVisibility(View.INVISIBLE);
if (mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
mNewsFooterCheckForUpdateButton.setVisibility(View.VISIBLE);
mNewsFooterUpdateButton.setVisibility(View.INVISIBLE);
}
});
}

Maybe too late but I think you can handle it by using withResponse()which basically embeds the downloaded file within a com.koushikdutta.ion.Response object, which of course contains headers. Then you can check them to be sure that no error code was returned.
downloading = Ion.with(getActivity())
.load(url)
.progressBar(mProgressBar)
.write(destinationFile)
.withResponse() // response will incapsulates the result file
.setCallback(new FutureCallback<Response<File>>()
#Override
public void onCompleted(Exception e, Response<File> response) {
File result = null;
if (e != null || response.getHeaders().code() != 200)) { // check response headers
// an error was occurred
// ...
} else {
// file was successfully downloaded
result = response.getResult();
// ...
}
});

Related

Is there any way to programmatically upload files from Android application to Google Drive? [duplicate]

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.

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

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.

What should we use for downloading large files from remote server. Service? IntentService? AsyncTask? Thread? or something else in android?

I am new to android, I have gone through many of the forums and discussions but still I am confused about what should I use for downloading large files from server!
In our App we are playing multiple videos in a playlist on the app frontend and meanwhile we are calling API service to get list videos in playlist, we are calling the API within an asynctask and onpostexecute method parse the API response and queue any new files to download in the downloadmanger.
The points of concern
Is using asynctask for fetching response from remote API enough? or is there any better option for us?
Calling download manager from main is a bad practice as I understand from reading, then whats the best way to go (Service, IntentService, Thread or AsyncTask)? What will be the difference of using Service, IntentService, Thread or AsyncTask in this scenario.
Can we execute the download when the app is kickedoff when in case of incoming call or user clicks home button, so the download should still continue and don't waste bandwidth, memory etc used for already downloaded part.
Can we initiate a download even if the app is in background?
Should we do the database operations in a different thread, is it the best practice?
public class MediaAsyncTask extends AsyncTask>
{
#Override
protected List<Media> doInBackground(String... params) {
List<Media> result = new ArrayList<Media>();
try {
ResponseHandler responseHandlerObj = new ResponseHandler(getApplicationContext());
result = responseHandlerObj.deviceMedia(device_id);
media_status = responseHandlerObj.getResponse_status();
media_msg = responseHandlerObj.getResponse_msg();
media_version = responseHandlerObj.getMedia_version();
medias_total = responseHandlerObj.getMedias_total();
} catch (Exception e) {
Log.d(TAG, e.getLocalizedMessage());
e.printStackTrace();
}
return result;
}
#Override
protected void onPostExecute(List<Media> result) {
Log.e(TAG, "status " + media_status);
if (media_status.equals(STATUS_SUCCESS)) {
Log.d(TAG, media_msg);
if (device_path != null) {
int _total_downloaded = databaseHandler.getDownloadedMediaCount(device_id);
int _total_in_api = medias_total;
int _downloaded_version = preferenceHelper.getDeviceMediaVersion(device_id);
Log.d(TAG, "media_version : " + media_version + " _downloaded_version : " + _downloaded_version + " _total_downloaded : " + _total_downloaded + " _total_in_api : " + _total_in_api);
//remove true after testing
if (media_version != _downloaded_version || _total_downloaded != _total_in_api) {
databaseHandler.deleteAllDeviceMedias(device_id);
int id;
String file;
for (Media media : result) {
id = 0;
file = media.getFile();
String file_url = media.getFile_url();
Log.d(TAG, "media file exists: " + fileManager.checkFileExists(device_path, file));
if (file != null && !fileManager.checkFileExists(device_path, file) && URLUtil.isValidUrl(file_url)) {
media.setDownloaded(0);
id = databaseHandler.saveMedia(media);
queueDownload(file_url, file);
} else if (fileManager.checkFileExists(device_path, file)) {
long app_size = (int) fileManager.getFileSize(device_path + "/" + file);
long server_size = media.getFile_size();
long server_size_minus = server_size - 100;
if (app_size < server_size_minus) {
fileManager.deleteFile(device_path + "/" + file);
queueDownload(file_url, file);
} else {
id = saveDownloadedResource(media);
}
}
}
}
if (download_files.size() == 0) {
Log.d(TAG, "nothing to download");
preferenceHelper.setDeviceMediaVersion(device_id, media_version);
}
}
} else {
Log.e(TAG, "Media: Failed to fetch data!");
}
}
private int saveDownloadedResource(Media media) {
int id = 0;
media.setDownloaded(1);
id = databaseHandler.saveMedia(media);
initUpdateLayoutOnNewResource();
return id;
}
}

ownCloud Android DownloadRemoteFile File Name

I'm trying to download a list of RemoteFiles in Android using ownCloud. I can download the files perfectly fine but I'd like to notify the user when a file finishes. I'm downloading an entire directory:
#Override
public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
if (operation instanceof ReadRemoteFolderOperation) {
if (result.isSuccess()) {
Toast.makeText(this, "Finished reading folder", Toast.LENGTH_SHORT).show();
for (Object o : result.getData()) {
RemoteFile remoteFile = (RemoteFile) o;
String remotePath = remoteFile.getRemotePath();
File targetDirectory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
"/owncloud_download");
downloadHelper.downloadFile(remoteFile, targetDirectory);
}
}
}
if (operation instanceof DownloadRemoteFileOperation) {
if (result.isSuccess()) {
// Notify the user here that the file finished
}
}
}
I've looked at the ownCloud library source but can't seem to find what a DownloadRemoteFileOperation returns as a result other than a boolean indicating success and an HTTP status code. I thought it might be in result.getLogMessage() but that just gives me an HTTP 200 status. How can I get the name of a file that's finished?
Edit: I also looked at result.getData() but that's null in a DownloadRemoteFileOperation.
Here's my workaround for the time being. I didn't want to modify the ownCloud library source (again) so instead I just do a check in onTransferProgress like so:
#Override
public void onTransferProgress(long rate, long transferred, long total, String fileName) {
if (transferred == total) {
runOnUiThread(new Runnable() {
// do the update here, file name is available
}
}
}
Here's another option. I needed the file being uploaded if the upload failed so I modified the ownCloud library source. This way I could return file names in the RemoteOperationResult.
RemoteOperationResult.java:
private String fileName;
public String getFileName() {
return fileName;
}
public void setFileName(String name) {
fileName = name;
}
DownloadRemoteFileOperation.java
#Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
/// download will be performed to a temporal file, then moved to the final location
File tmpFile = new File(getTmpPath());
/// perform the download
try {
tmpFile.getParentFile().mkdirs();
int status = downloadFile(client, tmpFile);
result = new RemoteOperationResult(isSuccess(status), status,
(mGet != null ? mGet.getResponseHeaders() : null));
Log_OC.i(TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " +
result.getLogMessage());
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " +
result.getLogMessage(), e);
}
// Added this line
result.setFileName(mRemotePath);
return result;
}
UploadRemoteFileOperation.java:
#Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
try {
// / perform the upload
synchronized (mCancellationRequested) {
if (mCancellationRequested.get()) {
throw new OperationCancelledException();
} else {
mPutMethod = new PutMethod(client.getWebdavUri() +
WebdavUtils.encodePath(mRemotePath));
}
}
int status = uploadFile(client);
if (mForbiddenCharsInServer){
result = new RemoteOperationResult(
RemoteOperationResult.ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER);
} else {
result = new RemoteOperationResult(isSuccess(status), status,
(mPutMethod != null ? mPutMethod.getResponseHeaders() : null));
}
} catch (Exception e) {
// TODO something cleaner with cancellations
if (mCancellationRequested.get()) {
result = new RemoteOperationResult(new OperationCancelledException());
} else {
result = new RemoteOperationResult(e);
}
}
// Added this line
result.setFileName(mLocalPath);
return result;
}

How to sync image folder from Android phone to Dropbox using Dropbox Sync Api

How to sync the entire image folder in Android phone to Dropbox using Dropbox Sync Api?
My app only has access to image file types as I want to only sync images to Dropbox. I got this error when I try to implement my current code:
03-04 20:38:42.010: W/libDropboxSync.so(thr)(23160): util.cpp:124: int dropbox_wait_for_first_sync(dbx_client_t*) should not be called on the main thread
03-04 20:38:42.020: W/libDropboxSync.so(ERR)(23160): DROPBOX_DISALLOWED: sync.hpp:300: app is not allowed to create file p(/i9)
Main part of the code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dropbox_activity);
mTestOutput = (TextView) findViewById(R.id.test_output);
mLinkButton = (Button) findViewById(R.id.link_button);
mLinkButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
onClickLinkToDropbox();
}
});
mDbxAcctMgr = DbxAccountManager.getInstance(getApplicationContext(), appKey, appSecret);
}
#Override
protected void onResume() {
super.onResume();
if (mDbxAcctMgr.hasLinkedAccount()) {
showLinkedView();
doDropboxTest();
} else {
showUnlinkedView();
}
}
private void showLinkedView() {
mLinkButton.setVisibility(View.GONE);
mTestOutput.setVisibility(View.VISIBLE);
}
private void showUnlinkedView() {
mLinkButton.setVisibility(View.VISIBLE);
mTestOutput.setVisibility(View.GONE);
}
private void onClickLinkToDropbox() {
mDbxAcctMgr.startLink((Activity)this, REQUEST_LINK_TO_DBX);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_LINK_TO_DBX) {
if (resultCode == Activity.RESULT_OK) {
doDropboxTest();
} else {
mTestOutput.setText("Link to Dropbox failed or was cancelled.");
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void doDropboxTest() {
mTestOutput.setText("Dropbox Sync API Version "+DbxAccountManager.SDK_VERSION_NAME+"\n");
try {
final String TEST_DATA = "Hello Dropbox";
final String TEST_FILE_NAME = "Pars";
DbxPath testPath = new DbxPath(DbxPath.ROOT, TEST_FILE_NAME);
// Create DbxFileSystem for synchronized file access.
DbxFileSystem dbxFs = DbxFileSystem.forAccount(mDbxAcctMgr.getLinkedAccount());
// Print the contents of the root folder. This will block until we can
// sync metadata the first time.
List<DbxFileInfo> infos = dbxFs.listFolder(DbxPath.ROOT);
mTestOutput.append("\nContents of app folder:\n");
for (DbxFileInfo info : infos) {
mTestOutput.append(" " + info.path + ", " + info.modifiedTime + '\n');
}
// Create a test file only if it doesn't already exist.
if (!dbxFs.exists(testPath)) {
DbxFile testFile = dbxFs.create(testPath);
try {
testFile.writeString(TEST_DATA);
} finally {
testFile.close();
}
mTestOutput.append("\nCreated new file '" + testPath + "'.\n");
}
// Read and print the contents of test file. Since we're not making
// any attempt to wait for the latest version, this may print an
// older cached version. Use getSyncStatus() and/or a listener to
// check for a new version.
if (dbxFs.isFile(testPath)) {
String resultData;
DbxFile testFile = dbxFs.open(testPath);
try {
resultData = testFile.readString();
} finally {
testFile.close();
}
mTestOutput.append("\nRead file '" + testPath + "' and got data:\n " + resultData);
} else if (dbxFs.isFolder(testPath)) {
mTestOutput.append("'" + testPath.toString() + "' is a folder.\n");
}
} catch (IOException e) {
mTestOutput.setText("Dropbox test failed: " + e);
}
}
Your code tries to write a file called Pars, but you only have permission to write image files (ones with extensions like .jpg, .png, etc.). If you change your filename to something with an image extension, like Pars.jpg, you'll be able to write it.

Categories

Resources