I'm building application using Google Drive api. But app folder not working after uninstalling the app. Here is what I been trying to do:
public searchFiles(){
GoogleApiClient googleApiClient = getGoogleApiClient();
Drive.DriveApi.getAppFolder(googleApiClient).listChildren(googleApiClient)
.setResultCallback(metadataBufferCallback);
}
private final ResultCallback<DriveApi.MetadataBufferResult> metadataBufferCallback = new
ResultCallback<DriveApi.MetadataBufferResult>() {
#Override
public void onResult(DriveApi.MetadataBufferResult result) {
if (!result.getStatus().isSuccess()) {
// Error
return;
}
MetadataBuffer metadataBuffer = result.getMetadataBuffer();
DriveId driveId = null;
if(metadataBuffer.getCount() > 0){
Metadata metadata = metadataBuffer.get(0);
driveId = metadata.getDriveId();
}
metadataBuffer.close();
if(driveId != null){
// success
}
else{
// omg, why?
}
}
};
I am not working with filters just yet, I got only got one file there. If I replace getAppFolder with getRootFolder it works just fine.
Also it works when it's cached, but once I uninstall the application metadataBuffer.getCount() is always return 0, even so in drive it says that I have 23 bytes of hidden data.
What am I missing here?
*I asked the user for SCOPE_APPFOLDER in the permissions. And I am running a signed version of the app.
Related
I am trying to access all files and folders from google drive to a arraya list. But I can get only one file from Drive. What to do get all files and folders from google drive. I am using the following code..
Thanks
Arun
public void onConnected(Bundle connectionHint) {
// Log.i(TAG, "API client connected.");
Toast.makeText(getActivity(), "Successfully logged in", Toast.LENGTH_LONG).show();
DriveFolder s = Drive.DriveApi.getRootFolder(mGoogleApiClient);
String s1 = (Drive.DriveApi.getRootFolder(mGoogleApiClient)).getDriveId().toString();
DriveId sFolderId2 = DriveId.decodeFromString(s1);
DriveId sFolderId = (Drive.DriveApi.getRootFolder(mGoogleApiClient)).getDriveId();
DriveFolder folder = Drive.DriveApi.getFolder(mGoogleApiClient, sFolderId);
folder.listChildren(mGoogleApiClient).setResultCallback(rootFolderCallback);
// findAll(folder);
}
public ResultCallback<DriveApi.MetadataBufferResult> rootFolderCallback = new
ResultCallback<DriveApi.MetadataBufferResult>() {
#Override
public void onResult(DriveApi.MetadataBufferResult result) {
if (!result.getStatus().isSuccess()) {
return;
}
resultarray = new ArrayList<String>();
int hh = result.getMetadataBuffer().getCount();
for (int i = 0; i < result.getMetadataBuffer().getCount(); i++) {
resultarray.add(result.getMetadataBuffer().get(i).getTitle());
}
Toast.makeText(getActivity(), "Successfully listed files.", Toast.LENGTH_LONG).show();
}
};
UPDATE (Aug 25, 2015, 10:39 MST)
Based on your comment below, you have 2 options:
1/ Stay with the GDAA, use one of the INTENTS:
- Pick a file with opener activity
- Pick a folder with opener activity
See, GDAA does not let your app see anything it did not create (SCOPE_FILE only), but it still allows user to browse everything. If the user selects a file, it will become visible to you app. I don't know your app's intentions, so I can't say if this approach is usable.
2/ Switch to the REST with the DRIVE scope and your app will see everything (user has to approve up front). The basic CRUD implementation can be found here but make sure you change the scope in the init() method to 'DriveScopes.DRIVE'.
In case your app needs to iterate down the folder tree, collecting files in the process, both 'testTree()' and 'deleteTree()' methods in the MainActivity() do exactly that.
You may also stay with the GDAA and add REST functionality to it by adding
com.google.api.services.drive.Drive mGOOSvc = new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(),
GoogleAccountCredential.usingOAuth2(appContext, Collections.singletonList(DriveScopes.DRIVE))
.setSelectedAccountName(email)
but you will sooner or later run into problems caused by GDAA caching / latency.
ORIGINAL ANSWER
Try this approach:
private static GoogleApiClient mGAC;
/****************************************************************************
* find file/folder in GOODrive
* #param prnId parent ID (optional), null searches full drive, "root" searches Drive root
* #param titl file/folder name (optional)
* #param mime file/folder mime type (optional)
* #return arraylist of found objects
*/
static void search(String prnId, String titl, String mime) {
if (mGAC != null && mGAC.isConnected()) {
// add query conditions, build query
ArrayList<Filter> fltrs = new ArrayList<>();
if (prnId != null){
fltrs.add(Filters.in(SearchableField.PARENTS,
prnId.equalsIgnoreCase("root") ?
Drive.DriveApi.getRootFolder(mGAC).getDriveId() : DriveId.decodeFromString(prnId)));
}
if (titl != null) fltrs.add(Filters.eq(SearchableField.TITLE, titl));
if (mime != null) fltrs.add(Filters.eq(SearchableField.MIME_TYPE, mime));
Query qry = new Query.Builder().addFilter(Filters.and(fltrs)).build();
// fire the query
Drive.DriveApi.query(mGAC, qry).setResultCallback(new ResultCallback<MetadataBufferResult>() {
#Override
public void onResult(MetadataBufferResult rslt) {
if (rslt != null && rslt.getStatus().isSuccess()) {
MetadataBuffer mdb = null;
try {
mdb = rslt.getMetadataBuffer();
if (mdb != null ) for (Metadata md : mdb) {
if (md == null || !md.isDataValid()) continue;
String title = md.getTitle();
DriveId driveId = md.getDriveId();
//.......
}
} finally { if (mdb != null) mdb.close(); }
}
}
});
}
}
Call it first with NULLs
search(null,null,null)
To list all the files in your Google Drive. You will see all the files your Android App created. But only those - FILE scope does not see anything else.
If you need to scan the directory tree, you may look closer at this GDAA demo, in MainActivity, there is are 'testTree()' / 'deleteTree() methods that recursively scan the directory tree structure.
Also, you may look at the answer here, it deals with a similar issue (especially the comments exchange under the answer).
Good Luck
Please note that you can use GDAA to retrieve the files and folder that you have either uploaded from the Android Device or downloaded via the drive app. This is to have more security (as quoted by Google).
In he code you need to ensure that you are trying all possible combinations for the files that may be present in your Google Drive account. For example, check if you are tracking the parent of a file or a folder. If this condition is not met your app wont be able to retrieve those specific files.
/** Get the list of parents Id in ascending order. */
private List<String> collectParents(String folderId, Map<String, String> folderIdToParentId){
String parentId = folderIdToParentId.get(folderId);
if (logger.isTraceEnabled()){
logger.trace("Direct parent of {} is {}", folderId, parentId);
}
List<String> ancestors = new ArrayList<String>();
ancestors.add(parentId);
if (folderIdToParentId.containsKey(parentId)){
ancestors.addAll(collectParents(parentId, folderIdToParentId));
return ancestors;
}
return ancestors;
}
See the full code here.
I'm trying to develop an android app that can read a xml file stored in my google drive folder, the idea at first is trying to open the file and handle the content.
I've read the Google Drive API docs for android and i reached a point that I'm lost, it's working with file contents.
According to this guide the way to open a file from drive is this:
DriveFile file = ...
file.open(mGoogleApiClient, DriveFile.MODE_READ_ONLY, null).setResultCallback(contentsOpenedCallback);`
Searching I realized that the complete code (that they not include there is):
DriveFile file = Drive.DriveApi.getFile(mGoogleApiClient,DriveId.bg(id));
file.open(mGoogleApiClient, DriveFile.MODE_READ_ONLY, null).setResultCallback(contentsOpenedCallback);`
Well the problem there is that I don't know the file "id". I've tried the id from the web link of google drive, something like this (https://drive.google.com/open?id=1EafJ-T6H4xI9VaUuUO5FMVb9Y30xyr7OHuISQ53avso&authuser=0) but didnĀ“t work.
You could use the DriveAPI Query method, to retrieve any information about an specific file. you will need to define a query object as the following:
Query query = new Query.Builder()
.addFilter(Filters.eq(SearchableField.TITLE, "HelloWorld.java"))
.build();
And set a callback function to iterate on the results:
Drive.DriveApi.query(googleApiClient, query)
.setResultCallback(new OnChildrenRetrievedCallback() {
#Override
public void onChildrenRetrieved(MetadataBufferResult result) {
// Iterate over the matching Metadata instances in mdResultSet
}
});
You can find more information on the topic here: https://developers.google.com/drive/android/queries
The solution i found for this problem was creating the file from the app. Using the class ("CreateFileActivity.java") from google drive api demo app.
With this class i save the returning Driveid from the new file in a global DriveId variable.
final private ResultCallback<DriveFolder.DriveFileResult> fileCallback = new
ResultCallback<DriveFolder.DriveFileResult>() {
#Override
public void onResult(DriveFolder.DriveFileResult result) {
if (!result.getStatus().isSuccess()) {
Log.e("","Error while trying to create the file");
return;
}
Id=result.getDriveFile().getDriveId();
Log.e("","Created a file with content: " + Id);
}
};
Then with this id in another method i call the file and read it (If i want i can edit this file information from Google Drive Web App):
public void leer(){
DriveFile file = Drive.DriveApi.getFile(getGoogleApiClient(),Id);
file.open(mGoogleApiClient, DriveFile.MODE_READ_ONLY, null)
.setResultCallback(contentsOpenedCallback);
}
ResultCallback<DriveApi.DriveContentsResult> contentsOpenedCallback =
new ResultCallback<DriveApi.DriveContentsResult>() {
#Override
public void onResult(DriveApi.DriveContentsResult result) {
if (!result.getStatus().isSuccess()) {
Log.e("Error:","No se puede abrir el archivo o no se encuentra");
return;
}
// DriveContents object contains pointers
// to the actual byte stream
DriveContents contents = result.getDriveContents();
BufferedReader reader = new BufferedReader(new InputStreamReader(contents.getInputStream()));
StringBuilder builder = new StringBuilder();
String line;
try {
while ((line = reader.readLine()) != null) {
builder.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
String contentsAsString = builder.toString();
Log.e("RESULT:",contentsAsString);
}
};
I've been playing with this stuff a few months back, and still have some code on GitHub. It may be VERY outdated (libver 15 or so), but it may serve as a reference point, and it is simple. Look here. Pull it down, plug in, step through. Fix what's not working anymore :-). I've abandoned it some time ago.
Be aware of the fact that there are 2 different IDs for Google Drive Android API objects, see SO 22841237.
In general, you usually start with knowing the file/folder name, query GDAA to get a list of objects. Each of them will yield DriveID and ResourceID. DriveID is used in your app to manipulate the objects (does not mean anything outside your Android App and/or device). ResourceID is the string that appears in different forms in URLs and can be used outside your app (web browser for instance...). Look at this wrapper to get some feeling how it works. But again, it's been a few versions back, so there are no guaranties.
The Google Drive API is deprecated, now its Google Drive V3 and for Query we use
String pageToken = null;
do {
FileList result = driveService.files().list()
.setQ("mimeType='image/jpeg'")
.setSpaces("drive")
.setFields("nextPageToken, files(id, name)")
.setPageToken(pageToken)
.execute();
for (File file : result.getFiles()) {
System.out.printf("Found file: %s (%s)\n",
file.getName(), file.getId());
}
pageToken = result.getNextPageToken();
}
while (pageToken != null);
You can Learn more here Officals Docs
i am using this code to retrieve the list of files and folders on Android, this returns only one file :(
{
Query query = new Query.Builder().setPageToken(mNextPageToken).build();
Drive.DriveApi.query(getGoogleApiClient(), query).setResultCallback(
metadataBufferCallback);
}
private final ResultCallback<MetadataBufferResult> metadataBufferCallback = new ResultCallback<MetadataBufferResult>() {
#Override
public void onResult(MetadataBufferResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Problem while retrieving files");
return;
}
mResultsAdapter.append(result.getMetadataBuffer());
mNextPageToken = result.getMetadataBuffer().getNextPageToken();
}
};
The Android API uses Drive.File scope, which gives your app access to the specific files created by it or explicitly opened with it by the user. The query will return the subset of files you have access to that match the query.
First error come when I'm trying to get Resource id from Driveid.
DriveFile dfile= Drive.DriveApi.getFile(mGoogleApiClient,DriveId.decodeFromString(driveId));
Log.e(TAG,"Driveid>>>>" + driveId);
String resourceID= dfile.getDriveId().getResourceId().toString();
Whenever I got Resource id and trying to delete item from google drive.
com.google.api.services.drive.Drive service;
service.files().delete(resourceID).execute();
Here Logcat ERROR:
Please Give me standard Solution for delete file from google drive.
For newly created files, the resourceId will not be populated right away. It will be populated once the file is committed to the server. You should check if it is null before using it.
For 'trash', there is no need to mix the GDAA with the REST Api anymore. Since GooPlaySvcs release 7.0 (March 2015), there is a 'trash()' method in the GDAA that does not require the ResourceId, shielding you from the timing issues related to the the latency/existence of it.
For short demonstration, here is a 'trash' wrapper for the GDAA that does not need ResourceId. On top of it, you don't need to worry about the network (wifi) on-line / off-line state.
private static GoogleApiClient mGAC;
...
static void trash(DriveId dId) {
if (mGAC != null && mGAC.isConnected() && dId != null) {
DriveResource driveResource;
if (dId.getResourceType() == DriveId.RESOURCE_TYPE_FOLDER) {
driveResource = Drive.DriveApi.getFolder(mGAC, dId);
} else {
driveResource = Drive.DriveApi.getFile(mGAC, dId);
}
if (driveResource != null) {
driveResource.trash(mGAC).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
// bingo, trashed successfully !!!
}
});
}
}
}
Good Luck
I'm using the AppFolder, and successfully reading/writing files to that folder. I can write a file to that folder on one device and read it on another device (using the same Google account).
However, every morning I wake up and find listChildren on the AppFolder returns an empty MetadataBuffer. When I look in Manage Apps section of the Google Drive website, there is clearly something (40KB) in my app's AppFolder.
What could be the possible reasons for this?
EDIT: Added some code
public void onConnected(Bundle bundle) {
DriveFolder folder = Drive.DriveApi.getAppFolder(mGoogleApiClient);
folder.listChildren(mGoogleApiClient).setResultCallback(mChildrenRetrievedCallback);
...
mChildrenRetrievedCallback = new ResultCallback<MetadataBufferResult>() {
public void onResult(MetadataBufferResult result) {
if (!result.getStatus().isSuccess()) {
// oh noes!
return;
}
MetadataBuffer buffer = result.getMetadataBuffer();
// buffer.getCount() is 0