I'm trying to establish a rule to fetch firestore data, that can be accessed by a google signed in client.
So the problem I'm facing is when I'm using this rule
match /helpers/customer/data/{document=**}{
allow read: if request.auth != null;
}
An error pops in logcat
onFailure:
Errorcom.google.firebase.firestore.FirebaseFirestoreException:
PERMISSION_DENIED: Missing or insufficient permissions.
also it is only working when I'm using
match /helpers/customer/data/{document=**}{
allow read: if true;
}
That means the path is write.
GoogleSignInAccount acct = GoogleSignIn.getLastSignedInAccount(this);
if(acct != null){
Log.i(TAG, "onCreate: Database Working");
mFirestoreDB
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
Log.d(TAG, document.getId() + " => " + document.getData());
}
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
}else{
Log.i(TAG, "onCreate: Database not Working");
}
What I need is a rule where I can allow only a google signed in user to access.
Signing in with Google does not automatically sign the user in with Firebase. You will need to also sign them in with Firebase Authentication, before your security rules will have its auth variable set.
From the Firebase documentation in signing in with Google:
private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
Log.d(TAG, "firebaseAuthWithGoogle:" + acct.getId());
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = mAuth.getCurrentUser();
updateUI(user);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Toast.makeText(GoogleSignInActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
updateUI(null);
}
// ...
}
});
}
But I recommend you read the entire page I linked.
Related
I am Using Google Fit For Recording Step . Dont Clear Data Google Fit Day. 2 Button in Application . number one Start Record Step ,number two for Stop Record
My Code For Start Recoud
Fitness.getRecordingClient(this, GoogleSignIn.getLastSignedInAccount(this))
.subscribe(DataType.TYPE_STEP_COUNT_DELTA)
.addOnCompleteListener(
new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
} else {
}
}
});
//
Fitness.getRecordingClient(this, GoogleSignIn.getLastSignedInAccount(this))
.subscribe(DataType.TYPE_DISTANCE_DELTA)
.addOnCompleteListener(
new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
} else {
}
}
});
//
Fitness.getRecordingClient(this, GoogleSignIn.getLastSignedInAccount(this))
.subscribe(DataType.TYPE_CALORIES_EXPENDED)
.addOnCompleteListener(
new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
} else {
}
}
});
Code For Delete Data Not Working
public void ClearHistory(){
Log.i(TAG, "Deleting today's step count data");
// [START delete_dataset]
// Set a start and end time for our data, using a start time of 1 day before this moment.
Calendar cal = Calendar.getInstance();
Date now = new Date();
cal.setTime(now);
long endTime = cal.getTimeInMillis();
cal.add(Calendar.DAY_OF_MONTH, -20);
long startTime = cal.getTimeInMillis();
// Create a delete request object, providing a data type and a time interval
DataDeleteRequest request = new DataDeleteRequest.Builder()
.setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
.addDataType(DataType.TYPE_STEP_COUNT_DELTA)
.build();
// Invoke the History API with the Google API client object and delete request, and then
// specify a callback that will check the result.
Fitness.HistoryApi.deleteData(mClient, request)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Successfully deleted today's step count data");
Toast.makeText(p_context,"ok",Toast.LENGTH_LONG).show();
Toast.makeText(p_context,status.getStatus().toString(),Toast.LENGTH_LONG).show();
} else {
// The deletion will fail if the requesting app tries to delete data
// that it did not insert.
Log.i(TAG, "Failed to delete today's step count data");
}
}
});
}
For Get Data
Fitness.getHistoryClient(p_context, GoogleSignIn.getLastSignedInAccount(p_context))
.readDailyTotal(DataType.TYPE_STEP_COUNT_DELTA)
.addOnSuccessListener(
new OnSuccessListener<DataSet>() {
#Override
public void onSuccess(DataSet dataSet) {
long total =
dataSet.isEmpty()
? 0
: dataSet.getDataPoints().get(0).getValue(Field.FIELD_STEPS).asInt();
//String Calley = dataSet.getDataPoints().get(0).getValue(Field.FIELD_CALORIES).toString();
/*
long distance =
dataSet.isEmpty()
? ""
: dataSet.getDataPoints().get(0).getValue(Field.FIELD_DISTANCE.getFormat());
*/
//
Log.i("countstep", "Total steps: " + total);
//CalleryStart = Double.parseDouble(String.valueOf(Calley));
//distancestart = Double.parseDouble(String.valueOf(distance));
//Toast.makeText(getApplicationContext(), Double.toString( total),Toast.LENGTH_LONG).show();
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w("errorcountstep", "There was a problem getting the step count.", e);
}
});
this Codes for Google Fit Api not Working I am Using Google Fit Version 16.0.1 dont word. Get Data SuccessFully Work And record Step... . no Working Delete History. I am Using Google Fit API Documention
I created a new app and the authentication part for GoogleFit is a complete copy/paste of another app that works perfectly. The window to choose an account appears but after that I'm expecting to see the window that showing needed scope but nothing.
Is there someone who already encountered this issue ?
I can post my code if needed.
Thanks a lot !
Edit
This is my code to connect to Google Fit:
private void buildFitnessClient() {
// Create the Google API Client
mFitClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.HISTORY_API)
.addApi(Fitness.RECORDING_API)
.addApi(Fitness.CONFIG_API)
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ_WRITE))
.addScope(new Scope((Scopes.FITNESS_NUTRITION_READ_WRITE)))
.addScope(new Scope(Scopes.FITNESS_BODY_READ_WRITE))
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected to Fitness API!!!");
// Now you can make calls to the Fitness APIs.
// Put application specific code here.
// Once connected go the Main2Activity
Intent start_google_plus = new Intent(GoogleFitAuthentication.this, MainActivity.class);
startActivity(start_google_plus);
finish();
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "onConnectionSuspend");
// If your connection to the sensor gets lost at some point,
// you'll be able to determine the reason and react to it here.
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG, "Connection lost. Reason: Service Disconnected");
}
}
}
)
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
// Called whenever the API client fails to connect.
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed. Cause: " + result.toString());
if (!result.hasResolution()) {
// Show the localized error dialog
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(),
GoogleFitAuthentication.this, 0).show();
return;
}
// The failure has a resolution. Resolve it.
// Called typically when the app is not yet authorized, and an
// authorization dialog is displayed to the user.
if (!authInProgress) {
try {
Log.i(TAG, "Attempting to resolve failed connection");
authInProgress = true;
result.startResolutionForResult(GoogleFitAuthentication.this, REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
}
}
)
.build();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "Processing onActivityResult...");
if (requestCode == REQUEST_OAUTH) {
Log.d(TAG, "requestCode == REQUEST_OAUTH");
authInProgress = false;
if (resultCode == RESULT_OK) {
Log.d(TAG, "resultCode == RESULT_OK");
// Make sure the app is not already connected or attempting to connect
if (!mFitClient.isConnecting() && !mFitClient.isConnected()) {
mFitClient.connect();
}
}
}else{
Log.d(TAG, "Impossible to process onActivityResult...");
}
}
#Override
protected void onStart() {
super.onStart();
// Connect to the Fitness API
Log.i(TAG, "Connecting...");
if(mFitClient!=null){
mFitClient.connect();
}
}
#Override
protected void onStop() {
super.onStop();
Log.i(TAG, "onStop...");
if (mFitClient!=null && mFitClient.isConnected()) {
mFitClient.disconnect();
}
}
#Override
protected void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(AUTH_PENDING, authInProgress);
}
When you authorized the scopes , the browser will store your session. So if you again authorize the app in the same browser, you will only shows the scope as Have offline access.
I develop an Universal App that uses MVVM-Light. I call WebServices from the ViewModels, and I throw the exceptions encountered by the calls at the WebServices to the ViewModels: TimeOut, Wrong URL, Server Exception, ...
I have created a class "ExceptionsMsgHelper.cs" which centralizes the messages displayed for each of these exceptions through MessageDialog.
My HomePage is based on a Pivot that containing several datas: some WebServices are called asynchronously. I so meet a crash if I show an Exception in a MessageDialog through the class "ExceptionsMsgHelper.cs", whereas a previous Exception is also showed in another MessageDialog.
Here is a part of my original class:
public class ExceptionsMsgHelper
{
public async static void MsgboxWebserviceErrors(WebServiceErrorsException wseE, string errors)
{
Windows.UI.Popups.MessageDialog msgbox =
new Windows.UI.Popups.MessageDialog("The Websercice '" + wseE.WebService + "' has returned errors : \n" + errors,
"Unexpected data");
await msgbox.ShowAsync();
}
}
=> If I call twice the "msgbox.ShowAsync()", I get the "System.UnauthorizedAccessException" Exception: with message "Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))"
I've so looked for solutions in order to fix it:
use a "Dispatcter", like it is recommended here (WinRT - MessageDialog.ShowAsync will throw UnauthorizedAccessException in my custom class)
The code is:
public class ExceptionsMsgHelper
{
public async static void MsgboxWebserviceErrors(WebServiceErrorsException wseE, string errors)
{
Windows.UI.Popups.MessageDialog msgbox =
new Windows.UI.Popups.MessageDialog("The Websercice '" + wseE.WebService + "' has returned errors : \n" + errors,
"Unexpected data");
CoreDispatcher dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
await msgbox.ShowAsync();
});
}
}
=> But I always meet the same exception.
use a "IAsyncOperation" command to close the previous MessageDialog, like recommended here (MessageDialog ShowAsync throws accessdenied exception on second dialog)
With this code:
public class ExceptionsMsgHelper
{
private static IAsyncOperation<IUICommand> messageDialogCommand = null;
public async static Task<bool> ShowDialog(MessageDialog dlg)
{
// Close the previous one out
if (messageDialogCommand != null)
{
messageDialogCommand.Cancel();
messageDialogCommand = null;
}
messageDialogCommand = dlg.ShowAsync();
await messageDialogCommand;
return true;
}
public async static void MsgboxWebserviceErrors(WebServiceErrorsException wseE, string errors)
{
Windows.UI.Popups.MessageDialog msgbox =
new Windows.UI.Popups.MessageDialog("The Websercice '" + wseE.WebService + "' has returned errors : \n" + errors,
"Unexpected data");
CoreDispatcher dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
await ShowDialog(msgbox);
});
}
}
=> But in this case too, I always get the same exception.
use an extension to queue up messagedialogs, like describing here (Multiple MessageDialog app crash)
The code is now:
public class ExceptionsMsgHelper
{
public async static void MsgboxWebserviceErrors(WebServiceErrorsException wseE, string errors)
{
Windows.UI.Popups.MessageDialog msgbox =
new Windows.UI.Popups.MessageDialog("The Websercice '" + wseE.WebService + "' has returned errors : \n" + errors,
"Unexpected data");
await MessageDialogExtensions.ShowAsyncQueue(msgbox);
}
}
public static class MessageDialogExtensions
{
private static TaskCompletionSource<MessageDialog> _currentDialogShowRequest;
public static async Task<IUICommand> ShowAsyncQueue(this MessageDialog dialog)
{
if (!Window.Current.Dispatcher.HasThreadAccess)
{
throw new InvalidOperationException("This method can only be invoked from UI thread.");
}
while (_currentDialogShowRequest != null)
{
await _currentDialogShowRequest.Task;
}
var request = _currentDialogShowRequest = new TaskCompletionSource<MessageDialog>();
var result = await dialog.ShowAsync();
_currentDialogShowRequest = null;
request.SetResult(dialog);
return result;
}
private static IAsyncOperation<IUICommand> messageDialogCommand = null;
public async static Task<bool> ShowDialog(this MessageDialog dlg)
{
// Close the previous one out
if (messageDialogCommand != null)
{
messageDialogCommand.Cancel();
messageDialogCommand = null;
}
messageDialogCommand = dlg.ShowAsync();
await messageDialogCommand;
return true;
}
#endregion
}
=> And this works for me.
But like says it's author, it's probably not the best solution:
Close existing dialog when you need to open a new one. This is the simplest option and possibly the best, although you risk cancelling a dialog that might be somehow important depending on what your dialogs are about.
Queue up dialogs so the old ones don't get dismissed, but the new ones show up after the old ones were dismissed. This one will make sure all dialogs are closed by the user, but that could be a problem if your app can somehow start showing hundreds of dialogs.
Only open a new one if there isn't one already displayed. Now this risks that a newer message is not shown, which sounds more problematic than the first option.
=> I would like to understand why I can't apply one the 2 first solutions that seems to be more adapted
Ofcourse you can't show 2 or more message dialog at the same time (windows phone limits). Moreover MesssageDialog on Windows Phone 8.1 has probably bug and can't be closed.
If closing previous dialog will be solution for you, try to use ContentDialog instead MessageDialog. Check my answer in this topic: Closing MessageDialog programatically in WP 8.1 RT
I think it solve your problem.
I have successfully uploaded a file to Drive and inserted permissions of another account to share. All this is working. But when I try from the other account to list out the shared files for download, it returns that there are no files.
Does anyone know how to retreive files that are shared from another user?
Here is what I've tried.
private class RetrieveAllShareFiles extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... arg0) {
Files.List request = null;
try {
request = service.files().list().setQ("sharedWithMe");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
do {
try {
FileList files = request.execute();
filesResult.addAll(files.getItems());
request.setPageToken(files.getNextPageToken());
} catch (IOException e) {
System.out.println("An error occurred: " + e);
request.setPageToken(null);
}
} while (request.getPageToken() != null &&
request.getPageToken().length() > 0);
return "Executed";
}
When using the drive.files scope your app will only be able to access files that you have created with it or that the user is opening from the Drive UI.
When the file is shared with another user, he won't be able to see it using the drive.files scope. For this use case you should request access to the full Drive scope.
Check the documentation for more details on the available OAuth scopes: https://developers.google.com/drive/scopes
I am writing an Android (version ICS) app. which uploads data to the Google Drive. The app
uses oauth2 to acquire the access token.
First step: acquire authorization token.
String AUTH_TOKEN_TYPE = "oauth2:https://www.googleapis.com/auth/drive";
// Step 1
accountManager.getAuthToken(
account, // Account retrieved using getAccountsByType("com.google")
AUTH_TOKEN_TYPE, // Auth Token Type
options, // Authenticator-specific options
this, // Your activity
new OnTokenAcquired(), // Callback called when a token is successfully acquired
new Handler(new OnAuthTokenError())); // Callback called if an error occurs
}
private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
#Override
public void run(AccountManagerFuture<Bundle> result) {
// Get the result of the operation from the AccountManagerFuture.
Bundle bundle;
try {
bundle = result.getResult();
authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
Log.d(TAG,"authToken:" + authToken);
exchangeToken access = (exchangeToken) new exchangeToken().execute();
} catch (OperationCanceledException e) {
e.printStackTrace();
} catch (AuthenticatorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Success. An authorization token is acquired.
Step 2: Exchange authorization token for Access Token.
private class exchangeToken extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... params) {
HttpTransport transport = new NetHttpTransport();
JsonFactory jsonFactory = new GsonFactory();
String CLIENT_ID = "999999999999.apps.googleusercontent.com";
String CLIENT_SECRET = "axXXXXXXXXXXXXXXX7";
try { // Step 2: Exchange for an access and refresh token
GoogleTokenResponse authResponse = new GoogleAuthorizationCodeTokenRequest(transport, jsonFactory, CLIENT_ID, CLIENT_SECRET, authToken, CALLBACK_URL).execute();
accessToken = authResponse.getAccessToken();
Log.d("Get Access","Token:" + accessToken);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Fail. The LogCat shows the following:
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error":"unauthorized_client"
}
I have been able to access "Google Drive" on my Android tablet using the "Drive" app. so
my email account is valid. May be the AUTH_TOKEN_TYPE is incorrect, but the Google Drive
SDK is not clear what it must be. What am I missing?
You do not need to do the second step of exchanging the token. Android grants you an access token directly, it does not grant you an auth code which you would have to exchange for tokens.
This page on the Android documentation explains everything really well.
You know that for using the Drive API your users have to install your app on the Chrome(!) Webstore?
Normally Documents List API is the better choice from Android.