I'm asking this because I want display a message to the user only once:
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
val isUserNew = authResult.additionalUserInfo!!.isNewUser!!
if(isUserNew) {
Toast.makeText(baseContext, "Hello", Toast.LENGTH_SHORT).show()
}
} else {
Log.d(TAG, task.exception!!.message!!)
}
}
So can isUserNew be false? Or it's always true since createUserWithEmailAndPassword is only called once? And I don't even need to check that.
AdditionalUserInfo is also used in other auth methods so, isUserNew is there for convenience.
If user deleted the app and signed in again, or logged in via Google on second device for example, isUserNew will be false. But in this particular case it will always be true.
Related
in my application first i authenticate user email and then i am verifying user email i have set dialog activity to inform user to check email and verify email i have close button in dialog activity if user click on it dialog will be dismissed
i have implemented override fun onResume() method first activity and in this method i check user have verified email or not by auth.getInstance().currentUser.isEmailVerified
i ran this app i got email and successfully verify but in onResume() method auth.getInstance().currentUser.isEmailVerified returns false
auth.createUserWithEmailAndPassword(binding.email.text.toString(),binding.password.text.toString()).addOnCompleteListener { task->
Log.d("userAuthenticated","yes")
if(task.isSuccessful)
{
val currUser=auth.currentUser
Log.d("TaskIsSuccessful","Yes")
currUser!!.sendEmailVerification().addOnSuccessListener {
Log.d("Emailissent","yes")
uniqueFirebaseAuthId=task.result!!.user!!.uid.toString()
val sentEmailbinding=ActivityEmailVarificationSignUpBinding.inflate(layoutInflater)
val dialog = Dialog(this#SignUp)
dialog.setContentView(sentEmailbinding.root)
dialog.setCanceledOnTouchOutside(true)
dialog.setCancelable(false)
sentEmailbinding.closebtn.setOnClickListener{
dialog.dismiss()
Log.d("Iamback","Yes")
}
dialog.show()
Log.d("verified",currUser.isEmailVerified.toString())
Log.d("Dialogshown","yes")
Log.d("uniqueFirebaseAuthValue","${uniqueFirebaseAuthId} ")
}.addOnFailureListener {
Log.d("emailauthverification",it.toString())
}
}
task.addOnFailureListener {
Log.d("TaskFail",it.toString())
}
onResume() function
override fun onResume() {
super.onResume()
val userEnterdName=binding.uiqueusername.toString()
val currUser=FirebaseAuth.getInstance().currentUser
if(currUser!!.isEmailVerified) {
val verifiedUser=UseratFirebase(userEnterdName,binding.email.toString(),binding.password.toString())
val uniqueAuthId=uniqueFirebaseAuthId.toString()
database.reference.child("users").child(uniqueAuthId).setValue(verifiedUser).addOnSuccessListener {
val intent=Intent(this#SignUp,SignIn::class.java)
intent.putExtra("Email",binding.email.text.toString())
intent.putExtra("password",binding.email.toString())
}.addOnFailureListener {
Toast.makeText(this#SignUp,"Error occured while stroting data",Toast.LENGTH_LONG).show()
}
}
else
{
Log.d("Curruser", "${currUser.toString() } -> ${currUser.isEmailVerified}")
Toast.makeText(this#SignUp,"Please verify Your Account",Toast.LENGTH_LONG).show()
}
}
Verifying the user's email address happens in another application (you click the link in your mail app, and then it verifies that action in the browser), so you app is not aware of it right away.
The information is encoded in the user's ID token, which is refreshed automatically every hour, or when the user signs in again. So you can either wait/force the user to sign in again, or you can tell the SDK to refresh the token by calling user.getIdToken(true) or user.reload().
I wonder if someone may be able to assist with my struggles, I apologise as I’m new to Kotlin.
After implementing facebook login following the parse-sdk-android documentation I have realised that onActivityResult() is deprecated (though it still works for the timebeing).
I am trying to adapt my code to work with the new Activity Result API’s (I saw a previous suggestion to use registerForActivityResult) however, my issue is that we are only calling the method ParseFacebookUtils.logInWithReadPermissionsInBackground in the code and the activity being called is nested within this method.
I attempted to use registerForActivityResult to start the activity containing this method however it will only capture the result of the activity started and not that of the nested activity within ParseFacebookUtils.logInWithReadPermissionsInBackground (which is the expected behaviour). Online searches have not brought back any results for a way to implement this for parse-sdk-android.
So my question is whether there is a way to capture the result of the nested activity using just the method ? without being able to change the nested code.
My code for logging in currently is as below:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
loginFacebook()
}
private fun loginFacebook(){
val permissions: List<String> = listOf("public_profile", "email")
ParseFacebookUtils.logInWithReadPermissionsInBackground(this,permissions) { user: ParseUser?, err: ParseException? ->
when {
err != null -> {
Log.e("FacebookLoginExample", "done: ", err)
Toast.makeText(this, err.message, Toast.LENGTH_LONG).show()
}
user == null -> {
Toast.makeText(this, "The user cancelled the Facebook login.", Toast.LENGTH_LONG).show()
Log.d("FacebookLoginExample", "Uh oh. The user cancelled the Facebook login.")
}
user.isNew -> {
Toast.makeText(this, "User signed up and logged in through Facebook.", Toast.LENGTH_LONG).show()
Log.d("FacebookLoginExample", "User signed up and logged in through Facebook!")
getUserDetailFromFB()
}
else -> {
Toast.makeText(this, "User logged in through Facebook.", Toast.LENGTH_LONG).show()
Log.d("FacebookLoginExample", "User logged in through Facebook!")
showAlert("Oh, you!", "Welcome back!")
}
}
}
}
For an integration test I want to do some tests with a very newly created user account. For that I create a Firebase user in my test case function like that:
#Test
fun registerAndSigningInWithVeryNewUser() {
val auth = Firebase.auth
auth.createUserWithEmailAndPassword(strEmail, strPassword)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "createUserWithEmail:success")
// doing some test stuff
} else {
// If sign in fails
Log.w(TAG, "createUserWithEmail:failure", task.exception)
assert(false)
}
}
}
The new user account is created correctly. I can verify that in the Firebase Authentication dashboard. But the task in addOnCompleteListener is never called. I could not understand why.
Update: If I use the debugger and go step by step through the test function, the listener is called. So I think I need some idle code to wait for the async database call
Any hints?
The problem was, that the called function is an asynchronous call to a remote server (of cause).
The test case ends before the response could arrive. So I added an ugly Thread.sleep(10000).
#Test
fun registerAndSigningInWithVeryNewUser() {
val auth = Firebase.auth
auth.createUserWithEmailAndPassword(strEmail, strPassword)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "createUserWithEmail:success")
// doing some test stuff
} else {
// If sign in fails
Log.w(TAG, "createUserWithEmail:failure", task.exception)
assert(false)
}
}
Thread.sleep(10000)
}
But using Thread.sleep(...) is not always good: https://www.repeato.app/android-espresso-why-to-avoid-thread-sleep/ ore https://developer.android.com/training/testing/espresso/idling-resource
So I've been following a video and Google's documentation trying to implement user sign in with Firebase on an android app. Which is working, so to try and tidy up (and help me reuse the code in another project) I have alot of the sign in code moved to a seperate .kt file and used the below funcion to create a new user.
//in LoginActivity.kt
fun createNewUser(email:String, password:String) :Boolean{
var success:Boolean = false
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
success = true
// Sign in success, update UI with the signed-in user's information
Log.d(null, "createUserWithEmail:success")
val user = auth.currentUser
//updateUI(user)
} else {
// If sign in fails, display a message to the user.
Log.w(null, "createUserWithEmail:failure", task.exception)
//Toast.makeText(baseContext, "Authentication failed.",Toast.LENGTH_SHORT).show()
//updateUI(null)
success = false
}
}
return success
}
The issue I am having is that the "success" boolean isn't being updated when the account is created, the Log saying "success" appears to run fine. I tried changing the inital state of success from false to true and that returned true as expected and my code looking at the result of this ran fine.
Here is where its being called from, as I said the toasts run fine but the value of success returned is always what it was initialised as.
//in MainActivity.kt
var login = LoginActivity()
if(login.createNewUser(email,password)) {
Toast.makeText(this,"I got this far",Toast.LENGTH_SHORT).show()
uploadImageToFirebase()
}
else{
Toast.makeText(this,"I didnt get this far",Toast.LENGTH_SHORT).show()
}
Thanks for any help :)
I'll start at the end, because this is a huge mistake:
var login = LoginActivity()
Never instantiate an Activity. Activity instantiation is handled by the operating system. If createNewUser relies on any functions of LoginActivity, then it will fail when called on your own instantiated instance. And if it doesn't rely on them, then don't define it inside LoginActivity.
Regarding your main question:
When you pass a callback to a function, that means it runs asynchronously. The callback will be called some time in the future, after this function has already returned. So createNewUser can't return the result of the callback.
Instead, you can create your own callback for your function like this. I'm treating auth.currentUser as type User, but you should put whatever class it actually is.
fun createNewUser(email:String, password:String, onComplete: (User?) -> Unit) {
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d(null, "createUserWithEmail:success")
onComplete(auth.currentUser)
} else {
// If sign in fails, display a message to the user.
Log.w(null, "createUserWithEmail:failure", task.exception)
onComplete(null)
}
}
}
Then to use it, you can call the function and in your lambda callback you can react based on whether the user is null or not, which indicates failure or success:
createNewUser(email, password) { user ->
if (user != null) {
// success. Do something with the smart-casted non-null user variable
} else {
// failure. Show error message to the user, etc.
}
}
I'm using AWS Amplify SDK for Cognito integration. Actually, I successfully integrated user sign in and sign up flows based on the documentation available here. However, after the successful login if we restart the app the user session is not persisting. Amplify.Auth.fetchAuthSession() always returns isSignedIn as false. I have no idea where I'm making a problem. Please find the 'sign in' snippet below.
fun onSingIn(view: View) {
Amplify.Auth.signIn(
email.value,
password.value,
{ result ->
Log.i(TAG, if (result.isSignInComplete) "Sign in succeeded" else "Sign in not complete")
if (result.isSignInComplete) {
view.context.let {
it.startActivity(Intent(it, FeedActivity::class.java))
signInStatus.postValue(true)
}
}
},
{ error ->
view.context.let {
var message = it.getString(R.string.something_went_wrong)
when (error.cause) {
is UserNotConfirmedException ->{
email.value?.let {emailAddress ->
val direction =LoginFragmentDirections
.actionLoginFragmentToEmailVerificationCodeFragment(emailAddress)
view.findNavController().navigate(direction)
}
}
is UserNotFoundException ->
message = it.getString(R.string.credentilas_incorrect)
else->
viewModelScope.launch(Dispatchers.Main) { it.showToast(message) }
}
Log.e(TAG, error.toString())
}
}
)
}
Finally resolved the issue. The problem was related user pool app client settings configurations. I haven't checked identity providers inside app client settings. After choosing 'Cognito User Pool' as an identity provider the login session stayed alive without any issues. Hope this answer will help someone facing a similar issue.