How To Replace OnActivityResult With New Activity Result API With Parse-SDK - android

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!")
}
}
}
}

Related

Can createUserWithEmailAndPassword called be multiple times?

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.

FIrebase sign in and out options are not working

Can someone explain to me why this simple code is not working properly?
In the beginning I created an object with auth and currentUser
object FirebaseUtils {
val auth: FirebaseAuth = FirebaseAuth.getInstance()
val currentUser: FirebaseUser? = auth.currentUser
}
My login activity function
fun login(){
val email = binding.loginInput.text.toString()
val password = binding.passwordInput.text.toString()
auth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener {
task ->
if (task.isSuccessful){
task.result
Log.d("login_status", "Logged: ${currentUser?.uid}")
startActivity(Intent(this, MainActivity::class.java))
finish()
} else {
Log.d("login_status", task.exception.toString())
}
}
}
Start activity:
lifecycleScope.launch {
delay(2000)
if(currentUser?.uid != null){
Log.d("login_status", "Logged: ${currentUser.uid}")
startActivity(Intent(applicationContext, MainActivity::class.java))
}else{
startActivity(Intent(applicationContext, LoginMainActivity::class.java))
}
finish()
}
And sign out
fun signOut(){
auth.signOut()
startActivity(Intent(this, LoginMainActivity::class.java))
Log.d("login_status", "Signed out: ${currentUser?.uid}")
finish()
}
The problem is that after the first login I can see that logged user is null so my app is crashing (no data for the user). However, after restarting I am logged in as this user. I cant also sign out - activity changes to the login screen but even if I pass different credentials the user remains the same.
EDIT
When I log in and restart the app it works - the correct user is logged.
When I log out and restart the app it also works - the user is signed out.
So why is there a problem between activities
Your result is null because you are getting the result object out of the task object but you aren't doing anything with it. Simply calling:
task.result
Doesn't provide any benefit. However, you can save that result into a variable and call AuthResult#getUser() like this:
val user = task.result.getUser()
Log.d("login_status", "Logged: ${user?.uid}")
So right after you authenticate the user successfully, you'll be able to log the UID correctly.

email is not verified

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().

Why isn't the variable being updated and returned correctly in this function?

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.
}
}

How to sign in a user with AWS Amplify on Android + Kotlin?

I'm trying to make an Android app with a sign in screen on Android in Kotlin using AWS Amplify, here's my sign in code:
AWSMobileClient.getInstance().signIn(username, password, null, object : Callback<SignInResult> {
override fun onResult(signInResult: SignInResult) {
runOnUiThread {
Log.d("DEBUG", "Sign-in callback state: " + signInResult.signInState)
when (signInResult.signInState) {
SignInState.DONE -> Log.d("DEBUG", "Sign-in done.")
SignInState.SMS_MFA -> Log.d("DEBUG", "Please confirm sign-in with SMS.")
SignInState.NEW_PASSWORD_REQUIRED -> Log.d("DEBUG", "Please confirm sign-in with new password.")
else -> Log.d("DEBUG", "Unsupported sign-in confirmation: " + signInResult.signInState)
}
}
}
override fun onError(e: Exception) {
Log.e("DEBUG", "Sign-in error", e)
}
})
I used the documentation of Amazon here, copied and pasted the block found at the Sign In chapter into Android Studio that automatically converted the Java code into Kotlin.
Using logs I see that my code above this one is executed when I press the login button but the onResult block is never called. The logs only print a D/AWSMobileClient: Sending password. from AWS sdk.
I remember that this code worked before Christmas holidays so I think that it's maybe a change on the Amazon side but I find nothing in the documentation.
Do you have any idea of what's wrong here ?

Categories

Resources