I have successfully added Google authentication in android app. I am able to login properly without any error. But when i try to logout GoogleApiClient is giving me null so that i am failing to logout successfully. I tried so many answers here but nothing worked for me. Below is the code I entered in my MainActivity.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if(ApplicationPreferences.get().isFirstTimeUser()) {
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(new Scope(GmailScopes.GMAIL_READONLY))
.requestServerAuthCode(Constants.SERVER_CLIENT_ID, true)
.requestEmail()
.build();
signInButton.setSize(SignInButton.SIZE_STANDARD);
signInButton.setScopes(gso.getScopeArray());
signInButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.sign_in_button:
signIn();
break;
}
}
});
signInButton.setVisibility(View.VISIBLE);
// Build a GoogleApiClient with access to the Google Sign-In API and the
// options specified by gso.
mGoogleApiClient = new GoogleApiClient.Builder(MainActivity.this)
.enableAutoManage(MainActivity.this, MainActivity.this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.addConnectionCallbacks(MainActivity.this)
.build();
mGoogleApiClient.connect();
} else {
loadMainActivity();
}
}
}, 2000);
Below is my signOut method as specified by Documentation but i failed to understand their statement You must confirm that GoogleApiClient.onConnected has been called before you call signOut. Need some idea what I am doing wrong here.
if (mGoogleApiClient != null)
{
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
ApplicationPreferences.get().clearAll();
Intent intent = getIntent();
finish();
startActivity(intent);
}
});
}
My OnStart()
#Override
public void onStart() {
super.onStart();
OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
if (opr.isDone()) {
// If the user's cached credentials are valid, the OptionalPendingResult will be "done"
// and the GoogleSignInResult will be available instantly.
Log.d(TAG, "Got cached sign-in");
GoogleSignInResult result = opr.get();
handleSignInResult(result);
} else {
// If the user has not previously signed in on this device or the sign-in has expired,
// this asynchronous branch will attempt to sign in the user silently. Cross-device
// single sign-on will occur in this branch.
showProgressDialog();
opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
#Override
public void onResult(GoogleSignInResult googleSignInResult) {
hideProgressDialog();
handleSignInResult(googleSignInResult);
}
});
}
}
The error, if you say callbacks are not being called, might just be the sign that you may not have connected first. I imagine you have implemented the callbacks and they are not being called?
In any case, to "handle" the error situation, you may want to check if the GoogleApiClient is connected.. like this:
if (mGoogleApiClient != null && mGoogleApiClient.isConnected())
{
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
ApplicationPreferences.get().clearAll();
Intent intent = getIntent();
finish();
startActivity(intent);
}
});
}
else{
Log.w("SomeTag", "It looks like GoogleApiClient is not connected");
}
But I do think you need to check if there are any errors (for instance does onConnectionFailed(ConnectionResult result) get called instead? What error do you see?
Hope this helps.
Related
I'm working on an Android app that does the following:
Upon app start-up, it checks if a user is logged in, using AuthStateListener.
If there is a user logged in, it retrieves data from Firestore. The user data is stored in a document that I named with the following nomenclature: "User " + user's_email_ID. For example, if a user has an email ID xyz#gmail.com, his data will be stored in the document named: User xyz#gmail.com.
All documents are within the collection named "Users".
If all the fields are null/ empty in the user's data document, the app opens an Activity that asks him/her to fill all the details. Else, it takes the user to the main page (StudentMainActivity if the user is a student, or ProfessorMainActivity if the user is a professor).
Coming to my problem:
The block of code which checks whether the fields are empty has some erratic and unpredictable behavior. I'm not sure if this is a problem based on Firestore, or on the fact that data retrieval happens on a different thread.
I checked the Firestore database and saw that all fields were filled. However, when a user (who's already logged in) starts the app, the app knows that it is the same user (i.e. he's not prompted to sign in, because AuthStateListener does its job), but instead of being redirected to either StudentMainActivity or ProfessorMainActivity (the main screens), he's asked to fill his details again.
What's more confusing is that this bug doesn't always occur. There are times when the app does what is expected, i.e. take the user to the main screen, but the next time he starts the app, he's again taken to the activity that asks him to enter his details.
Source Code:
LoginActivity.java (Only the relevant parts)
//AuthStateListener is in onCreate
authStateListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null){
UIDEmailID = user.getEmail();
updateUI(user);
}
else{
updateUI(null);
}
}
};
private void updateUI(FirebaseUser user){
// Update UI after login
if (user != null) {
Toast.makeText(LoginActivity.this, "User " + UIDEmailID, Toast.LENGTH_LONG).show();
db.collection("Users").document("User " + UIDEmailID).get()
.addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (documentSnapshot.get("department") != null || // if any
documentSnapshot.get("phoneNumber") != null || // field in
documentSnapshot.get("name") != null || // Firestore is
documentSnapshot.get("studentSemester") != null || // non-null then
documentSnapshot.get("dateOfBirth") != null || // proceed to
documentSnapshot.get("university") != null) { // further activities
if (documentSnapshot.get("userType") == "Lecturer/ Professor") {
Intent intent = new Intent(LoginActivity.this, ProfessorMainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
else {
Intent intent = new Intent(LoginActivity.this, StudentMainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
} else {
Toast.makeText(LoginActivity.this, "We need some additional details before we go ahead.", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(LoginActivity.this, GFBDetailsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(LoginActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
I'm sorry for the long question; I just tried to make it super descriptive. Some help would be greatly appreciated.
P.S. The reason I think this is a problem involving the usage of multiple threads is because whenever the app runs as expected (i.e. takes the user to the main screen), the toast "We need some additional details before we go ahead." appears as well. If you look at the code (the last "else" block) you will realise that it is in a seperate conditional block altogether, and thus isn't even supposed to show up if the main screen (which is in another conditional block) shows up.
EDIT 1:
I'm enclosing screenshots pertaining to the problem. Ignore the bland UI :P
This is what's expected (Comes under the second 'else' block). It is supposed to show up only if the user is logging in for the first time, i.e. does not have his data stored in a Firestore document.
The background is StudentMainActivity (inside the nested 'else'). However, even the Toast is displayed (it belongs to a seperate block altogether).
So it turns out Firestore wasn't (entirely) at fault.
Every activity in an Android application has a life span, and every time an activity is run, it goes through an elaborate sequence of lifecycle functions.
An activity's lifecycle is as follows:
Launched --> onCreate() --> onStart() --> onResume() --> Running --> onPause() --> onStop() --> onDestroy() --> Finished
I won't be digressing by going into the details of each function, because the function names are quite intuitive and self-explanatory.
As you can see in the code snippet in the question, onAuthStateChanged() is inside onCreate(). My Document ID on Firebase is of the form "User UIDEmailID", where UIDEmailID is the email ID of the user. And UIDEmailID gets updated only in onAuthStateChanged() (which, in turn, is inside onCreate()), i.e. only when the activity starts afresh, after the app has been closed and opened again.
Therefore, I updated UIDEmailID in onStart() as well, which means that every time an app is resumed, it will retrieve the email ID of the user, which can subsequently be used to retrieve the document from Firestore.
Also, I slightly tweaked my Firestore data retrieval bit of code upon advice from Nibrass H. The solution is as follows:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
running = true;
if (savedInstanceState != null){
running = savedInstanceState.getBoolean("running");
wasrunning = savedInstanceState.getBoolean("wasrunning");
}
setContentView(R.layout.splash_screen);
firebaseAuth = FirebaseAuth.getInstance();
db = FirebaseFirestore.getInstance();
authStateListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth1) {
FirebaseUser user = firebaseAuth1.getCurrentUser();
if (user != null){
UIDEmailID = user.getEmail();
updateUI(user);
} else {
updateUI(null);
}
}
};
}
#Override
protected void onStart() {
super.onStart();
firebaseAuth.addAuthStateListener(authStateListener);
if (firebaseAuth.getCurrentUser() != null) {
UIDEmailID = firebaseAuth.getCurrentUser().getEmail();
updateUI(firebaseAuth.getCurrentUser());
} else {
updateUI(null);
}
}
#Override
protected void onRestart() {
super.onRestart();
authStateListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth1) {
FirebaseUser user = firebaseAuth1.getCurrentUser();
if (user != null) {
UIDEmailID = user.getEmail();
updateUI(user);
} else {
updateUI(null);
}
}
};
}
#Override
protected void onPause() {
super.onPause();
wasrunning = running;
running = false;
}
#Override
protected void onResume() {
super.onResume();
if (wasrunning){
running = true;
}
}
#Override
protected void onStop() {
super.onStop();
if (authStateListener != null) {
firebaseAuth.removeAuthStateListener(authStateListener);
}
}
private void updateUI(FirebaseUser firebaseUser){
if (firebaseUser != null){
Toast.makeText(this, "User " + firebaseUser.getEmail(), Toast.LENGTH_SHORT).show();
db.collection("Users").document("User " + UIDEmailID).get()
.addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (documentSnapshot.get("userType") != null) {
if (documentSnapshot.get("userType").equals("Lecturer/ Professor")){
Intent intent = new Intent(SplashScreenActivity.this, ProfessorMainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
finish();
startActivity(intent);
} else {
Intent intent = new Intent(SplashScreenActivity.this, StudentMainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
finish();
startActivity(intent);
}
} else {
Toast.makeText(SplashScreenActivity.this, "We need some additional details before we go ahead.", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(SplashScreenActivity.this, GFBDetailsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
finish();
startActivity(intent);
}
}
});
}
}
I have my login setup like this, I use retrofit to authenticate from the server and I'm using a token api authentication:
In the MainActivity.java method onCreate
apiInterface = ApiClient.getClient().create(ApiInterface.class);
User user = SharedPreferencesHelper.getUser(MainActivity.this);
if (user.getToken() == null) {
Intent login = new Intent(MainActivity.this, LoginActivity.class);
startActivity(login);
} else {
setContentView(R.layout.activity_main);
buildMain();
}
In the LoginActivity.java method on create (I'll summarize, the code is quite long)
loginbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//get login ingo
Login login = new Login(scardI, passwordI, device_name);
Call<User> call = apiInterface.LoginUser(login);
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
User user = response.body();
//save user info into SharedPreferences
SharedPreferencesHelper.setUser(LoginActivity.this, user);
//check if user saved correctly by getting the user token
if (SharedPreferencesHelper.getUserToken(LoginActivity.this) != null) {
finish();
}
} else {
//show error message
}
}
#Override
public void onFailure(Call<User> call, Throwable t) {
//show error message
}
});
}
});
I'm having an issue, after the user logs in a blank page is displayed instead of the activity_main.xml however when I close the app and reopen it it takes me straight to the activity_main.xml as expected. Is there a reason that after the login it doesn't take me to the activity_main like expected.
An intent to MainActivity.java is missing on success. A blank screen is displayed because finish() is called.
if (response.isSuccessful()) {
User user = response.body();
SharedPreferencesHelper.setUser(LoginActivity.this, user);
if (SharedPreferencesHelper.getUserToken(LoginActivity.this) != null){
Intent i = new Intent(this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(i);
}
}
I'm writing this question and answer because I haven't seen a full solution to the integration of Google sign in on Android using Facebook's Parse SDK (or Sashido in my case) as a back-end without cloud code.
Related Questions:
How to link Google + signed in users on Parse backend on Android?
Google Plus Login issues - Parse.com
How would one go about integrating Google Sign in with Parse back-end without Cloud Code?
First of all, follow the steps provided by Android Developers on starting and implementing the integration.
Start Integrating Google Sign-In into Your Android App
Integrating Google Sign-In into Your Android App
In the onCreate your activity you need to build the GoogleSignInOptions
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build();
You can get your web_client_id when you add Google Services to your project to your Google Developers account. Find out more at: Creating a Google API Console project and client ID
Build your GoogleApiClient (make it a global instance private GoogleApiClient mGoogleApiClient;)
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.e("Failed", "failed" + connectionResult.getErrorMessage());
}
})
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
Listen out for the click on the dedicated button for your Google sign in and then start a Auth.GoogleSignInApi.getSignIntent(mGoogleApiClient);
case R.id.btn_google:
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
break;
Make sure you've assigned a value to RC_SIGN_IN (I've done 1000)
Now start adding implementation to your onActivityResult method
// Result returned from launching the Intent from
// GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
handleSignInResult(result);
} else {
ParseFacebookUtils.onActivityResult(requestCode, resultCode, data);
}
Now to handle the sign in request:
`private void handleSignInResult(GoogleSignInResult result) {
Log.e("handleSignIn", "handleSignInResult:" + result.isSuccess());
if (result.isSuccess()) {
// Signed in successfully, show authenticated UI.
final GoogleSignInAccount acct = result.getSignInAccount();
if (acct != null) {
ParseQuery<ParseObject> query = ParseQuery.getQuery("_User");
query.setLimit(10000);
query.whereEqualTo("email", acct.getEmail());
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
if (e == null) {
if (objects.size() == 0) {
saveNewUserGoogle(acct);
} else {
loginGoogleUser(objects.get(0), acct);
}
} else {
saveNewUserGoogle(acct);
}
}
});
}
} else {
Log.e("failed", "failed to sign in");
// Signed out, show unauthenticated UI.
}
}`
So what this method does is if the request to the GoogleSignIn Request is successful, get the account details, query the _User table in your database and to see if the email with the account matches. If it does, Log the user in.
private void loginGoogleUser(ParseObject j, GoogleSignInAccount acct) {
ParseUser.logInInBackground(j.getString("username"), String.valueOf(acct.getId()), new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
Intent i = new Intent(AllLoginActivity.this, MainActivity.class);
startActivity(i);
finish();
} else {
Log.e("failed", "could not be validated");
}
}
});
}
else sign the user up:
private void saveNewUserGoogle(GoogleSignInAccount acct) {
google = true;
final ParseUser user = new ParseUser();
String mFullName = acct.getDisplayName();
String mEmail = acct.getEmail();
String mProfilePic = String.valueOf(acct.getPhotoUrl());
String mUsername = acct.getId();
String password = acct.getId();
user.setUsername(mUsername);
user.setEmail(mEmail);
user.setPassword(password);
user.put("userEmail", mEmail);
user.put("uniqueID", mUsername);
user.put("name", mFullName);
user.put("loginMethod", "Google");
user.put("profilePicture", mProfilePic);
user.signUpInBackground(new SignUpCallback() {
public void done(ParseException e) {
if (e == null) {
Log.e("SaveTest", "Successful");
//sign user up
} else {
switch (e.getCode()) {
case ParseException.USERNAME_TAKEN:
Toast.makeText(context, "Sorry, this username has already been taken.", Toast.LENGTH_SHORT).show();
break;
case ParseException.USERNAME_MISSING:
Toast.makeText(context, "Sorry, a username is needed", Toast.LENGTH_SHORT).show();
break;
case ParseException.PASSWORD_MISSING:
Toast.makeText(context, "Sorry, a password is needed.", Toast.LENGTH_SHORT).show();
break;
case ParseException.OBJECT_NOT_FOUND:
Toast.makeText(context, "invalid credentials", Toast.LENGTH_SHORT).show();
break;
case ParseException.CONNECTION_FAILED:
Toast.makeText(context, "Sorry, internet is needed.", Toast.LENGTH_SHORT).show();
break;
default:
Log.d("Testing", e.getLocalizedMessage());
break;
}
}
}
});
}
So for this if you set the password on Parse as the clientID it'll be unique to that user and can be read by Parse and given by Google.
Note: I'm setting the username as the Google Identifier and then when they have successfully connected and signed up I display a username dialog box where they enter a username, so it can be displayed as something in plain text rather than numerics.
I have a problem with leadherBoard via Google Games.
I have login into app. login run good.
I have copied some block of code from internet and login run good...
But If I want send score in LatherBoard or work with latherboard.
Games.Leaderboards.submitScore(mGoogleApiClient, getString(LEADERBOARD_ID)), 137);
startActivityForResult(Games.Leaderboards.getLeaderboardIntent(mGoogleApiClient,
getString(LEADERBOARD_ID)), REQUEST_LEADERBOARD);
Becoause I testing app I have thise code under Button. But If I press this button Application crashed.
But I don't know why.
I sign in with thise code (code from internet not mine)
#Override
public void onStart() {
super.onStart();
OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
if (opr.isDone()) {
// If the user's cached credentials are valid, the OptionalPendingResult will be "done"
// and the GoogleSignInResult will be available instantly.
GoogleSignInResult result = opr.get();
handleSignInResult(result);
} else {
// If the user has not previously signed in on this device or the sign-in has expired,
// this asynchronous branch will attempt to sign in the user silently. Cross-device
// single sign-on will occur in this branch.
// showProgressDialog();
opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
#Override
public void onResult(GoogleSignInResult googleSignInResult) {
// hideProgressDialog();
handleSignInResult(googleSignInResult);
}
});
}
}
// [START onActivityResult]
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
handleSignInResult(result);
}
}
// [END onActivityResult]
// [START handleSignInResult]
private void handleSignInResult(GoogleSignInResult result) {
if (result.isSuccess()) {
// Signed in successfully, show authenticated UI.
GoogleSignInAccount acct = result.getSignInAccount();
mStatusTextView.setText(getString(R.string.signed_in_fmt, acct.getDisplayName()));
updateUI(true);
} else {
// Signed out, show unauthenticated UI.
updateUI(false);
}
}
// [END handleSignInResult]
// [START signIn]
private void signIn() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}
// [END signIn]
// [START signOut]
private void signOut() {
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
// [START_EXCLUDE]
updateUI(false);
// [END_EXCLUDE]
}
});
}
// [END signOut]
// [START revokeAccess]
private void revokeAccess() {
Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
// [START_EXCLUDE]
updateUI(false);
// [END_EXCLUDE]
}
});
}
// [END revokeAccess]
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// An unresolvable error has occurred and Google APIs (including Sign-In) will not
// be available.
}
private void showProgressDialog() {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage("Loading...");
mProgressDialog.setIndeterminate(true);
}
mProgressDialog.show();
}
private void hideProgressDialog() {
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.hide();
}
}
private void updateUI(boolean signedIn) {
if (signedIn) {
findViewById(R.id.sign_in_button).setVisibility(View.GONE);
findViewById(R.id.sign_out_and_disconnect).setVisibility(View.VISIBLE);
} else {
mStatusTextView.setText(R.string.signed_out);
findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
findViewById(R.id.sign_out_and_disconnect).setVisibility(View.GONE);
}
}
public void Login(){
// Views
mStatusTextView = (TextView) findViewById(R.id.status);
// Button listeners
findViewById(R.id.sign_in_button).setOnClickListener(this);
findViewById(R.id.sign_out_button).setOnClickListener(this);
findViewById(R.id.disconnect_button).setOnClickListener(this);
// [START configure_signin]
// Configure sign-in to request the user's ID, email address, and basic
// profile. ID and basic profile are included in DEFAULT_SIGN_IN.
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
// [END configure_signin]
// [START build_client]
// Build a GoogleApiClient with access to the Google Sign-In API and the
// options specified by gso.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
// [END build_client]
// [START customize_button]
// Customize sign-in button. The sign-in button can be displayed in
// multiple sizes and color schemes. It can also be contextually
// rendered based on the requested scopes. For example. a red button may
// be displayed when Google+ scopes are requested, but a white button
// may be displayed when only basic profile is requested. Try adding the
// Scopes.PLUS_LOGIN scope to the GoogleSignInOptions to see the
// difference.
SignInButton signInButton = (SignInButton) findViewById(R.id.sign_in_button);
signInButton.setSize(SignInButton.SIZE_STANDARD);
signInButton.setScopes(gso.getScopeArray());
// [END customize_button]
}
I don't know what problem are crashed application because in genymotion i can't use login. and my mobile can't use adb driver. Please Help me.
or give mi advice where I can download runing code with leadherboards I will try understanding and use in my application.
Thanks.
Edit
Log? from firebase
Exception java.lang.IllegalStateException: GoogleApiClient is not configured to use the Games Api. Pass Games.API into GoogleApiClient.Builder#addApi() to use this feature.
com.google.android.gms.common.internal.zzaa.zza ()
com.google.android.gms.games.Games.zzc ()
com.google.android.gms.games.Games.zzb ()
com.google.android.gms.games.internal.api.LeaderboardsImpl.submitScore ()
com.google.android.gms.games.internal.api.LeaderboardsImpl.submitScore ()
sk.atest.paradox02.animacia.Index.onClick (Index.java:963)
android.view.View.performClick (View.java:5207)
android.view.View$PerformClick.run (View.java:21177)
android.os.Handler.handleCallback (Handler.java:739)
android.os.Handler.dispatchMessage (Handler.java:95)
android.os.Looper.loop (Looper.java:148)
android.app.ActivityThread.main (ActivityThread.java:5438)
I'm trying to use the DriveApi in order to create some folders and upload a text file with some data for a user.
I've tried implementing the quick-start guide from (link), but it has a few fundamental issues:
The api gets connected at onResume so the user will get prompted to give access to the app immediately after he opens the app which is confusing and scary.
If you deny or press the back button at the consent screen, the onResume method will get called again and the consent screen will be shown one more time, leading to an infinite loop.
I would rather like to connect the api when the user actually needs to store data so that will make more sense to the user. I tried doing it like this:
ResultCallback<DriveFolder.DriveFolderResult> folderCreatedCallback = new
ResultCallback<DriveFolder.DriveFolderResult>() {
#Override
public void onResult(#NonNull DriveFolder.DriveFolderResult result) {
clearCurrentAction();
if (!result.getStatus().isSuccess()) {
Log.e(TAG, "Error while trying to create the folder");
return;
}
Log.d(TAG, "Created a folder: " + result.getDriveFolder().getDriveId());
}
};
public DriveApiHelper(GoogleApiClient mGoogleApiClient) {
this.mGoogleApiClient = mGoogleApiClient;
}
public void createBackupsFolder() {
currentAction = DriveActions.CREATING_FOLDER;
if (mGoogleApiClient.isConnected()) {
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle("test").build();
Drive.DriveApi.getRootFolder(mGoogleApiClient).createFolder(
mGoogleApiClient, changeSet).setResultCallback(folderCreatedCallback);
} else {
mGoogleApiClient.connect();
}
}
and this is how my onResume and onConnected methods look like:
#Override
protected void onResume() {
super.onResume();
if (mGoogleApiClient == null) {
// Create the API client and bind it to an instance variable.
// We use this instance as the callback for connection and connection
// failures.
// Since no account name is passed, the user is prompted to choose.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mDriveHelper = new DriveApiHelper(mGoogleApiClient);
}
//Log.d(TAG, mDriveHelper.getCurrentAction() + "");
Log.d("test", "Connected " + mGoogleApiClient.isConnected());
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "API client connected.");
switch (mDriveHelper.getCurrentAction()) { //resume the last action
case CREATING_FOLDER:
mDriveHelper.createBackupsFolder();
break;
}
}
I was hoping that keeping a reference of what the user tried to do when the api was asked to connect, I can resume that action after the api successfully connected. This is the closest implementation I've got to fit my needs, but after actually clicking the 'Allow' button from the consent screen none of the api callbacks gets called (onConnected, onConnectionFailed).
I actually need to call the connect method one more time in order to get connected and also fire the onConnected successfully resuming the users' action.
Turns out that I forgot about overriding onActivityResult (it wasn't mentioned in the documentation at that time and I don't know if they included it now)
Just add:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == REQUEST_CODE_RESOLUTION) {
mGoogleApiClient.connect();
}
} else {
if (requestCode == REQUEST_CODE_RESOLUTION) {
mDriveHelper.dismissStatusDialog();
}
}
}