I am making a notepad app using Google Drive. Whenever user creates a file in the app, it also creates a file in the Google Drive. And user can enter the text and save the file, the unsaved text will get committed whenever the internet is available. I am managing the update and create processes within the app using the DriveId.
If the user wants to use the files with the alternative device using my app, for that I also have the option called DriveId import. By clicking the option DriveId import user will be prompted with the input box for entering the existing DriveId. Using the DriveId I thought of opening the files, But it was giving an error.
Then I saw an answer given in this SO which clearly says DriveId can be used only inside the app and device which created the file.
I also found a similar question like mine in here SO But I can’t get my problem solved. I have taken ResourceId using result.getDriveFolder().getDriveId().getResourceId()
How to read the data’s programmatically using the ResourceID? As said in the above answer here I don’t want to change the track and go into Drive REST API. Is there a way that I can read the data using Google Drive Android API ? I have done all the development process, but in the ending when I try to access from other device it is giving the error. Totally struck.
If I can only read the data using REST API any simple code will be appreciated. Thanks in advance.
Finally Solved the DriveId Issue without REST API.
To get DriveId on the alternative device. You will need resourceId. You can use following code:-
String resourseId = "xxxxxxxxxxxxx"
Drive.DriveApi.fetchDriveId(mGoogleApiClient,resourseId).setResultCallback(idCallBack);
private ResultCallBack<DriveApi.DriveResult> idCallBack = new ResultCallback<DriveApi.DriveIdResult>() {
#Override
public void onResult(DriveApi.DriveIdResult driveIdResult) {
msg.Log("onResult");
DriveId id = driveIdResult.getDriveId(); //Here you go :)
}
}
Related
I am working on google drive api, I am using https://github.com/googledrive/android-demos but not getting notification.
I am not seeing any notification when I changed metadata of selected file from web.
Does anyone succeeded, please provide a link or demo so that a hurdle can be remove.
I have checked similar question Google Drive Android API Change Notifications not working, as I am unable to comment on this question due to less reputation.
You can use change listeners to receive notifications whenever a specified file or folder has changes to its contents or metadata.
Based from Google Drive API for Androids on how to listen for change events:
A change listener implements the OnChangeListener interface for the
ChangeEvent and receives a direct callback from the Drive service to a
currently connected client application.
You can add a change listener by calling the DriveResourceClient.addChangeListener method, passing in the file or folder you want to receive notifications for.
getDriveResourceClient()
.addChangeListener(file, changeListener)
.addOnSuccessListener(this, listenerToken -> mChangeListenerToken = listenerToken);
I am trying to download a doc.google file to my device, however I can't figure the best way for that..
First: I created an Auth key to my Drive following this tutorial
Then: I am trying to follow this tutorial to download the file, but It is not going well
I want to connect to this Auth key through the app and download/Export the file automatically without prompting the user to choose account or anything..
This is the URL for the doc file:
https://docs.google.com/spreadsheets/d/1QJTna4iz-VivwAzwgq7V5QDs2XbgM2lEFPEG7NqCPdo/
Thanks in advance
Try the method used in this SO post.
It was cited that to overcome the google problem when setting the file publicly. As in the post:
If you set the file permissions to be publicly available and
create/generate a direct access link by using something like the
gdocs2direct tool or just crafting the link yourself:
https://docs.google.com/uc?export=download&id=<your file id>
You will get a cookie based verification code and prompt "Google could
not scan this file" prompt, which won't work for things such as
wget or Vagrantfile configs.
The code that it generates is a simple code that appends GET query
variable ...&confirm=### to the string, but it's per user specific,
so it's not like you can copy/paste that query variable for others.
The specified web page hosting method will suffice.
I get an invalid parent folder error, and I've seen the solutions to use resource ID rather than Drive ID, but it's a different scenario here.
I'm trying to access the AppFolder, and this just uses the GoogleApiClient like so:
this.appFolder = Drive.DriveApi.getAppFolder(mGoogleApiClient);
When I later try to create a file in it, I get the above error.
DriveFolder.DriveFileResult fileResult = appFolder.createFile(mGoogleApiClient, changeSet, driveContentsResult.getDriveContents()).await();
Then fileResult.getStatus() gives me the erros.
This used to work for me before.
What's different is that I've manually emptied my app's data on Google Drive (delete hidden app data).
But I haven't disconnected the app - so I would assume that appFolder will continue to work the same way...
So far the only workaround is uninstalling the app, but this way I lose my data.
This is reproducible. Please help.
Update: This issue, #4483, was fixed in January 2017. The following fix may not apply anymore.
Since this continues to be an outstanding issue, I have taken steps to establish a work-around that can be done with code without resorting to user intervention.
As #seanpj says, this issue does not always occur and seems to be dependent upon the sync status of the Drive service. However, if the problem does occur, the following method works for me to circumvent the problem. I post it here in case it may be helpful to someone else. The Javadoc has more information.
/**
* Works around the Drive API for Android (GDAA) issue where the appDataFolder becomes
* unavailable after hidden app data is deleted through the online Drive interface
* (Settings->Manage Apps->Delete hidden app data) by using the REST v3 API to create an
* empty file in appDataFolder. The file is immediately deleted after creation but leaves
* the appDataFolder in working order.
* See <a href="https://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=4483"
* target="_blank">apps-api-issues #4483</a>
* <p>
* Call this method after a call to the Drive API fails with error code 1502
* (DriveStatusCodes.DRIVE_RESOURCE_NOT_AVAILABLE) when dealing with the appDataFolder then
* try the failed operation again.
* <p>
* This method assumes that all appropriate permissions have been granted and authorizations
* made prior to invocation.
*
* #param context - Context
* #param account The account name that has been authorized, e.g., someone#gmail.com.
* #throws IOException From the REST API.
*/
private void fixAppDataFolder(Context context, String account) throws IOException {
final String[] SCOPES = {DriveScopes.DRIVE_APPDATA};
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(
context, Arrays.asList(SCOPES)).setBackOff(new ExponentialBackOff());
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
com.google.api.services.drive.Drive driveService;
credential.setSelectedAccountName(account);
driveService = new com.google.api.services.drive.Drive.Builder(
transport, jsonFactory, credential)
.setApplicationName("Your app name here")
.build();
File fileMetadata = new File();
fileMetadata.setName("fixAppDataFolder")
.setMimeType("text/plain")
.setParents(Collections.singletonList("appDataFolder"));
File appDataFile = driveService.files()
.create(fileMetadata)
.setFields("id")
.execute();
driveService.files().delete(appDataFile.getId()).execute();
} // fixAppDataFolder
Although this does not solve your problem, your question got me interested, so I ran a little test using this demo (follow "appfolder" in this code). Here's what I learned:
First, I could reproduce your problem using the following sequence
1/ getAppFolder(mGAC)
2/ create folder DEMOROOT in app folder
3/ create folder 2015-10 in DEMOROOT
4/ create file with content in 151022-075754 in 2015-10
5/ list full tree ... result \DEMOROOT\2015-10\151022-075754
6/ read content of 151022-075754 ... OK
so far so good. Without disconnecting, I go to
drive.google.com > Settings > Manage Apps > Options > Delete hidden app data
Now, there should be no objects in the app folder, I run:
1/ getAppFolder(mGAC)
2/ list full tree ... result \DEMOROOT\2015-10\151022-075754
3/ read content of 151022-075754 ... FAIL
As you can see, in my situation the getAppFolder(mGAC) returns valid DriveFolder (DriveId) that can be used. Even the DriveId string looks the same.
Listing of folders/files returns valid objects. It is not supposed to, but I know there is a latency I have to count on, so the list result may change later to reflect the deletion. Attempt to read the file content fails.
A few minutes later (GDAA probably synchronized), the same attempt to list fails, still understandable result, but another attempt to create any object (folder/file) in app folder fails with 'invalid parent folder' error as you pointed out. Disconnect / re-connect does not help, so the app is toasted.
This points to a serious bug that should be addressed. Again the same as in SO 30172915, an uneducated user's action can cause irreparable damage - loss of data to the Android App with no known remedy.
I am experiencing the same problem. I thought GoogleApiClient.ClearDefaultAccountAndReconnect() might be a workaround but it didn't help. As an alternative to uninstalling/reinstalling the app you can try these steps, they worked for me:
In a browser, go to the page for managing your Google account's security settings.
Select "Connected apps & sites", then "Manage Apps"
Select your app from the list. It will show that it has access to Google Drive and a Remove button.
Click on Remove.
Wait a minute or two for the change to take effect, then run your app.
When your app attempts to connect to Drive, you should get the consent screen prompting the user to allow or deny access. Accepting will reauthorize the app and should clear the problem. It did for me.
This bug was reported to google on May 4th:
https://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=4483
As a workaround you can use the REST API.
Hi guys i plan at my android side to retrieve some documents file from my google drive,but always failed mention:
Drive item not found, or you are not authorized to access it.
Here is my code the problem part is the "EXISTING_FILE_ID "
private static final String EXISTING_FILE_ID = "0BxyOMAFcmxoYTkt6cHZwcUtaNlU";
private static final int REQUEST_CODE = 102;
private GoogleApiClient googleApiClient;
private static final String TAG = "retrieve_contents";
First:i tried to get my shared documents link at google drive and pick the key values example,0BxyOMAFcmxoYTkt6cHZwcUtaNlU https://drive.google.com/file/d/0BxyOMAFcmxoYTkt6cHZwcUtaNlU/view?usp=sharing
Second:i use my android side application to create a file,and retrieved a DriveId:CAESABiiHyCcwq2SpVMoAA== but still unable to retrieve file content
this problem confused me Several days does some one help me ?
From the fact that you mention 'EXISTING_FILE_ID', I assume you are referring to the demo code here.
So, to answer the point called 'First' above: The error tells you that you're trying to access a file, not created by your Android app. GDAA supports only SCOPE_FILE scope, e.g. only files created by the Android app can by found, opened, modified,...
The point called 'Second': You are (probably) correctly trying to access a file created by your Android app, but using incorrect ID. The ID I'm seeing is a 'DriveId', different from 'ResourceId' you are supposed to use (see SO 29030110 here).
The most immediate solution would be to turn your DriveId into ResourceId by means of
DriveId driveId = DriveId.decodeFromString("DriveId:CAESABii.....");
String EXISTING_FILE_ID = driveId.getResourceId();
And try that ID.
Good Luck
#user2953788
Did you solve this issue? I have the same example working and I can see 2 potential issues that could give you the error you have mentioned (you have not pasted the actual error log)
1) You have not given access to the app to Google drive (less likely since you followed tutorial)
2) The variable "public static final String EXISTING_FILE_ID" in the BaseDemoActivity.java in the sample code is not updated with the latest EXISTING_FILE_ID that you have in your Google drive. Every time you delete or add the file the ID changes even if the file name is not changed. This is more likely cause of your error. I assume you know how to find the EXISTING_FILE_ID of any file in Google drive as given in the Google tutorials.
All the best!
Using the new GDAA, as I understand it, in order to access a folder and its contents you have to have the folder's DriveId - because this insures that an app can only access the content it has created itself.
Now, my app uploads files to the user's Google Drive account (pictures) in a custom folder. When this folder is first created I save the DriveId of the folder to Shared Preferences so I can access the folder later for more uploads. My problem is that I would like the user to be able to access the pictures from multiple devices (so he/she e.g. can look at pictures uploaded from his/her phone while being on a tablet and vice versa), but this I cannot do without having the folder's DriveId on both devices. The only solution I can think of is sharing the DriveId between user's devices via some cloud service, but this seems awfully inconvenient for the purpose.
Any thoughts?
Shamelessly promoting myself to Cheryl's sidekick, I can give you some specific points, since I've run through this gauntlet before. This is what I did:
Create a unique 'root' for my app in the system root - "MyStupidAppRoot'. Here you'll hit the main challenge since you are creating it by name and if you base the creation on it's non-existence, you may not reliably be able to check it. But it is getting better, see SO 22382099 and SO 22515028.
Once you have a reliable anchor 'MyStupidAppRoot', you can create AppFolder mentioned by Cheryl (not available yet) or create you own visible file (again, the unique creation challenge) that can keep anything you want. Like for instance all your PREFERENCE strings. I even got so brave as to store full SQLite DB file there. It is possible since you write a byte[] buffer to a file.
Than, any other device with you app can find 'MyStupidAppRoot', get the resource file from there and read it.
It should be noted that the main difference between you own folder/file and the AppFolder is, that user's can't read the contents of an AppFolder, but can still delete it.
Here's how you can write byte[] buffer to a file. It is the 'await' version to make it simple, but there is an async version 'createFileAsync()' here.
public DriveFile createFileWait(DriveFolder fldr, String name, String mime, byte[] buff) {
DriveFile drvFile = null;
if (isConnected()) try {
ContentsResult rslt = Drive.DriveApi.newContents(_gac).await();
if (rslt.getStatus().isSuccess()) {
Contents cont = rslt.getContents();
cont.getOutputStream().write(buff);
MetadataChangeSet meta = (mime == null) ?
new MetadataChangeSet.Builder().setTitle(name).build() :
new MetadataChangeSet.Builder().setTitle(name).setMimeType(mime).build();
drvFile = fldr.createFile(_gac, meta, cont).await().getDriveFile();
}
} catch (Exception e) {}
return drvFile;
}
About the IDs:
The DriveId you mention above is an object, that can be turned into 2 different strings as discussed in SO 21800257. It is up to you which one you choose. The long one from 'encodeToString()' is easier to turn back into DriveId by 'decodeFromString()', the shorter one can be easily recognized in the http address, but takes async / await method to get back the DriveId - fetchDriveId().
You don't necessarily have to have the DriveId, its just the most sure-fire way to do it since it uniquely identifies the folder. You can also query based on the title to try to find the same folder. Assuming that the web and Android app share an app id, both should be able to access the same files.
One easy option for sharing state between apps is to make use of the newly launched App Folders (called App Data Folders on the web.) This is a hidden folder where you can store files specific to your app. Its not yet in the Android docs, but it should show up there as soon as the rollout of Google Play Services 4.3 is released. See http://android-developers.blogspot.com/2014/03/google-play-services-43.html