i`m using standard API (not REST API), and when i backup files and then restore, it works.... problems occurs when i re-install application. After re-install, files in AppFolder are not seen by app, but exists
Query query = new Query.Builder().addFilter(Filters.eq(SearchableField.TITLE, Tags.DB_DATA)).addFilter(Filters.eq(SearchableField.TRASHED, false)).build();
Drive.DriveApi.query(GAPI, query).setResultCallback(new ResultCallback<DriveApi.MetadataBufferResult>() {
#Override
public void onResult(#NonNull DriveApi.MetadataBufferResult result) {
loadBackups(result.getMetadataBuffer());
result.release();
}
});
this is code so far (inside loadBackups im creating ArrayList with HashMap with details, nothing special), but i have tried listChildren and queryChildren, but same...
at certain point, it can be seen, but i did not catch when it happens, but i know for sure that after re-install, it can not be seen
Not enough rep to comment. However, I suspect that the issue you are having is that by design the last install of an app that a user has removes the app folder from Drive.
So your solution needs to be to back up to a place that is not owned by the app.
I've had a further issue on multiple installs where if you install the app on a second device, it takes "some time" (not sure how long) for Drive to propagate the app folder to the Drive. I have used this to sync data between devices but it is in the hands of Drive when the sync might work its way around.
try to put these line of code onConnected method,
try {
Drive.DriveApi.requestSync(mGoogleApiClient)
.setResultCallback(syncCallBack);
} catch (IllegalStateException ex) {
}
And then
private ResultCallback<Status> syncCallBack = new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (!status.isSuccess()) {
if (DriveStatusCodes.DRIVE_RATE_LIMIT_EXCEEDED == status.getStatusCode()) {
}
}
Query query = new Query.Builder()
.addFilter(Filters.contains(SearchableField.TITLE, "abc.txt"))
.build();
Drive.DriveApi.query(mGoogleApiClient, query)
.setResultCallback(metadataCallback);
}
};
Related
I'm trying to make a mobile app that, eventually in one of its activities will connect to a Blob storage in Android to transfer a collection of images.
But I couldnt even get there, since one of the requirements is making that connection to be safe, since the client could be anyone from his mobile phone, so my first step here is requesting a SAS token prior to start any transaction.
So this is basically two steps that I'm following,
1 -> Implemented an Azure Function inside my App Service that returns a SAS token (I got that function from here: Sas Token Function
)
2 -> Trying to call that function from my Android Code and get my SAS token.
Looks really easy and I'm sure it is, the function in the link explains the required http body to ask for concrete access, and I think is there where I'm failing, below is my code to call the function:
private void getStringFromAzure() throws MalformedURLException {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("container", "uploadedimages");
jsonObject.addProperty("permissions", "Write, Create");
// Create the MobileService Client object and set your backend URL
String yourURL = "https://mydirectory.azurewebsites.net/";
MobileServiceClient mClient = new MobileServiceClient(yourURL, this);
// Your query pointing to yourURL/api/values
ListenableFuture<JsonElement> query = mClient.invokeApi("GetSasToken-Net", jsonObject, "POST", null);
// Callback method
Futures.addCallback(query, new FutureCallback<JsonElement>() {
#Override
public void onSuccess(JsonElement jsonElement) {
final String result = jsonElement.toString();
// Since you are on a async task, you need to show the result on the UI thread
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(mContext, result, Toast.LENGTH_LONG).show();
}
});
}
#Override
public void onFailure(Throwable throwable) {
Log.d(TAG, "onFailure: " + throwable.getMessage());
}
});
}
The code is failing in "InvokeApi" line function, where throws an exception before even warning me that is going to connect to Internet from mobile.
Another thing that I think could be wrong is that, nowhere in the Azure Get Sas Token Function is specifying my account credentials ( I didnt developed that function, but should work fine as it is, it anyways doesnt let you change anything, imported via GitHub )
I have really small base/background in this kind of things and Im sure I'm missing something (or "lots" of somethings), but I really appreciate a hand, this is driving me crazy.
PD. Internet permissions already given in manifest.
Thank you all in advance, first post in StackOverflow after following for many years!
I am trying to setup realtime multiplayer in my Android Game. However, when I call Games.RealTimeMultiplayer.create(googleApiClient, roomConfig); after selecting the players.
However every time onRoomCreated is called with status STATUS_CLIENT_RECONNECT_REQUIRED and room null:
#Override
public void onRoomCreated(int statusCode, Room room) {
if (statusCode == STATUS_CLIENT_RECONNECT_REQUIRED) {
// This gets called repeatedly
reconnectGoogleLogin();
return;
} else if (statusCode != GamesStatusCodes.STATUS_OK) {
disableAlwaysOnScreen();
return;
}
Intent i = Games.RealTimeMultiplayer.getWaitingRoomIntent(
googleApiClient, room, MIN_NUMBER_OF_PLAYERS);
startActivityForResult(i, RC_WAITING_ROOM);
}
I have tried a number of things before asking this:
Yes I checked my Google Play Developer Console, the Realtime Multiplayer Settings is ON in the Linked Apps
The APK installed is with a valid sign key, I have the debug key-store as valid.
Looked through the documentation, but I couldn't figure out why this is happening.
Would love some help :)
I have been following https://developers.google.com/identity/smartlock-passwords/android/retrieve-credentials to try to automatically sign in a user if they have saved their credentials to the new Android Smart Lock feature in chrome. I have followed the guide exactly, but my callback that I pass into setResultCallback() is not getting called. Has anyone run into this problem before?
There is no error message or anything, it just doesn't get called.
The problem is likely that the Google API client is not connected, try calling connect() in the onStart() method of your activity, or if you are using a recent version of Play Services, we added automatic management of the API client to make this easier, really simplifying things and avoiding common problems.
Just call enableAutoManage() when building the GoogleApiClient:
// "this" is a reference to your activity
mCredentialsApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.enableAutoManage(this, this)
.addApi(Auth.CREDENTIALS_API)
.build();
Then you can make an API request without having to call mCredentialsApiClient.onConnect() at any point, the Google API client's lifecycle will be managed automatically for you. e.g.
#Override
public void onStart() {
CredentialRequest request = new CredentialRequest.Builder()
.setSupportsPasswordLogin(true)
.build();
Auth.CredentialsApi.request(mCredentialsApiClient, request).setResultCallback(
new ResultCallback<CredentialRequestResult>() {
public void onResult(CredentialRequestResult result) {
// result.getStatus(), result.getCredential() ... sign in automatically!
...
Check out a full sample app at on Github: https://github.com/googlesamples/android-credentials/blob/master/credentials-quickstart/app/src/main/java/com/google/example/credentialsbasic/MainActivity.java
I tired the official demo app here, and it worked.
Basically, the setResultCallback() will be get called when save, request and delete
For save:
Auth.CredentialsApi.save(mCredentialsApiClient, credential).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.d(TAG, "SAVE: OK");
showToast("Credential Saved");
hideProgress();
} else {
resolveResult(status, RC_SAVE);
}
}
});
For request:
Auth.CredentialsApi.request(mCredentialsApiClient, request).setResultCallback(
new ResultCallback<CredentialRequestResult>() {
#Override
public void onResult(CredentialRequestResult credentialRequestResult) {
if (credentialRequestResult.getStatus().isSuccess()) {
// Successfully read the credential without any user interaction, this
// means there was only a single credential and the user has auto
// sign-in enabled.
processRetrievedCredential(credentialRequestResult.getCredential(), false);
hideProgress();
} else {
// Reading the credential requires a resolution, which means the user
// may be asked to pick among multiple credentials if they exist.
Status status = credentialRequestResult.getStatus();
if (status.getStatusCode() == CommonStatusCodes.SIGN_IN_REQUIRED) {
// This is a "hint" credential, which will have an ID but not
// a password. This can be used to populate the username/email
// field of a sign-up form or to initialize other services.
resolveResult(status, RC_HINT);
} else {
// This is most likely the case where the user has multiple saved
// credentials and needs to pick one
resolveResult(status, RC_READ);
}
}
}
});
For delete:
Auth.CredentialsApi.delete(mCredentialsApiClient, mCurrentCredential).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
hideProgress();
if (status.isSuccess()) {
// Credential delete succeeded, disable the delete button because we
// cannot delete the same credential twice.
showToast("Credential Delete Success");
findViewById(R.id.button_delete_loaded_credential).setEnabled(false);
mCurrentCredential = null;
} else {
// Credential deletion either failed or was cancelled, this operation
// never gives a 'resolution' so we can display the failure message
// immediately.
Log.e(TAG, "Credential Delete: NOT OK");
showToast("Credential Delete Failed");
}
}
});
Also you can clone the project in my github here, set the SHA1 in your console here.
At this point you should be ready to go :)
I am using the Android SDK of parse.com and have arrived at a peculiar problem.
From a fragment's onCreate:
Fetch an object from the server.
Pin it.
Fetch an object from the local datastore.
Here is a snippet of the code from the onCreate:
ParseObject myChatGroup = ParseObject.createWithoutData("ChatGroup", "mOJGWRiLPC");
myChatGroup.fetchInBackground(new GetCallback<ParseObject>() {
#Override
public void done(ParseObject chatGroup1, ParseException e) {
if (e == null) {
l.d("Fetched chat group: " + chatGroup1 + " from server");
chatGroup1.pinInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
l.d("Successfully pinned chat group");
ParseQuery<ParseObject> chatGroupParseQuery = new ParseQuery<>("ChatGroup");
chatGroupParseQuery.fromLocalDatastore()
.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> list, ParseException e) {
if (e == null) {
l.d("Found " + list.size() + " chat groups from local datastore");
} else {
e.printStackTrace();
}
}
});
} else {
e.printStackTrace();
}
}
});
} else {
e.printStackTrace();
}
}
});
Here is the log:
Fetched chat group: ChatGroup { objectId: mOJGWRiLPC, name: Admin } from server
Successfully pinned chat group
Found 0 chat groups from local datastore
But this doesn't make any sense! I just pinned an object so how can there be 0 objects in the local datastore. The code is so simple. What am I doing wrong? Could it be a bug with the SDK?
Any insight will be much appreciated I have been trying to find the issue for days now.
The Parse setup looks fine to me:
ParseObject.registerSubclass(ChatGroup.class);
Parse.enableLocalDatastore(this);
Parse.initialize(this, AppProps.properties.appId,
AppProps.properties.clientKey);
ParseUser.enableRevocableSessionInBackground();
Parse.setLogLevel(Parse.LOG_LEVEL_DEBUG);
Note:
It works fine when trying the same logic with the ParseUser object. And even other classes of mine like my Message which leads me to suspect that something is wrong with my ChatGroup class.
I have added two fields to my ChatGroup class on the parse.com data browser: name(String) and messages(Relation) with read and wrote access to a role called Admin.
When browsing to the actual parse db (using root access) I find that the database table (ParseObjects) does contain the row that I pinned. But somehow parse shows 0 results on querying it!
Parse doesn't seem to support ACLs on local datastore. So the easiest way to get around this issue is to do ignoreACLs() on the query -- assuming you do have roles/acls setup correctly on the server side, so whatever you have pinned locally should be OK permission-wise already.
I found the issue. It seems to be more like a bug with the Android SDK of parse. I narrowed it down to an issue with retrieving pinned objects with special ACLs using the Android SDK.
Initially, the object had the ACL such that only the role 'Admin' (that I created) can read and write. The funny thing is that the user with which I was testing the pinning and querying was an 'Admin'! But, when I changed the ACL such that public can read but only Admin can write, the problem was resolved!
My theory was that querying the local datastore behaves like a public query, no matter what role the user that is making the query has! But if any other theory explaining this would be appreciated. Luckily, in my case I need public read access, but this bug can be a huge downfall for some who need to have read access restricting ACLs! Hopefully parse.com will fix this issue soon.
This is quite a big issue! I am surprised that I couldn't find a question regarding this issue.
Yeah so basically you have to set ACL for current user and pin it before you pin the chat group.
ParseACL acl = new ParseACL();
acl.setReadAccess(ParseUser.getCurrentUser(), true);
ParseUser.getCurrentUser().setACL(acl);
ParseUser.getCurrentUser().pinInBackground();
I am creating an android application which should have access to a google drive account in order to store and read files in/from google drive. I used google drive android API for this purpose. but the problem is that when the user signs in to the account through the application, the account is also added to the device and the account is accessible through drive, gmail,... applications and I need to restrict the access to that google account to only my application.
Is there anyway to restrict access to google account to just my application?
I show some code related to connecting to google drive below:
public class MainActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
// Request code to use when launching the resolution activity
private static final int REQUEST_RESOLVE_ERROR = 1001;
private boolean mResolvingError = false;
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_RESOLVE_ERROR) {
mResolvingError = false;
if (resultCode == RESULT_OK) {
// Make sure the app is not already connected or attempting to connect
if (!mGoogleApiClient.isConnecting() &&
!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//start connection to google play
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// TODO Auto-generated method stub
if (mResolvingError) {
// Already attempting to resolve an error.
return;
} else if (result.hasResolution()) {
try {
mResolvingError = true;
result.startResolutionForResult(this,REQUEST_RESOLVE_ERROR);
} catch (SendIntentException e) {
// There was an error with the resolution intent. Try again.
mGoogleApiClient.connect();
}
} else {
// Show dialog using GooglePlayServicesUtil.getErrorDialog()
showErrorDialog(result.getErrorCode());
mResolvingError = true;
}
}
#Override
public void onConnected(Bundle arg0) {
// TODO Auto-generated method stub
showMessage("Connected to account");
}
protected void onPause()
{
showMessage("onPause");
super.onPause();
}
protected void onStart() {
super.onStart();
showMessage("onStart");
if (!mResolvingError && !mGoogleApiClient.isConnected()) { // more about this later
mGoogleApiClient.connect();
}
}
#Override
protected void onStop() {
showMessage("OnStop");
//mGoogleApiClient.disconnect();
super.onStop();
}
protected void onRestart()
{
showMessage("onRestart");
super.onRestart();
if (!mResolvingError && !mGoogleApiClient.isConnected()) { // more about this later
mGoogleApiClient.connect();
}
}
public void showMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
}
In fact I am making an application which we use to collect data from our users, and therefore we want the data to be stored in a central storage space which both we and other users of application can have access to data.(users have limited access to data through our application). we did the same with dropbox and it works well. but due to some restrictions on accessing dropbox by users, I am looking for alternative solutions. for now I am trying to do the same with google drive.
does anyone have any solution about how should I do this??
in fact the google account has nothing to do with the users of application, it's my google account in which the data coming from application should be stored.
I can't say I fully understand your question, but I'll try to help anyway.
You probably know, that your app needs to be authorized to access the Drive.
Assuming that is working, you need valid gmail account to access the drive. Under normal circumstances, you pull the gmail account from the set of accounts on your device, i.e. myaccount#gmail, youraccount#gmail, .... The list of these accounts is visible in the settings, and you usually add / remove them through the Settings or your app can do it by invoking AccountPicker. I have a little demo here, that handles the issue (follow the MainActivity - REQ_ACCPICK - GDAA branch there). The AccountPicker/Setting either picks an account from the list, or adds a new account to the device.
Now, let's assume you would like to access Drive with a gmail account that is not in the device's list (i.e . NOT-IN-LIST#GMAIL.COM), bypassing account picker, and stick it directly to (see the method here):
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.setAccountName("NOT-IN-LIST#GMAIL.COM")
.build();
If you do this, you'll get 'INVALID ACCOUNT' in 'onConnectionFailed()'. It makes sense, since you've just set an account name not known to the device - effectively even without knowing it's password. I assume that would be a major problem for Google Drive security, right?
So the conclusion (or my best guess) is: Unless you can 'hardcode' the account / passsword info into GoogleApiClient builder, the only way to get the Drive connection is to use one of the 'registered' accounts - they have the correct password already.
UPDATE:
There may be a different way to implement it. Again, UNTESTED. I would try to use a "supervisor" Google account and share the files with users. Android REST Api under DRIVE scope should be able to access these shared files/folders. This way users would access the "supervisor's" files using their own accounts (I vaguely remember hitting 'shared-with-me' files when playing with the REST api). A long shot, but it can easily be tested using the playground - the bottom of the page. And I would even test the same hypothesis under GDAA. I don't know if GDAA can see the 'shared files' under the FILE scope.
Good Luck
I had the same problem and after a lot of research and reading many posts from angry users about this "feature" I am under the impression that this cannot be done using GoogleApiClient.
Instead I used AppAuth to retrieve the authCode / token and then used that token with the Drive REST API to retrieve the users files.
Please note that WebView OAuth is no longer supported by Google as of 4/20/17 which is the reason I suggest AppAuth. AppAuth also works around other unpleasantries such as this.
You can find more details on this approach and a work around for a weird grant error here: invalid_grant trying to get oAuth token from google
Hope this helps.