I am trying to give user an option to login with google account using firebase
earlier i was successfully able to this this but recently i got this issue which i am not sure that why it is happening
ISSUE-> when i start another activity and get result back in registerForActivityResult()
i always getting result.resultCode as 0 i.e RESULT_CANCELED
here is the signup fragment
class NewAccountFragment : Fragment() {
private lateinit var binding: FragmentNewAccountBinding
//declaring and initializing the shareViewModel
private val sharedViewModel:SharedViewModel by activityViewModels()
private lateinit var auth:FirebaseAuth
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View{
val view = FragmentNewAccountBinding.inflate(inflater,container,false)
binding = view
return view.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//setting the things to use if user taps on google button
sharedViewModel.getGso(requireContext()) //to get info from user's gmail id
sharedViewModel.getGSC(requireContext())//google signInClient
//initializing fire base auth
auth = FirebaseAuth.getInstance()
//handling the click of register button
binding.registerButton.setOnClickListener {
startRegistrationProcess()
}
//handling the click of google sign in button
binding.googleSignInButton.setOnClickListener {
val intent = sharedViewModel.getSignInIntent(requireContext())
if(intent!=null){
//receiving intent to show pop up on screen to show option which account he/she will use for this app
//and passing this intent to googleLauncher
googleLauncher.launch(intent)
}
}
}
//this will handle the result from that pop up
private var googleLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
when (result.resultCode) {
RESULT_OK-> {
// There are no request codes
val data: Intent? = result.data
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
try {
// Google Sign In was successful, authenticate with Firebase
val account = task.getResult(ApiException::class.java)!!
//telling sharedViewModel to signIn the user with it's google account on firebase
sharedViewModel.firebaseAuthWithGoogle(account.idToken!!, requireContext())
//clearing up the inputs
binding.passwordEt.setText("")
binding.emailEt.setText("")
} catch (e: ApiException) {
// Google Sign In failed, show error on toast
Toast.makeText(requireContext(), e.message, Toast.LENGTH_SHORT).show()
}
}
RESULT_CANCELED->{
Toast.makeText(requireContext(),"result failed",Toast.LENGTH_SHORT).show()
}
}
}
private fun startRegistrationProcess() {
//getting text from editTexts
val email = binding.emailEt.text.toString().trim()
val password = binding.passwordEt.text.toString().trim()
//Validation.
//if email matches the standards
if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
binding.emailEt.error = "Invalid Email"
} else if (password.length < 8) {
//set error and focus on passWord.
binding.passwordEt.error = "Enter more than 7 character"
} else {
//telling shareViewModel to crate account for this use with email and password
sharedViewModel.registerOnFirebase(email,password,requireContext())
binding.passwordEt.setText("")
binding.emailEt.setText("")
}
}
}
and here is the viewModel attached to it
class SharedViewModel:ViewModel() {
private lateinit var gso:GoogleSignInOptions
private lateinit var googleSignInClient:GoogleSignInClient
private val auth: FirebaseAuth = FirebaseAuth.getInstance()
// -> FOR NEW ACCOUNT FRAGMENT
//for firebase registration
fun registerOnFirebase( email:String, password:String,context: Context){
auth.createUserWithEmailAndPassword(email, password).addOnCompleteListener { task->
if(task.isSuccessful){
//user has signed in successfully
Toast.makeText(context, "Account created successfully!!", Toast.LENGTH_SHORT).show()
// go to dashboard activity
val intent = Intent(context,DashboardActivity::class.java)
//intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
context.startActivity(intent)
MainActivity.isAlive.value = false
}else{
Toast.makeText(context, "error: ${task.exception!!.message}", Toast.LENGTH_SHORT).show()
}
}
}
//for google registration
fun getGso(context: Context){
gso = GoogleSignInOptions
.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(context.getString(R.string.server_client_id))
.requestEmail()
.build()
}
fun getGSC(context: Context){
googleSignInClient = GoogleSignIn.getClient(context,gso)
}
fun getSignInIntent(context: Context): Intent? {
val duplicate = checkDelicacy(context) //true if duplicate
if(duplicate){
Toast.makeText(context, "Already a member, Please logIn", Toast.LENGTH_SHORT).show()
} else {
return googleSignInClient.signInIntent
}
return null
}
fun firebaseAuthWithGoogle(idToken: String,context: Context) {
val credential = GoogleAuthProvider.getCredential(idToken, null)
auth.signInWithCredential(credential).addOnCompleteListener { task->
if(task.isSuccessful){
//if registered with google successfully then navigate to DashboardActivity with a toast
Toast.makeText(context, "Signed in with google", Toast.LENGTH_SHORT).show()
//navigate to DashboardActivity
val intent = Intent(context,DashboardActivity::class.java)
context.startActivity(intent)
MainActivity.isAlive.value = false
}else{
Toast.makeText(context, "error: ${task.exception!!.message}", Toast.LENGTH_SHORT).show()
}
}
}
private fun checkDelicacy(context: Context): Boolean {
val account = GoogleSignIn.getLastSignedInAccount(context)
return account!=null
}
// -> FOR ALREADY ACCOUNT FRAGMENT
//logging in with email and password
fun logInWithFireBase(email: String, password: String,context: Context) {
auth.signInWithEmailAndPassword(email,password).addOnCompleteListener { task->
if(task.isSuccessful){
//if logged in successfully then navigate to DashboardActivity with a toast
Toast.makeText(context, "Logged in successfully!!", Toast.LENGTH_SHORT).show()
val intent = Intent(context,DashboardActivity::class.java)
context.startActivity(intent)
MainActivity.isAlive.value = false
}else{
Toast.makeText(context, "error: ${task.exception!!.message}", Toast.LENGTH_SHORT).show()
}
}
}
}
Related
Hope you are well.
I would like to add a Check Box (I am 18+ Years Old) on my Login Activity (using Google Login) for my Android App.
It is working in a way: It continues to the Google Login Option (asking for your Email), then comes back to Login Activity again if not checked. Then shows the toast. So it works in a way.
I would like it to show the toast until the Box is Checked, then open the Email block to ask for your email.
Another problem is now it always returns to this screen when the app starts. But it does remember the user and doesn't ask for the email details again. I want it only once along with the Google Login.
What I'm really asking is please where should my check box if statement be? Please help.
It is now after:
private fun updateUI(user: FirebaseUser?) {
Here is a Pastebin link just in incase:
https://pastebin.com/GPC2X3xJ
Here is the Login Activity:
class LoginActivity : AppCompatActivity() {
private companion object {
private const val TAG = "LoginActivity"
private const val RC_GOOGLE_SIGN_IN= 4915
}
private lateinit var auth: FirebaseAuth
private lateinit var checkBox: CheckBox
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
auth = Firebase.auth
// Configure Google Sign In
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build()
val client = GoogleSignIn.getClient(this, gso)
findViewById<View>(R.id.btnSignIn)?.setOnClickListener {
val signInIntent = client.signInIntent
startActivityForResult(signInIntent, RC_GOOGLE_SIGN_IN)
}
}
override fun onStart() {
super.onStart()
// Check if user is signed in (non-null) and update UI accordingly.
val currentUser = auth.currentUser
updateUI(currentUser)
}
private fun updateUI(user: FirebaseUser?) {
//Navigate to MainActivity
if (user == null){
Log.w(TAG, "User is null, not going to navigate")
return
} else {
val mCheckBox = findViewById<CheckBox>(R.id.check_box_18)
if (mCheckBox.isChecked) {
startActivity(Intent(this, MainActivity::class.java))
finish()
} else {
Toast.makeText(
applicationContext,
"Please confirm you are 18+ years old",
Toast.LENGTH_SHORT
).show()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_GOOGLE_SIGN_IN) {
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
try {
// Google Sign In was successful, authenticate with Firebase
val account = task.getResult(ApiException::class.java)!!
Log.d(TAG, "firebaseAuthWithGoogle:" + account.id)
firebaseAuthWithGoogle(account.idToken!!)
} catch (e: ApiException) {
// Google Sign In failed, update UI appropriately
Log.w(TAG, "Google sign in failed", e)
}
}
}
private fun firebaseAuthWithGoogle(idToken: String) {
val credential = GoogleAuthProvider.getCredential(idToken, null)
auth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success")
val user = auth.currentUser
updateUI(user)
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.exception)
Toast.makeText(this, "Authentication Failed", Toast.LENGTH_SHORT).show()
updateUI(null)
}
I think you can make validation inside the button sign in here
findViewById<View>(R.id.btnSignIn)?.setOnClickListener { val signInIntent = client.signInIntent startActivityForResult(signInIntent, RC_GOOGLE_SIGN_IN)},
if the checkbox is not checked you can show the toast,
val signInIntent = client.signInIntent startActivityForResult(signInIntent, RC_GOOGLE_SIGN_IN)}`,
make this code inside validation
I wanted to add the sign in with google feature of firebase I connected my app to firebase then added the SHA-1 certificate fingerprint and wrote the below code.
Once I click on the sign in button the intent opens a chooser to select a google account but after selecting one account nothing happens even there is no exceptions or error in the logcat.
Code:
class SignInActivity : AppCompatActivity() {
private lateinit var googleSignInClient:GoogleSignInClient
private lateinit var auth:FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sign_in)
val gso= GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build()
googleSignInClient = GoogleSignIn.getClient(this,gso)
signInButton.setOnClickListener {
resultLauncher.launch(googleSignInClient.signInIntent)
}
}
private var resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
val intent=it.data
if(it.resultCode == Activity.RESULT_OK)
{
val task = GoogleSignIn.getSignedInAccountFromIntent(intent)
handleSignInResult(task)
}
}
private fun handleSignInResult(task: Task<GoogleSignInAccount>?) {
try{
val account= task?.getResult(ApiException::class.java)!!
Log.i("account","firebaseAuthWithGoogle:"+account.id)
firebaseAuthWithGoogle(account.idToken!!)
}catch (e : ApiException){
Log.i(TAG, "Google sign in failed", e)
}
}
private fun firebaseAuthWithGoogle(idToken: String) {
signInButton.visibility= View.GONE
progressBar.visibility=View.VISIBLE
val credential=GoogleAuthProvider.getCredential(idToken,null)
GlobalScope.launch(Dispatchers.IO) {
val auth=auth.signInWithCredential(credential).await()
val firebaseUser=auth.user
Log.i("user",firebaseUser.toString())
withContext(Dispatchers.Main){
updateUI(firebaseUser)
}
}
}
private fun updateUI(firebaseUser: FirebaseUser?) {
if(firebaseUser != null)
{
val intent=Intent(this,MainActivity::class.java)
startActivity(intent)
Log.i("intent","Intent Started")
// Toast.makeText(applicationContext,"Sign In Successful",Toast.LENGTH_SHORT).show()
finish()
}
else{
signInButton.visibility= View.VISIBLE
progressBar.visibility=View.GONE
Toast.makeText(this,"Sign In failed",Toast.LENGTH_SHORT).show()
}
}
}
Logcat:
I am very new to android development and this is my first time with firebase.
I am using Google Sign in to login into a app I am building to display calendars. Post Google Sign in - it also logs into Firebase where the user data is stored in the Realtime Database. While the whole app was working properly - suddenly it stopped syncing with the Google Calendar API and I get the below "Errors" in the Info. I am able to login and with new accounts just no sync - app works - no data. I have tried checking multiple issues and even reverted to old code - no diff. Firebase user data is also being displayed in the app. Can anybody please suggest an approach to solving this issue?
2021-01-04 09:59:21.021 2139-4708/com.google.android.gms.persistent W/Auth: [GetToken] GetToken failed with status code: ServiceDisabled
2021-01-04 09:59:21.022 10175-10254/ W/System.err: com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAuthIOException
2021-01-04 09:59:21.022 10175-10254/ W/System.err: at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential$RequestHandler.intercept(GoogleAccountCredential.java:286)
2021-01-04 09:59:21.022 10175-10254/ W/System.err: at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:859)
2021-01-04 09:59:21.023 10175-10254/ W/System.err: at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
2021-01-04 09:59:21.023 10175-10254/ W/System.err: at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
2021-01-04 09:59:21.023 10175-10254/ W/System.err: at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
2021-01-04 09:59:21.023 10175-10254/ W/System.err: at .Fragments.Home$syncWholeCalendar$1.invokeSuspend(Home.kt:298)
Below is the code I use to get the user to sign in
private const val TAG = "WelcomeActivity"
class WelcomeActivity : AppCompatActivity() {
var firebaseUser: FirebaseUser? = null
//For Google Sign In
val RC_SIGN_IN: Int = 9001
private lateinit var mGoogleSignInClient: GoogleSignInClient
lateinit var mGoogleSignInOptions: GoogleSignInOptions
private lateinit var firebaseAuth: FirebaseAuth
private var firebaseUserID : String = ""
private lateinit var refUsers : DatabaseReference
//get data from google signin in handlesigninresult
private var googleId = ""
private var googleFirstName = ""
private var googleLastName = ""
private var googleEmail = ""
private var googleProfilePicURL = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_welcome)
// //For google sign in
// configureGoogleSignIn()
// setupUI()
firebaseAuth = FirebaseAuth.getInstance()
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken("896894788293-oe0enptjj2hltdde9isemuf89gtkb7u4.apps.googleusercontent.com")
.requestEmail()
.build()
mGoogleSignInClient = GoogleSignIn.getClient(this, gso)
google_login.setOnClickListener {
signIn()
}
login_welcome.setOnClickListener {
val intent = Intent(this#WelcomeActivity, LoginActivity::class.java)
startActivity(intent)
finish()
}
}
private fun signIn() {
val signInIntent = mGoogleSignInClient.signInIntent
startActivityForResult(signInIntent, RC_SIGN_IN)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RC_SIGN_IN) {
val task =
GoogleSignIn.getSignedInAccountFromIntent(data)
handleSignInResult(task)
}
}
private fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) {
try {
val account = completedTask.getResult(
ApiException::class.java
)
// Signed in successfully
googleId = account?.id ?: ""
Log.i("Google ID", googleId)
googleFirstName = account?.givenName ?: ""
Log.i("Google First Name", googleFirstName)
googleLastName = account?.familyName ?: ""
Log.i("Google Last Name", googleLastName)
googleEmail = account?.email ?: ""
Log.i("Google Email", googleEmail)
val googleIdToken: String = account?.idToken ?: ""
Log.i("Google ID Token", googleIdToken)
googleProfilePicURL = account?.photoUrl.toString()
Log.i("Google Profile Pic URL", googleProfilePicURL)
firebaseAuthWithGoogle(googleIdToken)
} catch (e: ApiException) {
// Sign in was unsuccessful
Log.e(
"failed code=", e.statusCode.toString()
)
}
}
private fun firebaseAuthWithGoogle(idToken: String) {
val credential = GoogleAuthProvider.getCredential(idToken, null)
firebaseAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success")
firebaseUserID = firebaseAuth.currentUser!!.uid
refUsers = FirebaseDatabase.getInstance().reference.child("Users").child(
firebaseUserID
)
refUsers.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
if (p0.exists()) {
val user: Users? = p0.getValue(Users::class.java)
//Check if user exists in the database
if (user!!.getFirstName() != null) {
val intent = Intent(
this#WelcomeActivity,
IntroSplashScreen::class.java
)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
finish()
} else {
val usersHashMap = HashMap<String, Any>()
usersHashMap["uid"] = firebaseUserID
usersHashMap["firstname"] = googleFirstName
usersHashMap["surname"] = googleLastName
usersHashMap["profile"] = googleProfilePicURL
usersHashMap["primaryEmail"] = googleEmail
usersHashMap["search"] =
googleFirstName.toLowerCase(Locale.ROOT)
refUsers.updateChildren(usersHashMap)
.addOnCompleteListener {
if (task.isSuccessful) {
val intent = Intent(
this#WelcomeActivity,
IntroSplashScreen::class.java
)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
finish()
}
}
}
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.exception)
// ...
}
// ...
}
}
private fun refreshIdToken() {
// Attempt to silently refresh the GoogleSignInAccount. If the GoogleSignInAccount
// already has a valid token this method may complete immediately.
//
// 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 and get a valid
// ID token. Cross-device single sign on will occur in this branch.
mGoogleSignInClient.silentSignIn()
.addOnCompleteListener(
this
) { task -> handleSignInResult(task) }
}
override fun onStart() {
super.onStart()
//Checks if the Google IDToken has expired, if yes it refreshes by SilentSign in and generates new Firebase Token
refreshIdToken()
//Checks if user is logged in to firebase
firebaseUser = FirebaseAuth.getInstance().currentUser
//If logged in then sends to MainActivity
if(firebaseUser!=null){
startActivity(IntroSplashScreen.getLaunchIntent(this))
finish()
}
}
override fun onResume() {
super.onResume()
refreshIdToken()
}
}
Needed to create a Beta Test Program, as anybody who was not associated/listed was blocked from accessing data.
i have 3 progress activities for signup. I take the informations at first activity and then trying to send directly third activity to signup with firebase. I tried every way that i research but i can't figure it out.
This is my first activity
signUpNextButton.setOnClickListener {
val name = signUpFullname.text.toString()
val email = signUpEmail.text.toString()
val password = signUpPassword.text.toString()
val repassword = signUpPasswordRepeat.text.toString()
//Sending datas with this method
val intent = Intent(this, SignUp_Page3::class.java)
intent.putExtra("user_email", email)
intent.putExtra("user_password", password)
startActivity(Intent(this, SignUp_Page2::class.java))
}
this is the second one
signUpGetCode.setOnClickListener {
startActivity(Intent(this, SignUp_Page3::class.java)) }
and this is the last one:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.signup3)
val intent = getIntent()
val email = intent.getStringExtra("user_email")
val password = intent.getStringExtra("user_password")
signUpComplete.setOnClickListener {
//Firebase Authentication to create user
FirebaseAuth.getInstance()
.createUserWithEmailAndPassword(
email,
password
)
.addOnCompleteListener {
if (it.isSuccessful) {
startActivity(Intent(this, LogIn_Page::class.java))
Toast.makeText(
this,
"Account successfully created, please log in.",
Toast.LENGTH_LONG
).show()
finish()
} else {
Toast.makeText(this, "Something went wrong.", Toast.LENGTH_SHORT).show()
return#addOnCompleteListener
}
}
}
It looks like you are passing to the second page via Intent, but never pass from second to third page.
First retrieve the info in your second and third page.
private var email: String? = null
private var password: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (intent != null) {
email = intent.getStringExtra("user_email")
password = intent.getStringExtra("user_password")
} else if (savedInstanceState != null){
email = savedInstanceState.getString("user_email")
password = savedInstanceState.getString("user_password")
}
//TODO rest of onCreate
}
Try passing the info into the third page Intent.
Be careful about storing this data in the Intent. If you don't implement onSaveInstanceState in your second and third page, then you are going to lose the data on a rotation.
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("user_email", email)
outState.putString("user_password", password)
}
Also consider using Static String constants for your keys it will make everything much more manageable.
First1:
signUpNextButton.setOnClickListener {
val name = signUpFullname.text.toString()
val email = signUpEmail.text.toString()
val password = signUpPassword.text.toString()
//Sending datas with this method
val intent = Intent(this, SignUp_Page2::class.java)
intent.putExtra("user_email", email)
intent.putExtra("user_password", password)
//Starting another activity
startActivity(intent)
}
second1:
private var email: String? = null
private var password: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.signup2)
val intent = getIntent()
if (intent != null) {
email = intent.getStringExtra("user_email")
password = intent.getStringExtra("user_password")
} else if (savedInstanceState != null){
email = savedInstanceState.getString("user_email")
password = savedInstanceState.getString("user_password")
}
signUpGetCode.setOnClickListener {
val phone = signUpPhoneNumber.text.toString()
startActivity(Intent(this, SignUp_Page3::class.java))
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("user_email", email)
outState.putString("user_password", password)
}
third1:
private var email: String? = null
private var password: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.signup3)
val intent = getIntent()
if (intent != null) {
email = intent.getStringExtra("user_email")
password = intent.getStringExtra("user_password")
} else if (savedInstanceState != null) {
email = savedInstanceState.getString("user_email")
password = savedInstanceState.getString("user_password")
}
signUpComplete.setOnClickListener {
Toast.makeText(this, email + password, Toast.LENGTH_SHORT).show()
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("user_email", email)
outState.putString("user_password", password)
}
Toast message give me the null null output.
FirebaseAuth.getInstance()
.createUserWithEmailAndPassword(
email.toString(),
password.toString()
)
.addOnCompleteListener {
if (it.isSuccessful) {
startActivity(Intent(this, LogIn_Page::class.java))
Toast.makeText(
this,
"Account successfully created, please log in.",
Toast.LENGTH_LONG
).show()
} else {
Toast.makeText(this, "Something went wrong.", Toast.LENGTH_SHORT).show()
return#addOnCompleteListener
}
}
this returns "something went wrong" to me
So I have followed the advice of 'yoursTruly' and created an AuthStateListener in my Activity (as described here: https://www.youtube.com/watch?v=6CXUNcsQPgQ&feature=youtu.be).
This works really well, in the fact that the Activity is simply listening to Authentication and will divert to next Activity if someone logs in and the Fragment simply calls signIn(email, password) via the ViewModel.
However, can not see a way to look for failed login attempts (so the UI will just look like it is unresponsive).
My structure is as follows: Activity -> Fragment -> ViewModel -> Repository.
I'm using DataBinding & Navigation.
Activity
class LoginActivity : AppCompatActivity(), FirebaseAuth.AuthStateListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.login_activity)
}
override fun onStart() {
super.onStart()
FirebaseAuth.getInstance().addAuthStateListener(this)
}
override fun onStop() {
super.onStop()
FirebaseAuth.getInstance().removeAuthStateListener(this)
}
override fun onAuthStateChanged(firebaseAuth: FirebaseAuth) {
// Will only fire if state has changed!
if (FirebaseAuth.getInstance().currentUser == null) {
Toast.makeText(this,"Welcome to the Locators App!\n\nPlease login to continue", Toast.LENGTH_LONG).show()
return
}
firebaseAuth.currentUser?.getIdToken(true)
?.addOnSuccessListener { result ->
val idToken = result.token
Toast.makeText(this,"User Signed In", Toast.LENGTH_LONG).show()
Log.d(TAG, "GetTokenResult result (check this at https://jwt.io/ = $idToken")
goToSiteActivity()
}
}
private fun goToSiteActivity() {
val intent = Intent(this, SiteActivity::class.java)
startActivity(intent)
finish()
}
}
Fragment
class LoginFragment : Fragment() {
private lateinit var loginViewModel: LoginViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val binding: LoginFragmentBinding = DataBindingUtil.inflate(
inflater, R.layout.login_fragment, container, false)
binding.apply {
loginPasswordResetText.setOnClickListener{
findNavController().navigate(R.id.action_loginFragment_to_loginPasswordResetFragment)
}
loginButton.setOnClickListener{
loginProgressBar.visibility = View.VISIBLE
val email = loginEmailEditText.text.toString()
val password = loginPasswordEditText.text.toString()
if(validateForm(email, password)) {
loginViewModel.loginUser(email, password)
}
loginProgressBar.visibility = View.GONE
}
loginNewUserText.setOnClickListener{
findNavController().navigate(R.id.action_loginFragment_to_loginUserRegisterFragment)
}
}
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
loginViewModel = ViewModelProviders.of(requireActivity()).get(LoginViewModel::class.java)
}
private fun validateForm(email: String, password: String): Boolean {
var validForm = true
if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
loginEmailEditText.error = "Please enter valid email address!"
validForm = false
} else loginEmailEditText.error = null
if (password.isEmpty()) {
loginPasswordEditText.error = "Please enter password!"
validForm = false
} else loginPasswordEditText.error = null
Log.d(TAG,"validateForm: (email = $email, password = $password, validateForm = $validForm)")
return validForm
}
}
ViewModel
class LoginViewModel : ViewModel() {
fun loginUser (email: String, password: String) {
firestoreRepository.loginUser(email, password)
}
}
Repository
class FirestoreRepository {
var firebaseAuth = FirebaseAuth.getInstance()
var firebaseUser = firebaseAuth.currentUser
var failedLogin: Boolean = false
fun loginUser(email: String, password: String) {
failedLogin = false
firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener {
if (it.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithEmail:success")
} else {
// If sign in fails, display a message to the user.
Log.d(TAG, "signInWithEmail:failure", it.exception)
failedLogin = true
}
}
}
}
This question ties in with a larger query of, if you create LiveData in Repo, how do you Observe from ViewModel (i.e. what do you use as the LifeCycleOwner?), but I will ask on a seperate question..
An AuthStateListener is not sufficient to determine when a sign-in fails. It will only tell you when the state of the user changes between signed in and signed out.
You will have to use the result of firebaseAuth.signInWithEmailAndPassword to determine if the sign-in failed. It looks like you already have some code there to handle that case, but you're not doing much with the error other than setting a property.
What you should do instead is have your loginUser ViewModel method return a LiveData that gets notified when the sign-in succeeds or fails. You will have to wire up the call to signInWithEmailAndPassword to change the state of that LiveData, and your view will have to observe that LiveData to show a message to the user if necessary.