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 :)
Related
I have implemented Google Signing for Android app. The user can successfully login from the Google Login Button.
This screen appears while selecting a Social Account: Screenshot
So now the user has logged in successfully by selecting his/her account.
Now, user logs out, and tries to sign in again by using Google Login Button.
At this time, he is not asked with the option to choose account, he is automatically logged in using the account he/she selected at the first time.
At the time of logout what should I do to clear the cache of selected account.
In firebase documentation for android, they only refer to use this:
Firebase.auth.signOut()
However, next time the user logs in, the app will automatically select the previous email. To avoid this, you should use the follow code as well:
googleSignInClient.signOut()
As you didn't provide any code or reference how you are logging in and logging out, it might be that you incorrectly sign out user from the app.
So here is what docs describe one should do on user logout:
https://developers.google.com/identity/sign-in/android/disconnect
Sign out:
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
// ...
}
});
Note: You must confirm that GoogleApiClient.onConnected has been called before signing out.
Also check status which comes in onResult - maybe there is some error, which might lead to the answer.
GoogleSignInOptions gso = new GoogleSignInOptions.
Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).
build();
GoogleSignInClient googleSignInClient= GoogleSignIn.getClient(this,gso);
googleSignInClient.signOut().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()){
FirebaseAuth.getInstance().signOut(); // very important if you are using firebase.
Intent login_intent = new Intent(getApplicationContext(),YouLoginActivity.class);
login_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK); // clear previous task (optional)
startActivity(login_intent);
}
}
});
try using this method to log out from Google sign in:
Make sure u call it after u successfully get logged in onConnected(Bundle arg0)
public void Disconnect_google() {
try {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
mGoogleApiClient.clearDefaultAccountAndReconnect().setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
mGoogleApiClient.disconnect();
Toast.makeText(getApplicationContext(),"Disconnected",Toast.LENGTH_SHORT).show();
}
});
}
} catch (Exception e) {
Log.d("DISCONNECT ERROR", e.toString());
}
}
At the time of logout when you are login from google then use below code
if (mGoogleApiClient.isConnected()) {
Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
mGoogleApiClient.disconnect();
mGoogleApiClient.connect();
}
your problem will solve by using only single line for signOut instead of 8 lines code you can use in the signInActivity when you are signing a user
private fun signIn() {
googleSignInClient.signOut()
val signInIntent = googleSignInClient.signInIntent
startActivityForResult(signInIntent, RC_SIGN_IN)
}
and in the sign out function you can just use this
FirebaseAuth.getInstance().signOut()
where FirebaseAuth is : com.google.firebase.auth public abstract class FirebaseAuth
When you login using google it will show all the signin google account in the device. when you select any one than it proceed further but when you logout from your system and login it again. it directly choose the previous account.
so for choosing from all existing account in device you have to clear the app data.
for clearing app data follow below steps
1. go to device settings
2. choose APPs
3. select your app
4. storage/clear data
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.
I am using Google Sign in for authentication. Following the tutorial, I am able to log in. Now I want to log out the user. I got the code for logging out. But how to do I know that the logout is success or fail?
private void signOut() {
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
// What code should I write here to see if the user has successfully logged out. If not, then I need to display an error message.
}
});
}
Google can return 5 types status. Following are the statuses along with the status codes:-
SUCCESS(0), INTERNAL_ERROR(8), INTERRUPTED(14), TIMEOUT(15), CANCELED(16)
So you can check for status.getStatusCode() on logout and validate against the above mentioned statuses.
Just use
status.toString()
and log it to find out what details it contains. Then according to it you can use the below methods to check if you have been successfully logged out.
status.getStatusCode();
status.getStatusMessage();
Both methods are self explanatory.
I found a better approach to the question
Auth.GoogleSignInApi.signOut(googleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
// user logged out successfully
} else {
// the logout was not sucessful.
}
});
I'm new to Android Wearable and Google Fit. I'm investigating how Google Fit Recording API works by creating a simple Android app with the following code in the Main Activity (these were taken from Google's Basic Recording API example):
#Override
protected void onCreate(Bundle savedInstanceState) {
...
buildFitnessClient();
}
private void buildFitnessClient() {
// Create the Google API Client
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.RECORDING_API)
.addScope(Fitness.SCOPE_LOCATION_READ_WRITE)
.addScope(Fitness.SCOPE_ACTIVITY_READ_WRITE)
.addScope(Fitness.SCOPE_BODY_READ_WRITE)
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected!!!");
// Now you can make calls to the Fitness APIs. What to do?
// Subscribe to some data sources!
subscribe();
}
#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 == ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i == ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG, "Connection lost. Reason: Service Disconnected");
}
}
}
)
.enableAutoManage(this, 0, new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Google Play services connection failed. Cause: " +
result.toString());
Snackbar.make(
MainActivity.this.findViewById(R.id.main_activity_view),
"Exception while connecting to Google Play services: " +
result.getErrorMessage(),
Snackbar.LENGTH_INDEFINITE).show();
}
})
.build();
}
/**
* Subscribe to an available {#link DataType}. Subscriptions can exist across application
* instances (so data is recorded even after the application closes down). When creating
* a new subscription, it may already exist from a previous invocation of this app. If
* the subscription already exists, the method is a no-op. However, you can check this with
* a special success code.
*/
public void subscribe() {
// To create a subscription, invoke the Recording API. As soon as the subscription is
// active, fitness data will start recording.
// [START subscribe_to_datatype]
Fitness.RecordingApi.subscribe(mClient, DataType.TYPE_STEP_COUNT_DELTA)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
if (status.getStatusCode()
== FitnessStatusCodes.SUCCESS_ALREADY_SUBSCRIBED) {
Log.i(TAG, "Existing subscription for activity detected.");
} else {
Log.i(TAG, "Successfully subscribed!");
}
} else {
Log.i(TAG, "There was a problem subscribing: " + status.getStatusMessage());
}
}
});
// [END subscribe_to_datatype]
}
I wasn't sure how the recording API works. According to Google Fit documentation, the API would automatically take care of the tracking of steps (in this case) and storing the number of steps into the Fitness Store. So what I expected the app to work was starting the app, walking for a while, and when checking my Google Fit account, the number of steps should be increased.
However, this never occurred.
Could you please correct me if my understanding wasn't right, or if it is, please point me to the right direction to get this code working.
Cheers
Update: After more than an hour, my Google Fit data shown that the number of steps increased from 3033 (previously generated by the Fit app, which was then removed to securely testing this app) to 5011. The increasing amount is very confusing because I simulated steps by shaking my phone and certainly I didn't sake it 2000 times! I used Sensor API to display the number of steps in real time and the total of these numbers were only below 200.
Moreover, I manually checked the data every 10-20 mins and I'm sure that it took more than 1 hour for the data to get updated. According to Google Fit's documentation, the storing of data (into Fitness Store) is done automatically in a "battery- efficient manner". It however doesn't mention clearly how that is done, i.e., how frequently.
It would be great if someone can help me with these questions. Any help appreciated!
Can you filter it by using the confidence level for each activity?
eg.
An example of the values for a likely detection of walking may be:
walking -> 20.0
in_vehicle -> 10.0
biking -> 66.6
I am trying to find a good documented example of how to perform a login in my app using a google account.
Maybe I am looking in the wrong place, but i can't find anything in the android sdk docs. From what i understand its part of Google Services but still having problems find examples.
I also need to support if the user has more than 1 google account configured on the device to popup and ask which account to use.
Then on future loading of my app I would automatically login.
Can anyone point me in the right direction, or are there no examples available?
Thanks
You probably want to use this guide:
https://developers.google.com/+/mobile/android/sign-in
From the guide:
You must create a Google APIs Console project and initialize the PlusClient object.
Add the Google+ Sign-In button to your app
Add the SignInButton in your application's layout:
<com.google.android.gms.common.SignInButton
android:id="#+id/sign_in_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Initialize mPlusClient with the requested visible activities in your Activity.onCreate handler.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPlusClient = new PlusClient.Builder(this, this, this)
.setVisibleActivities("http://schemas.google.com/AddActivity", "http://schemas.google.com/BuyActivity")
.build();
}
In the Android activity, register your button's OnClickListener to sign in the user when clicked:
findViewById(R.id.sign_in_button).setOnClickListener(this);
After the user has clicked the sign-in button, you should start to resolve any connection errors held in mConnectionResult. Possible connection errors include prompting the user to select an account, and granting access to your app.
#Override
public void onClick(View view) {
if (view.getId() == R.id.sign_in_button && !mPlusClient.isConnected()) {
if (mConnectionResult == null) {
mConnectionProgressDialog.show();
} else {
try {
mConnectionResult.startResolutionForResult(this, REQUEST_CODE_RESOLVE_ERR);
} catch (SendIntentException e) {
// Try connecting again.
mConnectionResult = null;
mPlusClient.connect();
}
}
}
}
When the user has successfully signed in, your onConnected handler will be called. At this point, you are able to retrieve the user’s account name or make authenticated requests.
#Override
public void onConnected(Bundle connectionHint) {
mConnectionProgressDialog.dismiss();
Toast.makeText(this, "User is connected!", Toast.LENGTH_LONG).show();
}