I am programming an app that use a string (e.g. full name = "Adam Smith") and thus open corresponding "Adam Smith" folder in google drive. The next step is to show the content inside the folder.
Actually I am now able to access into google drive but unable to go into this specific folder. Can anyone post a sample code for me since I read the GoogleAPI webpage but cannot finish my app.
I am appreciated for suggestion in advance. Thank you
It is stated in this documentation that Folders provide a convenience method for listing their direct children using DriveFolder.listChildren. The sample code illustrates how to list files in a folder.
public void onConnected(Bundle connectionHint) {
super.onCreate(connectionHint);
setContentView(R.layout.activity_listfiles);
mResultsListView = (ListView) findViewById(R.id.listViewResults);
mResultsAdapter = new ResultsAdapter(this);
mResultsListView.setAdapter(mResultsAdapter);
DriveFolder folder = Drive.DriveApi.getFolder(getGoogleApiClient(), sFolderId);
folder.listChildren(getGoogleApiClient()).setResultCallback(childrenRetrievedCallback);
}
ResultCallback<MetadataBufferResult> childrenRetrievedCallback = new
ResultCallback<MetadataBufferResult>() {
#Override
public void onResult(MetadataBufferResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Problem while retrieving files");
return;
}
mResultsAdapter.clear();
mResultsAdapter.append(result.getMetadataBuffer());
showMessage("Successfully listed files.");
}
You can see more examples here.
Here are some related SO posts which might also help:
Android Google Drive SDK - how to show list of files in selected folder
Listing files and folders of GDrive using Google Drive Api
Happy coding!
Related
I am sure this is an easy question to answer, but I've been unable to find out how to instancate a DriveId and/or DriveFolder with the Drive resource id using the Google Drive Android API v 12.
I have read the Google Drive Android API documentation and have managed to create a file on my Google Drive from my Android app in the root folder, but now I want to create the file in a specific folder and I'm unsure how to go about this.
A lot of the code I've seen (such as this Stackoverflow answer) uses the deprecated Google DriveApi to get a DriveId from the resource id of the folder.
I have tried to use the DriveId method decodeFromString but when I ran the following code, I get an error saying the DriveId is invalid:
String googleDriveFolderId = "16TwNeDF9_inOK4X5AaGnVMNycNVxxMtd";
DriveFolder projectFolder = DriveId.decodeFromString(googleDriveFolderId).asDriveFolder();
What am I doing wrong?
Create a folder
To create a folder, call DriveResourceClient.createFolder(), passing
in a reference to the parent folder and the metadata object containing
the title and other attributes to set the values for the folder.
The following code sample demonstrates how to create a new folder in
the root folder:
private void createFolder() {
getDriveResourceClient()
.getRootFolder()
.continueWithTask(task -> {
DriveFolder parentFolder = task.getResult();
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle("New folder")
.setMimeType(DriveFolder.MIME_TYPE)
.setStarred(true)
.build();
return getDriveResourceClient().createFolder(parentFolder, changeSet);
})
.addOnSuccessListener(this,
driveFolder -> {
showMessage(getString(R.string.file_created,
driveFolder.getDriveId().encodeToString()));
finish();
})
.addOnFailureListener(this, e -> {
Log.e(TAG, "Unable to create file", e);
showMessage(getString(R.string.file_create_error));
finish();
});
}
on Success, try calling getDriveId().
What I am trying to do is simply not possible using the Google Drive Android API. I guess this is because the DriveResource does not get a resourceId until it has been uploaded.
See this SO answer which discusses how you aren't able to access any file or folder that isn't created by your app. I tested this and it's true - when I run a Query for a folder that I created manually in my root folder I cannot find it, but when I create a folder with the same name from my app, I get 1 query result.
Also see this SO thread which says you need to use another Google Drive API (they suggested the REST API) to be able to specify a folder programmatically (without using a popup where the user selects a folder). Unfortunately that won't work for me because I am building an offline app - precisely the reason I chose to work with Google Drive.
I ended up making a compromise and working with the root folder - luckily for me my project is to be used with very specific Google accounts so I am able to do this. My code looks something like this:
private void createFile() {
// [START create_file]
final Task<DriveFolder> rootFolderTask = getDriveResourceClient().getRootFolder();
final Task<DriveContents> createContentsTask = getDriveResourceClient().createContents();
Tasks.whenAll(rootFolderTask, createContentsTask)
.continueWithTask(task -> {
DriveFolder parent = rootFolderTask.getResult();
DriveContents contents = createContentsTask.getResult();
OutputStream outputStream = contents.getOutputStream();
try (Writer writer = new OutputStreamWriter(outputStream)) {
writer.write("Hello World!");
}
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle("HelloWorld.txt")
.setMimeType("text/plain")
.setStarred(true)
.build();
return getDriveResourceClient().createFile(parent, changeSet, contents);
})
.addOnSuccessListener(this,
driveFile -> {
showMessage(getString(R.string.file_created,
driveFile.getDriveId().encodeToString()));
finish();
})
.addOnFailureListener(this, e -> {
Log.e(TAG, "Unable to create file", e);
showMessage(getString(R.string.file_create_error));
finish();
});
// [END create_file]
}
If you can't compromise and use the root folder, I would suggest that you create a folder from within your app into the root folder and then save the string representation of the DriveId which you can use the next time you run the code. I haven't yet tested if the folder could be used by another instance of the app running on a different device, but I would hope so (fingers crossed).
Another option is displaying a popup so the user can select the folder manually. See this demo example.
I'd like for my app to be able to read from a pre-defined shared public Google Drive folder without the user having to log in or choose a Google account.
Background / Environment
Using my desktop browser, I have created a public folder on my Google Drive that is set up to be public. Anyone with the link may access (read) the drive, so no authorization is required:
In my Android Studio project, I have gone into File > Project Structure > Dependencies and added com.google.android.gms:play-services-drive:10.2.0
I now have the ability to create a new GoogleApiClient.Builder().
Question
I have looked at various examples, but in most cases, the drive has been created by the Android application. This is not the situation I'm trying to manage.
This question is about accessing a drive that has been made public using the "folder ID" or whatever you call 0B6X74x23H.... that was assigned when the folder was originally shared and made public.
I have examined the demo code provided by Google, but that, presumably, is not for a public folder because it says:
...need to register an OAuth 2.0 client
At a minimum, I could drive the process by using http-client, going to the sharing link https://drive.google.com/drive/folders/0B6X74x23Hx7DNE13M0ZIbVI....?usp=sharing with no authentication and not need to jump through hoops. But of course, it would be cleaner to use a defined API and simply specify the public shared folder in order to list the contents and, if needed, download the files from the public folder.
When I try this code:
Scope publicFolder = new Scope(EXISTING_FOLDER_ID);
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
.addApi(Drive.API)
.addScope(publicFolder)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
This method fires:
GoogleApiClient.OnConnectionFailedListener.onConnectionFailed()
The result contains statusCode=SIGN_IN_REQUIRED. But of course, sign-in is NOT required for a folder that's public.
Here is a workaround with Jsoup
implementation 'org.jsoup:jsoup:1.11.3'
val url = "https://drive.google.com/drive/folders/xxxxxxxxxxxxxxxxxx" // shared folder link
val doc = Jsoup.connect(url).get()
doc.outputSettings().prettyPrint(false)
val files = doc.select("div.WYuW0e")
for (file in files){
val fileName = file.text()
val fileID = file.attr("data-id")
val downloadLink = "https://drive.google.com/uc?export=download&id=$fileID"
//the downloadLink may open a 'Google Drive can't scan this file for viruses' page
// below we check for the new link
val doc2 = Jsoup.connect(downloadLink).get()
doc2.outputSettings().prettyPrint(false)
val elem = doc2.select("[id='uc-download-link']")
val newLink = if (elem.size != 0){
"https://drive.google.com" + elem.first().attr("href")
} else {
downloadLink
}
}
I want to retrieve metadata from files or folders in Google Drive on Android device in order to get deviceID or resourceID, so then I could download the file to local storage of the device. The problem with my application is that, the application doesn't need user interaction. It mean that, just tell the application the name so then the app will try to find the files in every directory and download it.
I have try to use query (link) follow quickstart tutorial but it return me only the name of the existing file only.
Note again: User does not need to select files or folders, just tell the name of the file is enough. And the file or folder is created by the application too.
How to get metadata from files or folders in Google Drive on Android?
According to Working with File and Folder Metadata:
Metadata is encapsulated in the Metadata class and contains all details about a file or folder including the title, the MIME type, and whether the file is editable, starred or trashed. The metadata is fetched for a DriveResource by calling the DriveResource.getMetadata method.
Here's a snippet from the docs:
/**
* An activity to retrieve the metadata of a file.
*/
public class RetrieveMetadataActivity extends BaseDemoActivity implements
ResultCallback {
#Override
public void onConnected(Bundle connectionHint) {
DriveFile file = Drive.DriveApi.getFile(getGoogleApiClient(),
DriveId.decodeFromString("0ByfSjdPVs9MZcEE3bzJCc3NsRkE"));
file.getMetadata(getGoogleApiClient()).setResultCallback(metadataRetrievedCallback);
}
ResultCallback<MetadataResult> metadataRetrievedCallback = new
ResultCallback<MetadataResult>() {
#Override
public void onResult(MetadataResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Problem while trying to fetch metadata");
return;
}
Metadata metadata = result.getMetadata();
showMessage("Metadata succesfully fetched. Title: " + metadata.getTitle());
}
}
}
How to get resource ID?
Still on the Android API for Drive, DriveId class has a method getResourceId () which returns the resource ID.
How to get device ID?
I don't think you can use the Android Drive API to get this. It seems you've mistaken this for fileID which you'll be using to Download Files.
Locate fileID manually in Google Drive:
If it's a spreadSheet file
https://docs.google.com/spreadsheets/d/1pE9ejBTBH38oCoOHU2O42qU6vzxagAJ9J1237dYB1Eg/edit#gid=0
fileID -> 1pE9ejBTBH38oCoOHU2O42qU6vzxagAJ9J1237dYB1Eg
If it's a doc file:
https://docs.google.com/document/d/1Fh6s7an-7I6VuDBxZKcxcaU3cG1XpSryHQXGnznWlns/edit
fileID -> 1Fh6s7an-7I6VuDBxZKcxcaU3cG1XpSryHQXGnznWlns
You get the pattern. It's a string of alphanumeric characters in the URL.
Let's say I use the Google Drive API to select a file that I want to open. I have this code to do so:
// Getting the drive ID for the file
DriveId driveId = (DriveId) data
.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
// Getting the selected file
DriveFile googleDriveFile = Drive.DriveApi.getFile(googleApiClient,
driveId);
googleDriveFile.open(googleApiClient, DriveFile.MODE_READ_ONLY,
null).setResultCallback(
new ResultCallback<DriveContentsResult>() {
#Override
public void onResult(DriveContentsResult result) {
if (result.getStatus().isSuccess()) {
Is there any way for me to get the file name of this file? (Not the drive ID, but its actual name?)
I'm trying to validate the chosen file (by checking its type, which is in the name), and I can't think of a way to do this other than get the name. The type is .cblite, a Couchbase Lite database file. Normally I'd just filter the Drive picker by MIME type, but .cblite (to my knowledge) isn't one of those options. Instead I'm trying to validate by file name.
Is there a way to do this? (Or is there a way to filter MIME types by miscellaneous/unidentified types?)
Yes, once you have DriveId, you can get metadata. And one of the metadata fields is getTitle() which will get you the file / folder name. Look at this code snippet:
DriveFile googleDriveFile = Drive.DriveApi.getFile(googleApiClient, driveId);
MetadataResult mdRslt = googleDriveFile .getMetadata(googleApiClient).await();
if (mdRslt != null && mdRslt.getStatus().isSuccess()) {
mdRslt.getMetadata().getTitle();
}
The 'await' flavor here is used for convenience, it must be run off-ui thread. Or just turn it into a callback style.
Good Luck
I am using Google Play Services SDK to integrate Google Drive.
My application need to show a list of all files in a folder.
From the demos: ListFilesInFolderActivity
I get the folder properly without any Authorization errors etc.. Because I changed the
com.google.android.gms.drive.sample.demo.BaseDemoActivity.EXISTING_FOLDER_ID
com.google.android.gms.drive.sample.demo.BaseDemoActivity.EXISTING_FILE_ID
values as per my application folder and file etc.
But in the
final private ResultCallback<MetadataBufferResult> metadataResult = new
ResultCallback<MetadataBufferResult>() {
#Override
public void onResult(MetadataBufferResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Problem while retrieving files");
return;
}
mResultsAdapter.clear();
mResultsAdapter.append(result.getMetadataBuffer());
showMessage("Successfully listed files.");
}
};
I only see the Toast "Successfully listed files." but nothing in the List. When checked for mResultsAdapter.getCount() it returns 0.
But the folder definitely has 1 file. What am I missing?
EDIT :
When I created folders/files from my application, they are visible. But folders/files added from web etc.. are not visible in the List.
Is it something like:
Only folders/files created by your application are accessible?
using
folder.listChildren(getGoogleApiClient()).setResultCallbackmetadataResult);
The Android API uses Drive.File scope, which means your app will only be able to see the files that the user has explicitly authorized your app to access. (Users much prefer this scope, since they have more control over who can see what data.)
If you open items with the same app on the web, they should be accessible to your Android app, but there may be some small delay in the showing up in the list response.