I am trying to finish up the implementation of a login screen for my app. I have a REST API backend that verifies the username + token and returns the userId of the person logging into the app.
I want to store the last userId from the user who has logged into the app. I plan to use Shared preferences for this.
Based on the last stored userId, i plan to execute either going to the main activity (if this user has logged in previously, but logged out after a while and is re-logging in), or executing an AsynkTask to syncronise some data from the backend (if it is a new user). Here is my logic, which seems to not be working properly.
It is switching directly to the MainSyncTask, even if i'm logging in with the last username (userId is the same, received from the API), and savedUserId.equals(currentUserId) should return true and execute the Intent. last userId is properly store in the sharedpreferences db, check with Stecho .
String userId = getUserIdFromAPIResponse();
sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
private void checkIdAndGoToActivity() {
final String PREF_VERSION_CODE_KEY = "user_id";
// Get current version code
String currentUserId = userId;
// Get saved version code
String savedUserId = sharedpreferences.getString(PREF_VERSION_CODE_KEY, "");
if (savedUserId.equals(currentUserId)) {
Log.e(TAG, "Current User Logged in");
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
/* destroys activity , prevents user from going back to previous MainActivity after login out */
finish();
} else if (!savedUserId.equals(currentUserId)) {
Log.e(TAG, "New user logged in");
MainSyncTask mainSyncTask = new MainSyncTask(LoginActivity.this, LoginActivity.this, userEmail, userPassword);
mainSyncTask.execute();
SyncEventReceiver.setupAlarm(getApplicationContext());
}
// Update the shared preferences with the current version code
sharedpreferences.edit().putString(PREF_VERSION_CODE_KEY, currentUserId).apply();
}
Related
Register Button in Register Acvtivity
public void registerBtnClicked(View view){
String email = binding.userEmailEditText.getText().toString();
String password = binding.userPasswordEditText.getText().toString();
String userNameData = binding.usernameEditText.getText().toString();
user = new Users(userNameData,email,password);
db = FirebaseDatabase.getInstance();
databaseReference = db.getReference(Users.class.getSimpleName());
databaseReference.push().setValue(user);
if(email.equals("") || password.equals("")){
Toast.makeText(this, "Enter email and password", Toast.LENGTH_LONG).show();
}else{
auth.createUserWithEmailAndPassword(email,password).addOnSuccessListener(new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
Intent intent = new Intent(RegisterPage.this, MainActivity.class);
startActivity(intent);
finish();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(RegisterPage.this, e.getLocalizedMessage(),Toast.LENGTH_LONG).show();
}
});
}
}
I created a real time database.But I couldn't figure out how to show username in navigation header section. Can you help me?
If I understand correctly, the firebaseUser is null when you're trying to read the display name from it. This is actually a common scenario, as the user's sign-in session is managed by Firebase in the background, and the current user may change at any time.
The simple fix is to check whether there is a current user before accessing their display name, which you can do with:
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
if (firebaseUser != null) {
navUserEmail.setText(firebaseUser.getEmail());
navUserName.setText(firebaseUser.getDisplayName());
}
Note though that the display name is an optional property of the user profile, so it can indeed be null. If you want to display nothing in that case, you can do:
String displayName = firebaseUser.getDisplayName();
navUserName.setText(displayName != null ? displayName : "");
Even if you've set the display name of a user, it may take up to an hour until that is updated for all connected clients, as they all cache the user profile. And since such updates happen in the background... 👇
To correctly handle all auth state changes, you'll want to use an auth state listener, as shown in this article: https://stackoverflow.com/collectives/google-cloud/articles/68104924/listen-for-authentication-state-in-android
I have an Android app where the user registers for an account with their email, password, and displayName. I want to send a welcome email to the user after they create an account. This is how I create my account and set their display name.
// This happens in Android (RegisterActivity.java) where I create user's account
FirebaseAuth auth = FirebaseAuth.getInstance();
auth.createUserWithEmailAndPassword(email, password)
.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
FirebaseUser user = authResult.getUser();
user.updateProfile(new UserProfileChangeRequest.Builder()
.setDisplayName(name).build());
}
});
Once the user's account is created, a firebase function is triggered. Below is my code:
// This happens in Firebase Cloud Functions (index.js)
exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => {
// send welcome email here
console.log(user.displayName) // displayName is null here
});
I believe that the firebase function gets triggered as soon as the account creation is successful, and I set user's displayname after the account is created and so displayName is null in the function. What can I do to solve the issue? I don't want to send an email to the user without their name in the email.
tl;dr: displayName is being called before is being set.
The onCreate function runs after the front end finishes createUserWithEmailAndPassword but before the displayName is set.
Either you run an onCall function after you update the displayName or as suggested on the firebase github thread on this issue you can add a profile parameter to the createUserWithEmailAndPassword so that we create new accounts with a pre-populated profile.
I want to generate and store token everytime users login. I tried for my code below, but it always generate same token when I login with another account.
mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(LoginActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
AlertDialog.dismiss();
if (!task.isSuccessful()) {
if (password.length() < 6) {
new SweetAlertDialog(LoginActivity.this, SweetAlertDialog.ERROR_TYPE)
.setTitleText("Oops...")
.setContentText("Enter minimum 6 charachters !! ")
.show();
} else {
passwordInput.setText("");
new SweetAlertDialog(LoginActivity.this, SweetAlertDialog.ERROR_TYPE)
.setTitleText("Oops...")
.setContentText("Authentication failed !!")
.show();
}
} else {
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
FirebaseUser users = FirebaseAuth.getInstance().getCurrentUser();
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference("users/"+ users.getUid());
String token = FirebaseInstanceId.getInstance().getToken();
Log.e("tokenid",""+token);
mDatabase.child("token_id").setValue(token);
finish();
}
}
});
}
});
please help, thanks..
When using the following line of code:
String token = FirebaseInstanceId.getInstance().getToken();
You are getting the Firebase Instance ID token, which is also known as FCM token, on the client side. You need to know that in Firebase there two different tokens:
A FCM Token/Instance ID token that identifies an installation of a specific application on a specific user device. It doesn't identify in any way a particular user.
An Auth ID token identifies a specific user of a specific application. It doesn't identify in any way a particular device.
The two tokens are quite different and serve different purposes. Please see the official documentation for Android regarding on how to retrieve ID tokens on clients.
The identity of the user is remembered indefinitely (or until you sign out). But their credentials (or rather, whether their token is still valid) are re-checked every hour.
FCM generates a registration token for the client app instance, hence It may happen that you'll get the same token for different users in your app. You can use forceRefresh to generate a new token every time. Register new token everytime user logins to any device and save it in DB and update with a new token on new login this way you will have a new token for each user on every login (If this fits your requirement)
Here is a good answer to understand how it works Firebase FCM force onTokenRefresh() to be called
Use UUID.randomUUID().toString()
You can read more here.
java docs - and here =)
I'm making an app for my final project in school..
I've made an Login page and inside the login page I need to retrieve a data from a specific column named Permissions and then check the permission to declare to which next Activity the app will take the user..
In simple words I need something like this:
public void login(View view){ //button
if(Permission == admin){ // get the permission from the user that is logging in.. lets say from username = "Bob123"
//do something..
}
}
A possible solution is to:
create an instance of BackendlessUser in your application class:
public static BackendlessUser user;
If you have added the permission column to the Users table and you have made the email an identity column in the schema you can use the following code to retrieve a BackendlessUser object and direct the user to the correct Activity based on his permission in the Users table:
public void login(String emailToLogin){
DataQueryBuilder dataQueryBuilder = DataQueryBuilder.create();
dataQueryBuilder.setWhereClause("email = " + "'" + emailToLogin + "'");
Backendless.Data.of(BackendlessUser.class).find(dataQueryBuilder,
new AsyncCallback<List<BackendlessUser>>() {
#Override
public void handleResponse(List<BackendlessUser> response) {
if (response.get(0).getProperty("permission").equals("permissionOne")) {
Intent intent = new Intent(LoginActivity.this, permissionOneActivity.class);
startActivity(intent);
}//end if
else if (response.get(0).getProperty("permission").equals("permissionTwo")) {
Intent intent = new Intent(LoginActivity.this, permissionTwoActivity.class);
startActivity(intent);
}//end else if
}//end handleResponse
#Override
public void handleFault(BackendlessFault fault) {
//add error handling here...
}//end handleFault
});}
In the code mentioned below, the response.get(0) will always return the correct user since we are getting the BackendlessUser object based on his email that we set to be a Unique Identifier.
"permissionOne" and "permissionTwo" is whatever you have called your permissions, eg. "permissionOne" takes you to the admin Activity and "permissionTwo" takes you to the clients Activity.
response.get(0).getProperty("permission").equals("permissionOne")
This code myUserObject.getProperty("myColumnName"); retrieves any property you want from the Users table in Backendless
Hope this helps somebody.
In an android app, which uses Parse, the login flow is like this...
We have our own logic to see if the user has entered the correct credentials. Once we verify that, signUpOrLoginOnParse() is called. Parse is used just to store data and handle sessions locally. Users can not access the api without the token.
private void signUpOrLogin(final String username, final String token) {
ParseUser user = new ParseUser();
user.setUsername(username);
user.setPassword(username);
user.signUpInBackground(new SignUpCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
// sign up success. ParseUser.getCurrentUser() populated
saveTokenToCloud(token);
} else if ("condition to check if the user already exists") {
// existing user, login.
ParseUser.logInInBackground(username, username, new LogInCallback() {
#Override
public void done(ParseUser parseUser, ParseException e) {
// login was successful, ParseUser.getCurrentUser() populated
saveTokenToCloud(token);
}
});
} else {
showProgress(false);
e.printStackTrace();
}
}
});
}
private void saveTokenToCloud(String token) {
// saving token to cloud
ParseUser user = ParseUser.getCurrentUser();
user.put("token", token); // THIS IS WHERE I GET NULL POINTER EXCEPTION
user.saveEventually();
// link installation to user.
ParseInstallation parseInstallation = ParseInstallation.getCurrentInstallation();
parseInstallation.put("user", user);
parseInstallation.saveEventually();
// Starting next activity
Intent i = new Intent(this, NextActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
finish();
}
All good when I first run the app. Once, logout button is pressed (contains - Parse.logoutInBackground()), it shows the LoginActivity (current one). When trying to log in, everything succeeds but I get a NullPointerException at line 3 of saveTokenToCloud().
It says - trying to invoke virtual method .put() over a null object reference.
But, isn't Parse.currentUser() already populated since this method is called from callback of methods that do that ?
It works after restarting the app. But then the same continues if logout is pressed.
After calling logoutInBackground , future calls to getCurrentUser() will return null.
You will need to initialize the user again.
signUpInBackground will create a new ParseUser on the server, and also persist the session on disk so that you can access the user using ParseUser.getCurrentUser().
However i am not sure you should be calling it every single time you log in.
Instead of calling the getCurrentuser inside the saveToken method you can pass the user to the saveTokenMethod from the done callback parameter.
Separate you logic in distinct methods for sign up and logIn. I suggest you check before calling signUp, and not abusing it every time you want to login