Request timeout in Google Fit - Android wear 2.0 - android

I have a problem with getting google fit data on Android Wear 2.0.
My requests are getting TIMEOUT response. If the await() method has no parameters, there is no response (the await() method did not returned). Any clues whats wrong?
App uses Google Sign-In, and everything works on regular Android device.
Creating of GoogleApiClient and SignInAccount
GoogleSignInOptions signInConfig = new GoogleSignInOptions
.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestScopes(new Scope(Scopes.FITNESS_LOCATION_READ),new Scope(Scopes.FITNESS_ACTIVITY_READ))
.build();
client = new GoogleApiClient.Builder(this)
.enableAutoManage(this,this)
.addApi(Auth.GOOGLE_SIGN_IN_API, signInConfig)
.addApi(Fitness.HISTORY_API)
.addApi(Fitness.GOALS_API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
After login procedure is done I run:
new Thread(new Runnable() {
#Override
public void run() {
PendingResult<DailyTotalResult> result =
Fitness.HistoryApi.readDailyTotal(client, TYPE_STEP_COUNT_DELTA);
DailyTotalResult totalResult = result.await(60,TimeUnit.SECONDS);
if (totalResult.getStatus().isSuccess()) {
DataSet totalSet = totalResult.getTotal();
long total = totalSet.isEmpty()? 0 : totalSet.getDataPoints().get(0).getValue(FIELD_STEPS).asInt();
p("daily steps " + total);
}}).start();
}

You may want to check the correct process in inserting data wherein it was discussed that to insert data into the fitness history, first create a DataSet instance before using the HistoryApi.insertData method and wait synchronously or provide a callback method to check the status of the insertion.
For a more detailed information and sample codes, you may want to check the full documentation.

Similar problem was asked here at G+ GoogleFitDevelopersGroup. Thanks to PujieWear we managed to solve the problem. You have to use two different GoogleApiClient's, one to get authenticated, second to get the data.
I'm no sure wheather this is proper way of using Google Sign-In, but it works.
//Yet, it seems that the Scopes are not yet resolved properly on Wear 2.0.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_SIGN_IN) {
GoogleSignInResult signInResult = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (signInResult.isSuccess()) {
acct = signInResult.getSignInAccount();
editor.putString(ACCOUNT_NAME_PREFS,acct.getEmail());
editor.commit();
dataGoogleApiClientBuilder.setAccountName(acct.getEmail());
dataGoogleApiClient = dataGoogleApiClientBuilder.build();
dataGoogleApiClient.connect();
[...]

Related

Google Play Sign-in: java.lang.SecurityException Not signed in when calling API

Since 1/17/22, we have been seeing a substantial (hundreds per day) number of crashes in our Android app with the following stack trace:
Fatal Exception: java.lang.SecurityException: Not signed in when calling API
at android.os.Parcel.createExceptionOrNull(Parcel.java:2385)
at android.os.Parcel.createException(Parcel.java:2369)
at android.os.Parcel.readException(Parcel.java:2352)
at android.os.Parcel.readException(Parcel.java:2294)
at com.google.android.gms.internal.games.zzb.zzb(com.google.android.gms:play-services-games##21.0.0:22)
at com.google.android.gms.games.internal.zzaf.zza(com.google.android.gms:play-services-games##21.0.0:259)
at com.google.android.gms.games.internal.zzf.onConnectedLocked(com.google.android.gms:play-services-games##21.0.0:752)
at com.google.android.gms.common.internal.BaseGmsClient.zzp(com.google.android.gms:play-services-basement##17.6.0:40)
at com.google.android.gms.common.internal.BaseGmsClient.zzl(:10)
at com.google.android.gms.common.internal.zzf.zza(com.google.android.gms:play-services-basement##17.6.0:6)
at com.google.android.gms.common.internal.zza.zzd(:6)
at com.google.android.gms.common.internal.zzc.zze(com.google.android.gms:play-services-basement##17.6.0:3)
at com.google.android.gms.common.internal.zzb.handleMessage(com.google.android.gms:play-services-basement##17.6.0:31)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:246)
at android.os.HandlerThread.run(HandlerThread.java:67)
We did not change anything with our app during this time, so I believe this was triggered by some update on Google Play Game Services' end.
I see similar reports from a number of years ago, but the common suggestion such as the one in the accepted answer here seems to be using a different API than we do. Our implementation does not use a GoogleApiClient object, but rather a GoogleSignInClient object:
signInClient.silentSignIn().addOnCompleteListener(new OnCompleteListener<GoogleSignInAccount>() {
#Override
public void onComplete(#NonNull Task<GoogleSignInAccount> task) {
...
}
This option does not allow for using the GoogleApiClient.disconnect() method, even via GoogleSignInClient.asGoogleApiClient().
Our GoogleSignInClient setup:
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
.requestScopes(new Scope(Scopes.DRIVE_APPFOLDER))
.requestServerAuthCode("...")
.build();
signInClient = GoogleSignIn.getClient(mainApplication, gso);
Our sign-in handling:
mainApplication().runOnActivityResult(new ActivityResultListener() {
#Override
public void receivedActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RC_SIGN_IN) {
OnSignInAttemptComplete(GoogleSignIn.getSignedInAccountFromIntent(data));
} else if (requestCode == GameHelper.RC_GAME_SERVICES_ACTIVITY) {
if (resultCode == GamesActivityResultCodes.RESULT_RECONNECT_REQUIRED) {
//They logged out
account = null;
listener.onSignedOut();
}
}
}
});
mainApplication.startActivityForResult(signInClient.getSignInIntent(), RC_SIGN_IN);
We have not seen any instances of this crash since February 1st, so it seems safe to assume at this point that it was due to an error on GPGS' end which has since been fixed.

Xamarin Google SignIn for Android - Refresh and Access Tokens

Using VisualStudio, I recently successfully implemented client-flow authentication for my Xamarin.Forms app via the Xamarin.Google.iOS.SignIn NuGet package. This sign-in is then used to allow the app access to our server API components via Azure Mobile Services MobileServicesClient.
It hinges on the ability to pass to Azure the access_token, refresh_token, and id_token from the Google IDP API - all 3 of which are available nicely after a sign in as SignIn.SharedInstance.CurrentUser.Authentication.AccessToken, SignIn.SharedInstance.CurrentUser.Authentication.RefreshToken and SignIn.SharedInstance.CurrentUser.Authentication.IdToken.
I am now trying to implement similar behavior in the Android version of our Xamarin.Forms app using the Xamarin.GooglePlayServices.Auth NuGet package.
However, although I think I have the basics in place for getting a successful authentication with Google, I cannot see how to retrieve the tokens I need from the result.
The google documentation talks about enabling retrieval of the IDToken and ServerAuthCode via setting up the GoogleSignInOptions object before building the APIClient, but not how to get the refresh_ or access_token from google? It seems to want to lay this responsibility onto our sever API. That is not how our iOS app works. Anyone successfully done this in an app using this NuGet package API? Does the Xamarin Android Google SignIn API even support what I want to do?
Yes, this is possible, try something like the following (disregarding where we see App.PostLoginAction - that is specific to my app, although certainly you can take a similar approach and implement an action at the App level as I have done to catch the results).
public class GoogleLoginService : Java.Lang.Object, GoogleApiClient.IConnectionCallbacks, GoogleApiClient.IOnConnectionFailedListener
{
public static GoogleApiClient GoogleApiClient { get; set; }
public static GoogleLoginService Instance { get; private set; }
public GoogleLoginService()
{
Instance = this;
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DefaultSignIn)
.RequestIdToken("YourAppsWebClientId") //note this is the WEB client id, NOT the android app client id
.RequestEmail()
.Build();
GoogleApiClient = new GoogleApiClient.Builder(CrossCurrentActivity.Current.Activity) //note you need to install the plugin king's (James Montemagno) Plugin.CurrentActivity nuget for this
.AddConnectionCallbacks(this)
.AddOnConnectionFailedListener(this)
.AddApi(Auth.GOOGLE_SIGN_IN_API, gso)
.AddScope(new Scope(Scopes.Email))
.AddScope(new Scope(Scopes.Profile))
.Build();
}
public void Login()
{
Intent signInIntent = Auth.GoogleSignInApi.GetSignInIntent(GoogleApiClient);
CrossCurrentActivity.Current.Activity.StartActivityForResult(signInIntent, 1);
GoogleApiClient.Connect();
}
public void Logout()
{
GoogleApiClient.Disconnect();
}
public void OnAuthCompleted(GoogleSignInResult result)
{
if (result.IsSuccess)
{
Task.Factory.StartNew(()=> {
//note result.SignInAccount.IdToken is NOT the access token, so we need this:
var accessToken = GoogleAuthUtil.GetToken(Android.App.Application.Context, result.SignInAccount.Account, $"oauth2:{Scopes.Email} {Scopes.Profile}");
App.PostLoginAction(SocialProvider.Google, accessToken , "Success!");
});
//to get user profile directly, without having to make separate call using the access token:
GoogleSignInAccount account = result.SignInAccount; //contains stuff like name, email, pic url, gender
}
else
{
App.PostLoginAction(SocialProvider.Google, null, "An error occurred.");
}
}
public void OnConnected(Bundle connectionHint)
{
}
public void OnConnectionSuspended(int cause)
{
App.PostLoginAction(SocialProvider.Google, null, "Canceled!");
}
public void OnConnectionFailed(ConnectionResult result)
{
App.PostLoginAction(SocialProvider.Google, null, $"An error occurred: {result.ErrorMessage}");
}
}

GoogleSignInResult returns DEVELOPER_ERROR in Android app using Firebase

So I've been messing with this for a couple of days now and I cannot figure out why it doesn't work. I am really hoping someone can help me.
I am trying to authenticate a user with Google sign in using Firebase. So following their guide here I have set up Google sign in to get an OAuth token and then use that to authenticate with Firebase. So I set up Google as they describe in their guide here but that is as far as I got. The OAuth token I get from Google is always null and the result code is Status{statusCode=DEVELOPER_ERROR, resolution=null}.
So far, my activity looks like this:
public static final int RC_GOOGLE_LOGIN = 1;
private GoogleApiClient mGoogleApiClient;
final Context context = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Firebase.setAndroidContext(this);
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestIdToken(this.getResources().getString(R.string.server_client_id))
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
SignInButton signInButton = (SignInButton) findViewById(R.id.googlebtn);
signInButton.setSize(SignInButton.SIZE_WIDE);
signInButton.setScopes(gso.getScopeArray());
signInButton.setOnClickListener(this);
}
#Override
public void onClick (View v) {
switch (v.getId()) {
case R.id.googlebtn:
signIn();
break;
}
}
private void signIn() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_GOOGLE_LOGIN);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_GOOGLE_LOGIN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
handleSignInResult(result);
}
}
private void handleSignInResult(GoogleSignInResult result) {
if (result.isSuccess()) {
// Signed in successfully, show authenticated UI.
GoogleSignInAccount acct = result.getSignInAccount();
String idToken = acct.getIdToken();
}
}
I have been googling this for a while and think I've tried everything that is already suggested. Of course I have done everything in the guides, added dependencies ('com.google.android.gms:play-services-auth:8.4.0') and created the necessary clients in the developer console.
I have also checked (multiple times) that the server client ID I am using is the right one from the Developer console, and that it matches my package name in both my gradle file and Manifest file. I have added the google-services.json file to my /app directory and even regenerated it to make sure it matches. I have also checked that the SHA1 key is correct and it still gives the same error.
If I remove the requestIdToken from the Google sign in options it works though, but that doesn't help me as I then cannot sign in with Firebase. Can someone tell me what I need to do to make it work?
Have you set your R.string.server_client_id?
Open the Credentials page in the API Console.
The Web application type client ID is your backend server's OAuth 2.0 client ID.
https://developers.google.com/identity/sign-in/android/start-integrating#get_your_backend_servers_oauth_20_client_id
After the SHA-1 this is the next stumbling point that I've seen.

Handle GoogleFit in background in Android App

I am trying to connect my app to Google Fit. I am using an IntentService that needs to do the following things. Gets started when I have information about steps. At this point I am trying to create the GoogleApiClient by calling the following code:
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ_WRITE))
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
log.info("FITNESS_API: Connected!!!");
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
insertOrUpdateDataPoints();
}
});
thread.start();
}
#Override
public void onConnectionSuspended(int i) {
// 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.info("FITNESS_API: Connection lost. Cause: Network Lost.");
} else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
log.info("FITNESS_API: Connection lost. Reason: Service Disconnected");
}
}
}
).build();
mClient.connect();
After creating a DataSet and adding the steps details as DataPoint elemnets, I sync the information to Google Fit and close the GoogleApiClient with:
com.google.android.gms.common.api.Status insertStatus =
Fitness.HistoryApi.insertData(mClient, dataSet).await(1, TimeUnit.MINUTES);
// Before querying the data, check to see if the insertion succeeded.
if (!insertStatus.isSuccess()) {
log.info("FITNESS_API: There was a problem inserting the dataset. Status = " + insertStatus.getStatusCode());
}
mClient.disconnect();
mClient = null;
The problem is that by trying to manage the GoogleApiClient on my own (without enableAutoManage), I don't get prompted to allow the app to post data to Google Fit. This behaviour changes if I use enableAutoManage when creating the GoogleApiClient. However, in order to enableAutoManage for the client, I need to have a ActivityFragment due to the parameters required by enableAutoManage. I don't have access to an ActivityFragment in the IntentyService and I do want to keep the management of the client and the insert action in a separate service which can run in the background.
Also when I don't use enableAutoManage even though I have registered the connect callback for the GoogleApiClient nothing happens.
How can I ensure that my application prompts the user to allow the app to post to Google Fit? I need this to happen if the app doesn't have permission to post in Google Fit when the user opens the app. Any ideas? Thank you.
I have found the solution.
If you don't want to use "enableAutoManage", you need to register onConnectionFailed method like this:
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if( !authInProgress ) {
try {
authInProgress = true;
connectionResult.startResolutionForResult( MainActivity.this, REQUEST_OAUTH );
} catch(IntentSender.SendIntentException e ) {
}
} else {
Log.e( "GoogleFit", "authInProgress" );
}
}
This will present the dialog.
In your intent service use the above method mentioned by #Vlad. Create a notification(Sticky or otherwise depending on your importance) asking user to give you permission when onconnection failed is encountered. The notification will redirect user to an activity where you ask user to give you fitaccess again.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_OAUTH:
if (resultCode != Activity.RESULT_OK) {
return;
}
if (!googleApiClient.isConnected()) {
googleApiClient.connect(GoogleApiClient.SIGN_IN_MODE_OPTIONAL);
} else {
readDataTask();
}
return;
case RC_SIGN_IN:
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (result.isSuccess()) {
GoogleSignInAccount account = result.getSignInAccount();
String email = account.getEmail();//you can get OAuth user's email AT THIS POINT.
if (GoogleFitService.googleApiClient.isConnected()) {
readDataTask();
}
}
}
}
First time what you have to DO is Oauth Goole accout, then get your's email.
gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.setAccountName("user's email")
.requestScopes(
new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE),
new Scope(Scopes.FITNESS_BODY_READ_WRITE),
new Scope(Scopes.FITNESS_NUTRITION_READ_WRITE),
new Scope(Scopes.FITNESS_LOCATION_READ_WRITE))
.build();
when you get Google Fit data at background, you need to set Email.

Can't get user birthday with Google Play services API

EDIT
After a new try I finally got my birthday. I didn't change the implementation. I guess it took a few hours for the changes in my Google Plus profile to propagate, making my birthday public. A bit more than expected. Now I'm wondering whether I can ask this permission (birthday) when the user sign in, without the need of the birthday to be public.
As suggested by this information in the developers guide :
For additional profile data that might be available, see
GoogleSignInAccount. Note that any of the profile fields can be null,
depending on which scopes you requested and what information the
user's profile includes.
Initial POST
I would like to get the birthdays of a user after he signed in Google Plus. Being not familiar with Google APIs in general, I'm wondering whether my implementation makes some sense or not. Right now, I'm just trying to get my own birthday from my Google account linked to my device.
Here is what I did. I followed the steps from developer guide for the sign in procedure. In addition to OAuth, I added the Google Plus dependency in gradle:
compile 'com.google.android.gms:play-services-plus:8.3.0'
In my Activity, there is a button to sign in Google Plus.
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(new Scope(Scopes.PLUS_ME), new Scope(Scopes.PLUS_LOGIN),new Scope(Scopes.PROFILE))
.build();
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Plus.API)
.build();
loginButton = (SignInButton) findViewById(R.id.sign_in_button);
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}
});
After the initial sign in, I try to connect to the Google Play Services.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
Log.d(TAG, "handleSignInResult:" + result.isSuccess());
if (result.isSuccess()) {
mGoogleApiClient.connect(GoogleApiClient.SIGN_IN_MODE_OPTIONAL);
}
}
}
Once connected, I try to fetch the birthday of the user.
#Override
public void onConnected(Bundle bundle) {
Person currentPerson = Plus.PeopleApi
.getCurrentPerson(mGoogleApiClient);
addGoogleProfile(currentPerson); //Add the user to a list of persons
refreshListView(); //update the listView
Log.d(TAG, "Current person: name=" + currentPerson.getDisplayName() + ", has birthday = " + (currentPerson.hasBirthday() ? "yes, it is" + currentPerson.getBirthday() : "no"));
}
Problem
The birthday is never set and always appears to be null. Other data such as the name and profile image are accessible. I didn't find much information on the different Scopes. I'm more familiar with Facebook API where the permissions are more explicitly requested upon login.
Any idea on what I am missing ?
Ho and I set my birthday field as "public" of the associated Google account.
Cheers
Dear you can only getting the following information :-
mePerson.getId()
mePerson.getDisplayName()
mePerson.getImage().getUrl()
mePerson.getUrl()
We can get the birthday of a user from gmail, but for that the user needs to have public visibility of the birthday.
Follow these steps:
Login to gmail and go to: https://myaccount.google.com/u/1/birthday?hl=en&pli=1
Click on "Manage sharing settings" and set birthday to public
Add scope: https://www.googleapis.com/auth/plus.login

Categories

Resources