I'm signing up users using Email/Password and Phone methods.
Signing up procedure is as follows
Sign in user with PhoneAuthCredential > Link created user with EmailCredential from entered email and password > send Email verification > Database entry
public class Sign_Up_page extends AppCompatActivity {
private String TAG = "Sign_Up_page";
// UI Widgets.
private View sign_up_btn;
// Firebase
private FirebaseAuth firebaseAuth;
private DatabaseReference reference;
private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks;
private PhoneAuthProvider.ForceResendingToken mResendToken;
private FirebaseAuth.AuthStateListener authListener;
private UserPojo userPojo;
private String mVerificationId = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sign__up_page);
firebaseAuth = FirebaseAuth.getInstance();
authListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
if (firebaseAuth.getCurrentUser() == null) {
Toast.makeText(Sign_Up_page.this, "user is null", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(Sign_Up_page.this, "user not null", Toast.LENGTH_LONG).show();
}
}
};
mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(PhoneAuthCredential credential) {
signInWithPhoneAuthCredential(credential);
}
#Override
public void onVerificationFailed(FirebaseException e) {
}
#Override
public void onCodeSent(String verificationId,
PhoneAuthProvider.ForceResendingToken token) {
mResendToken = token;
}
};
}
#Override
public void onClick(View v) {
super.onClick(v);
if (v == sign_up_btn) {
firebaseAuth.fetchSignInMethodsForEmail(userEmail).addOnCompleteListener(new OnCompleteListener<SignInMethodQueryResult>() {
#Override
public void onComplete(#NonNull Task<SignInMethodQueryResult> task) {
if (task.isSuccessful()) {
SignInMethodQueryResult result = task.getResult();
List<String> signInMethods = result != null ? result.getSignInMethods() : null;
if (signInMethods != null && signInMethods.size() == 0) {
startPhoneNumberVerification(userPhone);
verifyPhoneDialog();
}
}
}
});
}
}
private void signInWithPhoneAuthCredential(final PhoneAuthCredential credential) {
firebaseAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
if (task.getResult() != null) {
if (task.getResult().getAdditionalUserInfo().isNewUser()) {
AuthCredential emailCredential = EmailAuthProvider.getCredential(userEmail, userPass);
Toast.makeText(Sign_Up_page.this, "Signedin with phone", Toast.LENGTH_LONG).show();
linkUserCredentials(emailCredential);
} else {
firebaseAuth.signOut();
Toast.makeText(THIS, "This Phone no. is already registered with different account", Toast.LENGTH_SHORT).show();
}
}
}
}
});
}
private void linkUserCredentials(final AuthCredential credential) {
firebaseAuth.getCurrentUser().linkWithCredential(credential)
.addOnCompleteListener(Sign_Up_page.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
if (task.getResult() != null) {
FirebaseUser user = task.getResult().getUser();
Toast.makeText(Sign_Up_page.this, "credential linked", Toast.LENGTH_LONG).show();
// null current user was causing the account to create in Firebase Auth
// but no entry in Database so here I'm using user instance returned on
// linkCredentialSuccess for furthur use instead of "firebaseAuth.getCurrentUser()" to prevent that issue
sendVerificationEmail(user);
}
} else {
firebaseAuth.getCurrentUser().delete();
}
}
});
}
private void sendVerificationEmail(final FirebaseUser createdUser) {
if (firebaseAuth.getCurrentUser() != null) {
firebaseAuth.getCurrentUser().sendEmailVerification()
.addOnCompleteListener(this, new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Toast.makeText(Sign_Up_page.this, "email verification Op complete", Toast.LENGTH_LONG).show();
createUser(emailDelivery, createdUser);
}
});
}
}
private void createUser(final boolean emailDelivery, final FirebaseUser createdUser) {
reference = FirebaseDatabase.getInstance().getReference("users");
Toast.makeText(Sign_Up_page.this, "Creating user", Toast.LENGTH_LONG).show();
userPojo = new UserPojo();
userPojo.setValues(...);
String uid = "";
if (createdUser != null) {
uid = createdUser.getUid();
}
if (firebaseAuth.getCurrentUser() == null) {
AuthCredential emailCredential = EmailAuthProvider.getCredential(userEmail, userPass);
if (createdUser != null) {
createdUser.reauthenticate(emailCredential).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(Sign_Up_page.this, "user reAuthenticated", Toast.LENGTH_LONG).show();
}
}
});
}
}
if (!uid.equals("")) {
UserProfileChangeRequest userProfile = new UserProfileChangeRequest.Builder()
.setDisplayName(userName).build();
createdUser.updateProfile(userProfile);
userPojo.setUid(uid);
final String path = "" + FirebaseDatabase.getInstance().getReference("users").child(uid);
reference.child(uid).setValue(userPojo).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
startActivity(new Intent(Sign_Up_page.this, Home_Screen.class));
} else {
createdUser.delete();
AlertDialog.Builder DbEntryFailDialog = new AlertDialog.Builder(Sign_Up_page.this);
DbEntryFailDialog.setTitle("Error")
.setMessage("Error" + task.getException().getMessage()
+ "\n\nentry url is " + path)
.setPositiveButton("Ok", null)
.show();
Toast.makeText(Sign_Up_page.this, "Error occurred creating account when Db entry fail, Please try again", Toast.LENGTH_LONG).show();
}
}
});
} else {
if (createdUser != null) {
createdUser.delete();
}
}
}
#Override
protected void onStart() {
super.onStart();
firebaseAuth.addAuthStateListener(authListener);
}
#Override
protected void onStop() {
super.onStop();
firebaseAuth.addAuthStateListener(authListener);
}
}
now the problem is in 1 out of 10 attempts firebaseAuth.getCurrentUser() becomes null after linking With email credentials
I've added authStateListener to track changes in user Authentication State
here is the screenshot
of steps
here are my DB write rules for users table
"users":{
"$uid":{
".write": "auth.uid != null && newData.exists()",
},
".indexOn": "role"
}
Now I can handle null user or DB failure, But I want to know and prevent what is causing this problem
I did something wrong or is this a firebase bug...?
Related
Firebase register code is given below. When I add username as a parameter, the method does not let me do it.
firebaseAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
//checking if success
if(task.isSuccessful()){
finish();
startActivity(new Intent(getApplicationContext(), MainActivity.class));
}else{
//display some message here
Toast.makeText(RegisterActivity.this,"Bir hata oldu",Toast.LENGTH_LONG).show();
}
progressDialog.dismiss();
}
});
you need to update user after creating it.
firebaseAuth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (!task.isSuccessful()) {
Toast.makeText(YourActivity.this, "An error occurred", Toast.LENGTH_SHORT).show();
} else {
addUserNameToUser(task.getResult().getUser());
}
}
)};
private void addUserNameToUser(User user){
String username = "username";
String email = user.getEmail();
String userId = user.getUid();
User user = new User(username, email);
firebaseDB.child("users").child(userId).setValue(user);
}
the variable firebaseDB should be created before. You can create in where you create firebaseAuth like so ;
firebaseDB = FirebaseDatabase.getInstance().getReference();
Update 1
using com.google.firebase:firebase-auth:11.6.2
public class MainActivity extends AppCompatActivity {
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
firebaseAuth.createUserWithEmailAndPassword("erginersoyy#gmail.com", "12345").addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (!task.isSuccessful()) {
Toast.makeText(MainActivity.this, "An error occurred", Toast.LENGTH_SHORT).show();
} else {
addUserNameToUser(task.getResult().getUser());
}
}
});
}
private void addUserNameToUser(FirebaseUser user) {
String username = "username";
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(username)
.setPhotoUri(Uri.parse("https://example.com/jane-q-user/profile.jpg"))
.build();
user.updateProfile(profileUpdates)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "User profile updated.");
}
}
});
}
}
you can also check this link
I'm making an Android project, and for starters I have been figuring out how signing up works. By the way, I used Firebase for this. Here's my code:
package com....
import...
public class MainActivity extends AppCompatActivity {
//VIEW AND WIDGETS
Button createUser, moveToLoginBtn;
EditText userEmailEdit, userPasswordEdit;
//FIREBASE AUTH FIELDS
FirebaseAuth nAuth;
FirebaseAuth.AuthStateListener nAuthlistener;
DatabaseReference mDatabaseRef, mUserCheckData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//ASSIGN ID
createUser = (Button) findViewById(R.id.createUserBtn);
moveToLoginBtn = (Button) findViewById(R.id.moveToLogin);
userEmailEdit = (EditText) findViewById(R.id.emailEditTextCreate);
userPasswordEdit = (EditText) findViewById(R.id.passEditTextCreate);
//ASSIGN INSTANCE
mDatabaseRef = FirebaseDatabase.getInstance().getReference();
mUserCheckData = FirebaseDatabase.getInstance().getReference().child("Users");
nAuth = FirebaseAuth.getInstance();
nAuthlistener = new FirebaseAuth.AuthStateListener(){
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
final String emailForVer = user.getEmail();
mUserCheckData.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
checkUserValidation(dataSnapshot, emailForVer);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
} else {
}
}
};
//ON CLICK LISTENER
createUser.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
final String userEmailString, userPassString;
userEmailString = userEmailEdit.getText().toString().trim();
userPassString = userPasswordEdit.getText().toString().trim();
if (!TextUtils.isEmpty(userEmailString) && !TextUtils.isEmpty(userPassString))
{
nAuth.createUserWithEmailAndPassword(userEmailString,userPassString).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful())
{
DatabaseReference mChildDatabase = mDatabaseRef.child("Users").push();
String key_user = mChildDatabase.getKey();
mChildDatabase.child("isVerified").setValue("unverified");
mChildDatabase.child("userKey").setValue(key_user);
mChildDatabase.child("emailUser").setValue(userEmailString);
mChildDatabase.child("passWordUser").setValue(userPassString);
Toast.makeText(MainActivity.this, "User Account Created!", Toast.LENGTH_LONG).show();
startActivity(new Intent(MainActivity.this, Profile.class));
}
else
{
Toast.makeText(MainActivity.this, "User Account Creation Fail", Toast.LENGTH_LONG).show();
startActivity(new Intent(MainActivity.this, MainActivity.class));
}
}
});
}
}
});
//MOVE TO LOGIN
moveToLoginBtn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
startActivity(new Intent(MainActivity.this, LoginActivity.class));
}
});
}
private void checkUserValidation(DataSnapshot dataSnapshot, String emailForVer) {
Iterator iterator = dataSnapshot.getChildren().iterator();
while (iterator.hasNext())
{
DataSnapshot dataUser = (DataSnapshot) iterator.next();
if(String.valueOf(dataUser.child("emailUser").getValue()).equals(emailForVer) && dataUser.child("emailUser") != null)
{
if(String.valueOf(dataUser.child("isVerified").getValue()).equals("unverified") && dataUser.child("isVerified") != null)
{
Intent in = new Intent(MainActivity.this, Profile.class);
in.putExtra("USER_KEY" , String.valueOf(dataUser.child("userKey").getValue()));
startActivity(in);
//in.putExtra("NAME_KEY" , String.valueOf(dataUser.child("nameKey").getValue()));
}else
{
startActivity(new Intent(MainActivity.this, Welcome.class));
}
}
}
}
#Override
protected void onStart() {
super.onStart();
nAuth.addAuthStateListener(nAuthlistener);
}
#Override
protected void onStop() {
super.onStop();
nAuth.removeAuthStateListener(nAuthlistener);
}
}
I think I have implemented my methods correctly. But it toasts:
User Account Creation Failed
Is my
checkUseValidation() method wrong? Any kind of help is appreciated.
Also please pay attention to my:
public void onComplete
method, I have set it right I think. I don't know why the data isn't getting saved to the firebase database. Or why is the task unsuccesful as show in line:
if (task.isSuccessful())
Thank you very much.
First, you should change the toast, in your fail condition, to
Toast.makeText(MainActivity.this, task.getException().getMessage(), Toast.LENGTH_LONG).show();
So that you get what wrong in the task.
But before that did you enable Email/Password in the console????
See Sign up new users from url: https://firebase.google.com/docs/auth/android/start/?authuser=0
If task.isSuccessful() is false.You can add this to get error
Log.w(TAG, "createUserWithEmail:failure",task.getException());
Update you code as:
createUser.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
final String userEmailString, userPassString;
userEmailString = userEmailEdit.getText().toString().trim();
userPassString = userPasswordEdit.getText().toString().trim();
if (!TextUtils.isEmpty(userEmailString) && !TextUtils.isEmpty(userPassString))
{
nAuth.createUserWithEmailAndPassword(userEmailString,userPassString).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful())
{
DatabaseReference mChildDatabase = mDatabaseRef.child("Users").push();
String key_user = mChildDatabase.getKey();
mChildDatabase.child("isVerified").setValue("unverified");
mChildDatabase.child("userKey").setValue(key_user);
mChildDatabase.child("emailUser").setValue(userEmailString);
mChildDatabase.child("passWordUser").setValue(userPassString);
Toast.makeText(MainActivity.this, "User Account Created!", Toast.LENGTH_LONG).show();
startActivity(new Intent(MainActivity.this, Profile.class));
}
else
{
Log.w("TAG", "createUserWithEmail:failure",task.getException());
Toast.makeText(MainActivity.this, "User Account Creation Fail", Toast.LENGTH_LONG).show();
startActivity(new Intent(MainActivity.this, MainActivity.class));
}
}
});
}
}
});
You should see warning in logcat:
In my application, I have two users--Event Member and Client--they have separate user login and registration. If a client log in he will go to the the client activity; if an event member will log in he will go to the event member activity. How will I make sure that the email is a client or an event member?
Below image shows my firebase structure:
Here is my code:
SignupClient.java
signupClient.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String cemail = clie_email.getText().toString().trim();
final String cpassword = clie_password.getText().toString().trim();
String ccpassword = clie_cpassword.getText().toString().trim();
final String cfname = clie_firstname.getText().toString().trim();
final String clname = clie_lastname.getText().toString().trim();
final String cbday = clie_birthday.getText().toString().trim();
final String ccountry = clie_country.getSelectedItem().toString();
final String cmobile = clie_mobile.getText().toString().trim();
auth.createUserWithEmailAndPassword(cemail, cpassword)
.addOnCompleteListener(_5_SignupClient.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Toast.makeText(_5_SignupClient.this, "createUserWithEmail: onComplete" + task.isSuccessful(), Toast.LENGTH_LONG).show();
if (!task.isSuccessful()){
Toast.makeText(_5_SignupClient.this, "Authentication Failed" + task.getException(),
Toast.LENGTH_LONG).show();
}
else {
AccountInfo accountInfo = new AccountInfo(cfname, clname, cemail, cpassword, cbday, ccountry, cmobile);
mDatabaseReference.child("client").push().setValue(accountInfo);
startActivity(new Intent(_5_SignupClient.this, _7_ViewClient.class));
finish();
}
}
});
}
});
LoginClient.java
loginClient.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String clie_unameemail = clie_emailuname.getText().toString();
final String clie_pass = clie_password.getText().toString();
if(TextUtils.isEmpty(clie_unameemail)){
Toast.makeText(getApplicationContext(), "Field cannot be empty", Toast.LENGTH_LONG).show();
return;
}
if(TextUtils.isEmpty(clie_pass)){
Toast.makeText(getApplicationContext(), "Field cannot be empty", Toast.LENGTH_LONG).show();
return;
}
auth.signInWithEmailAndPassword(clie_unameemail, clie_pass)
.addOnCompleteListener(_3_LoginClient.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
ref = FirebaseDatabase.getInstance().getReference().child("client");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot snapshot : dataSnapshot.getChildren()){
if(FirebaseAuth.getInstance().getCurrentUser().getUid().equals(snapshot.getKey())){
startActivity(new Intent(_3_LoginClient.this, _7_ViewClient.class));
}
}
// startActivity(new Intent(_3_LoginClient.this, Normal_memberActivity.class));
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
} else {
// User is signed out
}
// ...
}
};
if (!task.isSuccessful()) {
// there was an error
if (clie_pass.length() < 8) {
clie_password.setError(getString(R.string.minimum_password));
} else {
Toast.makeText(_3_LoginClient.this, getString(R.string.auth_failed), Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(_3_LoginClient.this, "Successfully Registered", Toast.LENGTH_LONG).show();
Intent intent = new Intent(_3_LoginClient.this, _7_ViewClient.class);
startActivity(intent);
finish();
}
}
});
}
});
I hope you could help me. Thank you!
On your db there should be one more field like we say it USER_TYPE. While registering the user send its USER_TYPE. suppose if you are registering a user as a CLIENT then inser db value USER_TYPE="CLIENT" and if its as an Event member registration then inser db value USER_TYPE="EVENT" and now once you logged in check its USER_TYPE and redirect him based upon his USER_TYPE
Facebook logs in correctly. In the Firebase console, I can see the user has logged. However, I cannot access any of the user's info.
I am getting below error log in LogCat:
signInWithFacebook:{AccessToken token:ACCESS_TOKEN_REMOVED
permissions:[public_profile, contact_email, user_friends, email]}
Afterwards, I also receive a FirebaseError: Permission denied in the LogCat and as a toast inside the app.
Following this tutorial, I have made a project that integrates Facebook and Firebase. I've tried copy and pasting the source code, and replacing the necessary lines (such as Facebook ID and Firebase URL) but it isn't working for me.
here is the specific void
private void signInWithFacebook(AccessToken token) {
Log.d(TAG, "signInWithFacebook:" + token.getToken());
showProgressDialog();
AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Log.w(TAG, "signInWithCredential", task.getException());
Toast.makeText(LoginActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}else{
String uid=task.getResult().getUser().getUid();
String name=task.getResult().getUser().getDisplayName();
String email=task.getResult().getUser().getEmail();
String image=task.getResult().getUser().getPhotoUrl().toString();
//Create a new User and Save it in Firebase database
User user = new User(uid,name,null,email,name);
mRef.child(uid).setValue(user);
Log.d(TAG, uid);
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.putExtra("user_id",uid);
intent.putExtra("profile_picture",image);
startActivity(intent);
finish();
}
hideProgressDialog();
}
});
}
here is the full code
public class LoginActivity extends AppCompatActivity {
private static final String TAG = "AndroidBash";
public User user;
private EditText email;
private EditText password;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private ProgressDialog mProgressDialog;
private DatabaseReference mDatabase;
//Add YOUR Firebase Reference URL instead of the following URL
private Firebase mRef=new Firebase("https://firebase.firebaseio.com");
//FaceBook callbackManager
private CallbackManager callbackManager;
//
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mDatabase = FirebaseDatabase.getInstance().getReference();
mAuth = FirebaseAuth.getInstance();
FirebaseUser mUser = mAuth.getCurrentUser();
if (mUser != null) {
// User is signed in
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
String uid = mAuth.getCurrentUser().getUid();
String image=mAuth.getCurrentUser().getPhotoUrl().toString();
intent.putExtra("user_id", uid);
if(image!=null || image!=""){
intent.putExtra("profile_picture",image);
}
startActivity(intent);
finish();
Log.d(TAG, "onAuthStateChanged:signed_in:" + mUser.getUid());
}
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser mUser = firebaseAuth.getCurrentUser();
if (mUser != null) {
// User is signed in
Log.d(TAG, "onAuthStateChanged:signed_in:" + mUser.getUid());
} else {
// User is signed out
Log.d(TAG, "onAuthStateChanged:signed_out");
}
}
};
//FaceBook
FacebookSdk.sdkInitialize(getApplicationContext());
callbackManager = CallbackManager.Factory.create();
LoginButton loginButton = (LoginButton) findViewById(R.id.button_facebook_login);
loginButton.setReadPermissions("email", "public_profile");
loginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
#Override
public void onSuccess(LoginResult loginResult) {
Log.d(TAG, "facebook:onSuccess:" + loginResult);
signInWithFacebook(loginResult.getAccessToken());
}
#Override
public void onCancel() {
Log.d(TAG, "facebook:onCancel");
}
#Override
public void onError(FacebookException error) {
Log.d(TAG, "facebook:onError", error);
}
});
//
}
#Override
protected void onStart() {
super.onStart();
email = (EditText) findViewById(R.id.edit_text_email_id);
password = (EditText) findViewById(R.id.edit_text_password);
mAuth.addAuthStateListener(mAuthListener);
}
#Override
public void onStop() {
super.onStop();
if (mAuthListener != null) {
mAuth.removeAuthStateListener(mAuthListener);
}
}
//FaceBook
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
callbackManager.onActivityResult(requestCode, resultCode, data);
}
//
protected void setUpUser() {
user = new User();
user.setEmail(email.getText().toString());
user.setPassword(password.getText().toString());
}
public void onSignUpClicked(View view) {
Intent intent = new Intent(this, SignUpActivity.class);
startActivity(intent);
}
public void onLoginClicked(View view) {
setUpUser();
signIn(email.getText().toString(), password.getText().toString());
}
private void signIn(String email, String password) {
Log.d(TAG, "signIn:" + email);
if (!validateForm()) {
return;
}
showProgressDialog();
mAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.d(TAG, "signInWithEmail:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Log.w(TAG, "signInWithEmail", task.getException());
Toast.makeText(LoginActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
} else {
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
String uid = mAuth.getCurrentUser().getUid();
intent.putExtra("user_id", uid);
startActivity(intent);
finish();
}
hideProgressDialog();
}
});
//
}
private boolean validateForm() {
boolean valid = true;
String userEmail = email.getText().toString();
if (TextUtils.isEmpty(userEmail)) {
email.setError("Required.");
valid = false;
} else {
email.setError(null);
}
String userPassword = password.getText().toString();
if (TextUtils.isEmpty(userPassword)) {
password.setError("Required.");
valid = false;
} else {
password.setError(null);
}
return valid;
}
private void signInWithFacebook(AccessToken token) {
Log.d(TAG, "signInWithFacebook:" + token.getToken());
showProgressDialog();
AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Log.w(TAG, "signInWithCredential", task.getException());
Toast.makeText(LoginActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}else{
String uid=task.getResult().getUser().getUid();
String name=task.getResult().getUser().getDisplayName();
String email=task.getResult().getUser().getEmail();
String image=task.getResult().getUser().getPhotoUrl().toString();
//Create a new User and Save it in Firebase database
User user = new User(uid,name,null,email,name);
mRef.child(uid).setValue(user);
Log.d(TAG, uid);
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.putExtra("user_id",uid);
intent.putExtra("profile_picture",image);
startActivity(intent);
finish();
}
hideProgressDialog();
}
});
}
public void showProgressDialog() {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage(getString(R.string.loading));
mProgressDialog.setIndeterminate(true);
}
mProgressDialog.show();
}
public void hideProgressDialog() {
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
}
}
When I use signInWithEmailAndPassword() to login the onAuthStateChanged() always fire twice.
I'm very sure that the listening is only added once to firebaseAuth, and I have the code inonStop()` to remove the listener after that.
Anyone know how to solve this?
My code:
public class SignInActivity extends BaseActivity implements
View.OnClickListener,
GoogleApiClient.OnConnectionFailedListener{
private static final String PREF_KEY_USER_EMAIL = "User_Email";
private static final int RC_SIGN_IN = 1111;
private FirebaseAuth firebaseAuth;
private FirebaseAuth.AuthStateListener authStateListener;
private DatabaseReference firebaseDbReference;
private TextView fieldEmail;
private TextView fieldPassword;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sign_in);
getSupportActionBar().hide();
firebaseAuth = FirebaseAuth.getInstance();
firebaseDbReference = FirebaseDatabase.getInstance().getReference();
fieldEmail = (TextView) findViewById(R.id.field_email);
fieldPassword = (TextView) findViewById(R.id.field_password);
String userSavedEmail = getPreferences(MODE_PRIVATE).getString(PREF_KEY_USER_EMAIL, "");
if(userSavedEmail != null) {
fieldEmail.setText(userSavedEmail);
fieldPassword.requestFocus();
}
TextView linkForgotPassword;
Button buttonLogin;
linkForgotPassword = (TextView) findViewById(R.id.link_forgotPassword);
buttonLogin = (Button) findViewById(R.id.button_Login);
buttonSignUp = (Button) findViewById(R.id.button_signUp);
if (linkForgotPassword != null) {
linkForgotPassword.setOnClickListener(this);
}
if (buttonLogin != null) {
buttonLogin.setOnClickListener(this);
}
if (buttonSignUp != null) {
buttonSignUp.setOnClickListener(this);
}
authStateListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
if(firebaseAuth.getCurrentUser() != null) {
onAuthSuccess(firebaseAuth.getCurrentUser());
}
}
};
}
#Override
protected void onStart() {
super.onStart();
firebaseAuth.addAuthStateListener(authStateListener);
}
#Override
protected void onStop() {
super.onStop();
if (authStateListener != null) {
firebaseAuth.removeAuthStateListener(authStateListener);
}
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.link_forgotPassword:
forgotPassword();
break;
case R.id.button_Login:
emailLogin();
break;
case R.id.button_signUp:
emailSignUp();
break;
}
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Toast.makeText(this, "Google Play Services error.", Toast.LENGTH_SHORT).show();
}
private void forgotPassword(){
FirebaseAuth auth = FirebaseAuth.getInstance();
String emailAddress = fieldEmail.getText().toString();
if(TextUtils.isEmpty(emailAddress)){
Toast.makeText(SignInActivity.this, R.string.msg_EnterEmail,
Toast.LENGTH_SHORT).show();
}
else {
showProgressDialog();
auth.sendPasswordResetEmail(emailAddress)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
hideProgressDialog();
if (task.isSuccessful()) {
Toast.makeText(SignInActivity.this, R.string.msg_ResetPasswordEmailSent,
Toast.LENGTH_LONG).show();
}
}
});
}
}
private void emailLogin(){
if (!validateForm()) {
return;
}
showProgressDialog();
String email = fieldEmail.getText().toString();
String password = fieldPassword.getText().toString();
firebaseAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
hideProgressDialog();
if (!task.isSuccessful()) {
Toast.makeText(SignInActivity.this, R.string.msg_EmailLoginFailed,
Toast.LENGTH_SHORT).show();
}
else {
// Save the email
getPreferences(MODE_PRIVATE).edit()
.putString(PREF_KEY_USER_EMAIL, fieldEmail.getText().toString())
.apply();
}
}
});
}
private void emailSignUp(){
if (!validateForm()) {
return;
}
showProgressDialog();
String email = fieldEmail.getText().toString();
String password = fieldPassword.getText().toString();
firebaseAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
hideProgressDialog();
if (task.isSuccessful()) {
FirebaseUser user = task.getResult().getUser();
String displayName = displayNameFromEmail(user.getEmail());
// Update profile display name.
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName("Jane Q. User")
.build();
user.updateProfile(profileUpdates);
} else {
Toast.makeText(SignInActivity.this, R.string.msg_EmailSignUpFailed,
Toast.LENGTH_SHORT).show();
}
}
});
}
private void onAuthSuccess(FirebaseUser user) {
// Write new user
writeNewUser(user.getUid(),
user.getDisplayName(),
user.getEmail(),
user.getPhotoUrl());
// Go to MainActivity
startActivity(new Intent(this.getApplicationContext(), MainActivity.class));
finish();
}
private void writeNewUser(String userId, String displayName, String email, android.net.Uri photoUrl) {
User user = new User(displayName, email);
if(photoUrl != null){
user.setPhotoUrl(photoUrl.toString());
}
firebaseDbReference.child("users").child(userId).setValue(user);
}
private String displayNameFromEmail(String email) {
if (email.contains("#")) {
return email.split("#")[0];
} else {
return email;
}
}
private boolean validateForm() {
boolean result = true;
if (TextUtils.isEmpty(fieldEmail.getText().toString())) {
fieldEmail.setError("Required");
result = false;
} else {
fieldEmail.setError(null);
}
if (TextUtils.isEmpty(fieldPassword.getText().toString())) {
fieldPassword.setError("Required");
result = false;
} else {
fieldPassword.setError(null);
}
return result;
}
}
It does fire twice and I think this is a bug that Firebase guys should fix (looking at you Frank hehehe ).
The only thing I can think you can do right now is to add a flag like this.
private boolean flag = true;
...
authStateListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
if(firebaseAuth.getCurrentUser() != null && flag) {
onAuthSuccess(firebaseAuth.getCurrentUser());
flag=false;
}
}
};
Far from ideal, but will work for now.
Code still fires twice, we accept the first one and deny the second one with our flag, this way if Firebase guys fix it and suddenly the listener runs once, our code still works.
Maybe it is intended for the listener to run twice, hopefully we will have some answers from Frank's cross-post
The double call is due a registration call. Not only that, onAuthStateChanged is going to be called many times in many different states, with no possibility of knowing which state it is.
Documentation says:
onAuthStateChanged(FirebaseAuth auth)
This method gets invoked in the UI thread on changes in the authentication state:
Right after the listener has been registered
When a user is signed in
When the current user is signed out
When the current user changes
When there is a change in the current user's token
Here some tips to discover the current state:
Registration call: skip the first call with a flag.
User signed in: user from parameter is != null.
User signed out: user from parameter is == null.
Current user changes: user from parameter is != null and last user id is != user id from parameter
User token refresh: user from parameter is != null and last user id is == user id from parameter
This listener is a mess and very bugprone. Firebase team should look into it.
Far from ideal too, but is more accurate solution.
private String authFlag = "";
...
authStateListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
if (firebaseAuth.getCurrentUser() == null) {
if (authFlag != null) {
authFlag = null;
subscriber.onNext(null);
}
} else {
String uid = firebaseAuth.getCurrentUser().getUid();
if (authFlag == null || authFlag.isEmpty() || !authFlag.equals(uid)) {
authFlag = uid;
subscriber.onNext(firebaseAuth.getCurrentUser());
}
}
}
I suppose this might be a bad idea, but...
let timeout: NodeJS.Timeout
const unsubscribe = auth().onUserChanged((changedUser) => {
clearTimeout(timeout)
timeout = setTimeout(() => {
if (changedUser) signIn(changedUser)
else signOut()
}, 300)
})