I created a login page that asks the user to enter their phone number. After the user enters their number it takes them to a screen where the user types the OTP code send to their phone. After user enters the correct OTP code it sends them to the main screen of my app. But I have one problem. Whenever a new user is added it has different UID in database. It is not the same on as in my Firebase Authentication.
For example I logged in with my own phone number and on my Realtime database my UID is EbC9e1K39MYNJ49M7QrvV8ZLshJ3 and in my Firebase Authentication my UID thats on my phonenumber is R3ZjGJl56vcmwRKLBiUpB0g2xDc2.
Here are my codes:
CreateNewAccount class
class CreateNewAccount : AppCompatActivity() {
val mAuth = FirebaseAuth.getInstance()
var phoneNumber: String? = null
var username: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create_new_account)
username = accountName.text.toString()
sendCode.setOnClickListener {
username = accountName.text.toString()
val phoneNumberAsText = telephoneNumber.text.toString()
phoneNumber = "+389$phoneNumberAsText"
// val numberWithZeroRemoved = phoneNumber!!.substring(1,phoneNumber!!.length-1)
progressBar.visibility = View.VISIBLE
val options = PhoneAuthOptions.newBuilder(mAuth)
.setPhoneNumber(phoneNumber!!) // Phone number to verify
.setTimeout(30L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this) // Activity (for callback binding)
.setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
}
private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
Toast.makeText(this, "Auth success", Toast.LENGTH_SHORT).show()
sendToMain()
} else {
// Sign in failed, display a message and update the UI
Log.w(TAG, "signInWithCredential:failure: ${task.exception.toString()}")
if (task.exception is FirebaseAuthInvalidCredentialsException) {
// The verification code entered was invalid
}
// Update UI
}
progressBar.visibility = View.INVISIBLE
}
}
private fun sendToMain() {
// startActivity(Intent(this, MainActivity::class.java))
}
private val callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
signInWithPhoneAuthCredential(credential)
}
override fun onVerificationFailed(e: FirebaseException) {
if (e is FirebaseAuthInvalidCredentialsException) {
Log.d("TAG", "OnVerificationFailed:,${e.toString()}")
} else if (e is FirebaseTooManyRequestsException) {
Log.d("TAG", "OnVerificationFailed:,${e.toString()}")
}
progressBar.visibility = View.VISIBLE
// Show a message and update the UI
}
override fun onCodeSent(
verificationId: String,
token: PhoneAuthProvider.ForceResendingToken
) {
Log.d(TAG, "onCodeSent:$verificationId")
// Save verification ID and resending token so we can use them later
val intent = Intent(this#CreateNewAccount, VerifyAccount::class.java)
intent.putExtra("OTP", verificationId)
intent.putExtra("resendToken", token)
intent.putExtra("phoneNumber", phoneNumber)
intent.putExtra("username", username)
startActivity(intent)
progressBar.visibility = View.INVISIBLE
}
}
fun hideKeyboard(view: View) {
val inputMethodManager =
getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
}
VerifyAccount class
class VerifyAccount : AppCompatActivity() {
val mAuth = FirebaseAuth.getInstance()
private lateinit var OTP: String
private lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
private lateinit var phoneNumber: String
private lateinit var userName:String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_verify_account)
resendCode.isEnabled = false
val timer = object : CountDownTimer(30000, 1000) {
override fun onTick(millisUntilFinished: Long) {
val secs = millisUntilFinished / 1000
resendCode.text = "Wait $secs secs"
}
override fun onFinish() {
resendCode.text = "Resend Code"
resendCode.isEnabled = true
}
}
timer.start()
if (resendCode.isEnabled){
resendCode.setOnClickListener {
resendVerificationCode()
}
}
OTP = intent.getStringExtra("OTP").toString()
resendToken = intent.getParcelableExtra("resendToken")!!
phoneNumber = intent.getStringExtra("phoneNumber").toString()
userName = intent.getStringExtra("username").toString()
digitOne.setOnClickListener {
if (firstDigit.text.isEmpty()) {
firstDigit.text = "1"
} else if (secondDigit.text.isEmpty()) {
secondDigit.text = "1"
} else if (thirdDigit.text.isEmpty()) {
thirdDigit.text = "1"
} else if (fourthDigit.text.isEmpty()) {
fourthDigit.text = "1"
} else if (fifthDigit.text.isEmpty()) {
fifthDigit.text = "1"
} else if (sixthDigit.text.isEmpty()) {
sixthDigit.text = "1"
}
}
digitTwo.setOnClickListener {
if (firstDigit.text.isEmpty()) {
firstDigit.text = "2"
} else if (secondDigit.text.isEmpty()) {
secondDigit.text = "2"
} else if (thirdDigit.text.isEmpty()) {
thirdDigit.text = "2"
} else if (fourthDigit.text.isEmpty()) {
fourthDigit.text = "2"
} else if (fifthDigit.text.isEmpty()) {
fifthDigit.text = "2"
} else if (sixthDigit.text.isEmpty()) {
sixthDigit.text = "2"
}
}
digitThree.setOnClickListener {
if (firstDigit.text.isEmpty()) {
firstDigit.text = "3"
} else if (secondDigit.text.isEmpty()) {
secondDigit.text = "3"
} else if (thirdDigit.text.isEmpty()) {
thirdDigit.text = "3"
} else if (fourthDigit.text.isEmpty()) {
fourthDigit.text = "3"
} else if (fifthDigit.text.isEmpty()) {
fifthDigit.text = "3"
} else if (sixthDigit.text.isEmpty()) {
sixthDigit.text = "3"
}
}
digitFour.setOnClickListener {
if (firstDigit.text.isEmpty()) {
firstDigit.text = "4"
} else if (secondDigit.text.isEmpty()) {
secondDigit.text = "4"
} else if (thirdDigit.text.isEmpty()) {
thirdDigit.text = "4"
} else if (fourthDigit.text.isEmpty()) {
fourthDigit.text = "4"
} else if (fifthDigit.text.isEmpty()) {
fifthDigit.text = "4"
} else if (sixthDigit.text.isEmpty()) {
sixthDigit.text = "4"
}
}
digitFive.setOnClickListener {
if (firstDigit.text.isEmpty()) {
firstDigit.text = "5"
} else if (secondDigit.text.isEmpty()) {
secondDigit.text = "5"
} else if (thirdDigit.text.isEmpty()) {
thirdDigit.text = "5"
} else if (fourthDigit.text.isEmpty()) {
fourthDigit.text = "5"
} else if (fifthDigit.text.isEmpty()) {
fifthDigit.text = "5"
} else if (sixthDigit.text.isEmpty()) {
sixthDigit.text = "5"
}
}
digitSix.setOnClickListener {
if (firstDigit.text.isEmpty()) {
firstDigit.text = "6"
} else if (secondDigit.text.isEmpty()) {
secondDigit.text = "6"
} else if (thirdDigit.text.isEmpty()) {
thirdDigit.text = "6"
} else if (fourthDigit.text.isEmpty()) {
fourthDigit.text = "6"
} else if (fifthDigit.text.isEmpty()) {
fifthDigit.text = "6"
} else if (sixthDigit.text.isEmpty()) {
sixthDigit.text = "6"
}
}
digitSeven.setOnClickListener {
if (firstDigit.text.isEmpty()) {
firstDigit.text = "7"
} else if (secondDigit.text.isEmpty()) {
secondDigit.text = "7"
} else if (thirdDigit.text.isEmpty()) {
thirdDigit.text = "7"
} else if (fourthDigit.text.isEmpty()) {
fourthDigit.text = "7"
} else if (fifthDigit.text.isEmpty()) {
fifthDigit.text = "7"
} else if (sixthDigit.text.isEmpty()) {
sixthDigit.text = "7"
}
}
digitEight.setOnClickListener {
if (firstDigit.text.isEmpty()) {
firstDigit.text = "8"
} else if (secondDigit.text.isEmpty()) {
secondDigit.text = "8"
} else if (thirdDigit.text.isEmpty()) {
thirdDigit.text = "8"
} else if (fourthDigit.text.isEmpty()) {
fourthDigit.text = "8"
} else if (fifthDigit.text.isEmpty()) {
fifthDigit.text = "8"
} else if (sixthDigit.text.isEmpty()) {
sixthDigit.text = "8"
}
}
digitNine.setOnClickListener {
if (firstDigit.text.isEmpty()) {
firstDigit.text = "9"
} else if (secondDigit.text.isEmpty()) {
secondDigit.text = "9"
} else if (thirdDigit.text.isEmpty()) {
thirdDigit.text = "9"
} else if (fourthDigit.text.isEmpty()) {
fourthDigit.text = "9"
} else if (fifthDigit.text.isEmpty()) {
fifthDigit.text = "9"
} else if (sixthDigit.text.isEmpty()) {
sixthDigit.text = "9"
}
}
digitZero.setOnClickListener {
if (firstDigit.text.isEmpty()) {
firstDigit.text = "0"
} else if (secondDigit.text.isEmpty()) {
secondDigit.text = "0"
} else if (thirdDigit.text.isEmpty()) {
thirdDigit.text = "0"
} else if (fourthDigit.text.isEmpty()) {
fourthDigit.text = "0"
} else if (fifthDigit.text.isEmpty()) {
fifthDigit.text = "0"
} else if (sixthDigit.text.isEmpty()) {
sixthDigit.text = "0"
}
}
clearBTN.setOnClickListener {
firstDigit.text = ""
secondDigit.text = ""
thirdDigit.text = ""
fourthDigit.text = ""
fifthDigit.text = ""
sixthDigit.text = ""
}
verifyBTN.setOnClickListener {
val first = firstDigit.text.toString()
val second = secondDigit.text.toString()
val third = thirdDigit.text.toString()
val fourth = fourthDigit.text.toString()
val fifth = fifthDigit.text.toString()
val sixth = sixthDigit.text.toString()
val typedOTP = first + second + third + fourth + fifth + sixth
Log.d("typed otp is ", typedOTP)
if (typedOTP.isNotEmpty()) {
if (typedOTP.length == 6) {
val credential: PhoneAuthCredential = PhoneAuthProvider.getCredential(
OTP, typedOTP
)
progressbarverify.visibility = View.VISIBLE
signInWithPhoneAuthCredential(credential)
} else {
Toast.makeText(this, "Please Enter Correct OTP", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(this, "Please Enter OTP", Toast.LENGTH_SHORT).show()
}
}
}
private fun resendVerificationCode() {
val options = PhoneAuthOptions.newBuilder(mAuth)
.setPhoneNumber(phoneNumber) // Phone number to verify
.setTimeout(30L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this) // Activity (for callback binding)
.setCallbacks(callbacks)
.setForceResendingToken(resendToken)// OnVerificationStateChangedCallbacks
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
private val callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
// This callback will be invoked in two situations:
// 1 - Instant verification. In some cases the phone number can be instantly
// verified without needing to send or enter a verification code.
// 2 - Auto-retrieval. On some devices Google Play services can automatically
// detect the incoming verification SMS and perform verification without
// user action.
signInWithPhoneAuthCredential(credential)
}
override fun onVerificationFailed(e: FirebaseException) {
// This callback is invoked in an invalid request for verification is made,
// for instance if the the phone number format is not valid.
if (e is FirebaseAuthInvalidCredentialsException) {
// Invalid request
Log.d("TAG", "onVerificationFailed: ${e.toString()}")
} else if (e is FirebaseTooManyRequestsException) {
// The SMS quota for the project has been exceeded
Log.d("TAG", "onVerificationFailed: ${e.toString()}")
}
progressbarverify.visibility = View.VISIBLE
// Show a message and update the UI
}
override fun onCodeSent(
verificationId: String,
token: PhoneAuthProvider.ForceResendingToken
) {
// The SMS verification code has been sent to the provided phone number, we
// now need to ask the user to enter the code and then construct a credential
// by combining the code with a verification ID.
// Save verification ID and resending token so we can use them later
OTP = verificationId
resendToken = token
}
}
private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
val uid = FirebaseAuth.getInstance().uid ?: ""
val currentuid = FirebaseAuth.getInstance().currentUser!!.uid
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Toast.makeText(this, "Authenticate Successfully", Toast.LENGTH_SHORT).show()
val addUserToDatabase = FirebaseDatabase.getInstance().getReference("users/$currentuid/")
val user = User(currentuid,userName,phoneNumber)
addUserToDatabase.setValue(user)
.addOnSuccessListener {
Log.d("Database success","user added successfully")
sendToHobbies()
}
.addOnFailureListener {
Log.d("Database failure","user could not be added")
}
} else {
// Sign in failed, display a message and update the UI
Log.d("TAG", "signInWithPhoneAuthCredential: ${task.exception.toString()}")
if (task.exception is FirebaseAuthInvalidCredentialsException) {
// The verification code entered was invalid
}
// Update UI
}
progressbarverify.visibility = View.VISIBLE
}
}
private fun sendToHobbies() {
startActivity(Intent(this, Hobbies::class.java))
}
}
#Parcelize
class User(val currentuid:String,val name:String,val phonenumber:String):Parcelable{
constructor(): this("","","")
}
If someone can help me fix this problem I would really appreciate it.
Thanks in advance!
In signInWithPhoneAuthCredential you do:
val uid = FirebaseAuth.getInstance().uid ?: ""
val currentuid = FirebaseAuth.getInstance().currentUser!!.uid
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Toast.makeText(this, "Authenticate Successfully", Toast.LENGTH_SHORT).show()
val addUserToDatabase = FirebaseDatabase.getInstance().getReference("users/$currentuid/")
val user = User(currentuid,userName,phoneNumber)
addUserToDatabase.setValue(user)
...
So you determine the value of currentuid before you sign in the new user, and then use that value to write the profile of the new user.
To write the data under the new user's UID, move the assignment of currentuid into the if (task.isSuccessful) { block.
So I found an alternative solution. And that was instead of adding the new user to my Firebase Realtime Database when I verify the user, I take users user name and phone number and pass it to a class called Hobbies(which is the next activity after VerifyAccount)
VerifyAccount
private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Toast.makeText(this, "Authenticate Successfully", Toast.LENGTH_SHORT).show()
sendToHobbies()
} else {
// Sign in failed, display a message and update the UI
Log.d("TAG", "signInWithPhoneAuthCredential: ${task.exception.toString()}")
if (task.exception is FirebaseAuthInvalidCredentialsException) {
// The verification code entered was invalid
}
// Update UI
}
progressbarverify.visibility = View.VISIBLE
}
}
private fun sendToHobbies() {
val intent = Intent(this, Hobbies::class.java)
intent.putExtra("phoneNumber", phoneNumber)
intent.putExtra("username", userName)
startActivity(intent)
}
HobbiesClass
private lateinit var userName:String
private lateinit var phoneNumber:String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_hobbies)
val database = FirebaseDatabase.getInstance()
phoneNumber = intent.getStringExtra("phoneNumber").toString()
userName = intent.getStringExtra("username").toString()
letsgobtn.setOnClickListener {
var hobbies = selectedItems.toString()
val currentuid = FirebaseAuth.getInstance().currentUser!!.uid
val addUserToDatabase = FirebaseDatabase.getInstance().getReference("users/$currentuid/")
val user = User(currentuid,userName,phoneNumber,hobbies)
addUserToDatabase.setValue(user)
.addOnSuccessListener {
Log.d("Database success","user added successfully")
}
.addOnFailureListener {
Log.d("Database failure","user could not be added")
}
Toast.makeText(this,"Selected item is ${selectedItems.toString()}",Toast.LENGTH_SHORT).show()
}
I hope it helps others in the future :)
Related
I'm trying to make work the Login Validation form, but the program stops then reaches the second if, and I have Invalid email output. Run is clear and out of mistakes. Can't figure out what I'm doing wrong and why emailList is null
private fun logIn() {
val email = binding.editEmailAddress.text.toString()
val password = binding.editPassword.text.toString()
if (inputCheck(email, password)) {
mLoginViewModel = ViewModelProvider(this)[LoginViewModel::class.java]
val emailList = mLoginViewModel.getUserEmail(email)
if (emailList != null) {
if (emailList.password == password) {
Toast.makeText(requireContext(), "Logged in as $email", Toast.LENGTH_LONG)
.show()
findNavController().navigate(R.id.action_loginFragment_to_listFragment)
} else {
Toast.makeText(requireContext(), "Invalid password", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(requireContext(), "Invalid email", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(requireContext(), "Fill out blank fields", Toast.LENGTH_LONG).show()
}
}
private fun inputCheck(email: String, password: String): Boolean {
return !(TextUtils.isEmpty(email) || TextUtils.isEmpty(password))
}
LoginViewModel
fun getUserEmail(email: String): User? {
var checker: User? = null
viewModelScope.launch(Dispatchers.IO) {
checker = repository.getUserEmail(email)
}
return checker
}
fun getUserEmail(email: String): User? {
var checker: User? = null
viewModelScope.launch(Dispatchers.IO) {
checker = repository.getUserEmail(email)
}
return checker
// Will return null always because this is not waiting to assign value by above repository method
}
Insted you can do this
suspend fun getUserEmail(email: String): User? {
return repository.getUserEmail(email)
}
And in Activity Or Fragment
mLoginViewModel = ViewModelProvider(this)[LoginViewModel::class.java]
lifecycleScope.launch {
val emailList = mLoginViewModel.getUserEmail(email)
}
Don't Know what error you are getting on above code if that not works then use below code
mLoginViewModel = ViewModelProvider(this)[LoginViewModel::class.java]
CoroutineScope(Dispatchers.IO).launch {
val emailList = mLoginViewModel.getUserEmail(email)
withContext(Dispatchers.Main){
//Do whatever with emailList
}
}
I need to display the Telugu texts of Districts retrieved from API into Spinner, but random characters are displayed instead. How do I convert these characters to Telugu readable texts?
Sample Codes:
class MainActivity : AppCompatActivity() {
lateinit var spDistrict: Spinner
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
districtData = mutableListOf()
spDistrict = findViewById<Spinner>(R.id.district)
getDistrictData()
val jsonObject = JSONObject()
jsonObject.put("profile_pic", userImage.toString().replace("/storage/emulated/0/Pictures/",""))
jsonObject.put("district_id", districtData!![spDistrict.selectedItemPosition].id)
jsonObject.put("token", token)
Log.e("jsonObject", jsonObject.toString())
val url = Constant.BASE_URL + "register/"
Log.e("url", "---->$url")
val request = object : StringRequest(
Method.POST, url, Response.Listener { response ->
try {
val responseObj = JSONObject(response)
if (response.isNotEmpty()) {
next.hideProgress("నమోదు")
val status = responseObj.getString("status")
if (status == "success" && lang=="telugu") {
val message = responseObj.getString("response")
val token = responseObj.getString("token")
val prefs = SharedPrefs(this#TReg3)
prefs.token = (token)
if (userImage.isNotEmpty()) {
fileUpload()
} else {
showSuccessDialog(message)
dialog.dismiss()
}
} else {
next.hideProgress("నమోదు")
val message = responseObj.getString("response")
showCustomAlertDialog(message)
dialog.dismiss()
}
} else {
next.hideProgress("నమోదు")
showCustomAlertDialog("Something went wrong")
dialog.dismiss()
}
} catch (ex: Exception) {
next.hideProgress("నమోదు")
showCustomAlertDialog("Something went wrong")
dialog.dismiss()
}
},
Response.ErrorListener { error ->
next.hideProgress("ప్రవేశించండి")
val errorMessage = VolleyErrorParser.getVolleyErrorMessage(error)
showCustomAlertDialog(errorMessage)
dialog.dismiss()
}) {
override fun getHeaders(): MutableMap<String, String> {
val params = java.util.HashMap<String, String>()
params["Content-Type"] = "application/json"
return params
}
override fun getBody(): ByteArray {
return jsonObject.toString().toByteArray()
}
}
MySingleton.getInstance(this).addToRequestQueue(request)
}
}
private fun getDistrictData() {
val url = Constant.BASE_URL + "getDistricts/"
Log.e("districteUrl", url)
val request = StringRequest(Request.Method.GET, url, { response ->
try {
if (!response.isNullOrEmpty()) {
val jsonObject = JSONObject(response)
val status = jsonObject.getString("status")
if (status == "success") {
val data = jsonObject.getJSONArray("districts")
districtData = listOf(
*Gson().fromJson(
data.toString(),
Array<DistrictData>::class.java
)
)
if (districtData!!.isNotEmpty()) {
val categoryDataAdapter = ArrayAdapter<DistrictData>(
this,
android.R.layout.simple_list_item_1,
districtData!!)
categoryDataAdapter.setDropDownViewResource(android.R.layout.simple_list_item_1)
spDistrict.adapter = categoryDataAdapter
// getMandalData()
} else {
dialog.dismiss()
val response = jsonObject.getString("response")
Toast.makeText(this, response, Toast.LENGTH_SHORT).show()
}
} else {
dialog.dismiss()
val response = jsonObject.getString("response")
Toast.makeText(this, response, Toast.LENGTH_SHORT).show()
}
} else {
dialog.dismiss()
Toast.makeText(this, "Something Went Wrong", Toast.LENGTH_SHORT).show()
}
} catch (ex: Exception) {
Toast.makeText(this, "Something Went Wrong", Toast.LENGTH_SHORT).show()
dialog.dismiss()
ex.printStackTrace()
}
}, { error ->
dialog.dismiss()
val errorMessage = VolleyErrorParser.getVolleyErrorMessage(error)
Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT).show()
})
VolleySingleton.getInstance(this!!).addToRequestQueue(request)
}
}
How do I make my app automatically detetct the Telugu text? Do I have to use a flag value?
I am using Firebase PhoneAuth for user registration with my app. Users are verified successfully and started using the app without any issues. But, It happened to me a couple of times that user details vanished from Firestore database, not all users details have gone though. When I check the collection users in the Firestore, the document does exist for the user but some data was gone, in fact, it's overwritten the old data as if this is new user registration (However, the User UID under the Authentication is remain same). For example, the default value is user_type = "customer", as you can see in the fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential). Later I change this value accordingly to my need and when this issue happens the changes I made to this field and other fields are changed back to the default values.
Following is the code in my SignInWithPhone which will be called from the SplashScreen
class SigninWithPhoneActivity: BaseActivity() {
private lateinit var binding: ActivitySignInWithPhoneBinding
private lateinit var mAuth: FirebaseAuth
var code = ""
var number = ""
var phoneNumber = ""
var storedOtpID = ""
private lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySignInWithPhoneBinding.inflate(layoutInflater)
setContentView(binding.root)
}
mAuth = FirebaseAuth.getInstance()
binding.btnGetOtp.setOnClickListener {
code = binding.etCountryCode.text.toString().trim()
number = binding.etMobileNumber.text.toString().trim()
phoneNumber = code + number
if (number.isNotEmpty()) {
binding.etMobileNumber.isEnabled = false
binding.flOtp.visibility = View.VISIBLE
binding.btnGetOtp.visibility = View.GONE
binding.btnSignIn.visibility = View.VISIBLE
sendVerificationCode(phoneNumber)
} else {
Toast.makeText(this, "Please enter a valid mobile number", Toast.LENGTH_LONG).show()
}
}
binding.btnSignIn.setOnClickListener {
val otp = binding.etOtp.text.toString().trim()
if (otp.isNotEmpty() || otp.length != 6) {
verifyVerificationCode(otp)
} else {
Toast.makeText(this, "Please enter the OTP received through SMS", Toast.LENGTH_LONG)
.show()
}
}
}
private val mCallBack: PhoneAuthProvider.OnVerificationStateChangedCallbacks =
object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
val code = credential.smsCode
if (code != null) {
binding.etOtp.setText(code)
binding.pbOtp.visibility = View.GONE
}
}
override fun onVerificationFailed(p0: FirebaseException) {
binding.etMobileNumber.isEnabled = true
binding.flOtp.visibility = View.GONE
binding.btnGetOtp.visibility = View.VISIBLE
binding.btnSignIn.visibility = View.GONE
Toast.makeText(this#SigninWithPhoneActivity, "Login Failed", Toast.LENGTH_LONG)
.show()
}
override fun onCodeSent(otpID: String, token: PhoneAuthProvider.ForceResendingToken) {
super.onCodeSent(otpID, token)
Toast.makeText(
this#SigninWithPhoneActivity,
"OTP is send to your number",
Toast.LENGTH_LONG
).show()
storedOtpID = otpID
resendToken = token
}
}
private fun sendVerificationCode(phoneNumber: String) {
binding.pbOtp.visibility = View.VISIBLE
Toast.makeText(this#SigninWithPhoneActivity, "Sending OTP", Toast.LENGTH_LONG).show()
val options = PhoneAuthOptions.newBuilder(mAuth!!)
.setPhoneNumber(phoneNumber)
.setTimeout(60L, TimeUnit.SECONDS)
.setActivity(this)
.setCallbacks(mCallBack)
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
private fun verifyVerificationCode(code: String) {
Toast.makeText(
this#SigninWithPhoneActivity,
"Verifying credentials",
Toast.LENGTH_LONG
).show()
val credential = PhoneAuthProvider.getCredential(storedOtpID, code)
signInWithPhoneAuthCredential(credential)
}
private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
val firebaseUser: FirebaseUser = task.result!!.user!!
val userPreliminaryDetails = User(
firebaseUser.uid,
user_type = "customer",
mobile = binding.etMobileNumber.text.toString()
)
FirestoreClass().checkIfUserAlreadyExist(
this#SigninWithPhoneActivity,
firebaseUser.uid,
userPreliminaryDetails
)
} else {
showErrorSnackBar(task.exception!!.message.toString(), true)
if (task.exception is FirebaseAuthInvalidCredentialsException) {
binding.etMobileNumber.isEnabled = true
binding.flOtp.visibility = View.GONE
binding.etOtp.text?.clear()
binding.btnGetOtp.visibility = View.VISIBLE
binding.btnGetOtp.text = "Resend OTP"
binding.btnSignIn.visibility = View.GONE
Toast.makeText(this, "OTP entered is wrong", Toast.LENGTH_LONG).show()
}
}
}
}
fun userRegistrationSuccess() {
finish()
startActivity(Intent(this, ServiceAreaActivity::class.java))
Toast.makeText(this, "Signed Up successful", Toast.LENGTH_LONG).show()
}
fun userSignInSuccess() {
finish()
startActivity(Intent(this, ServiceAreaActivity::class.java))
Toast.makeText(this, "Signed in successfully", Toast.LENGTH_LONG).show()
}
}
EDIT:
The following function is called to check if the user already exists and accordingly sign in or register a new user.
fun checkIfUserAlreadyExist(
activity: SigninWithPhoneActivity, userId: String, userDetails: User
) {
mFireStore.collection("users")
.whereEqualTo(Constants.USER_ID, userId)
.get()
.addOnSuccessListener { document ->
if (document.documents.size > 0) {
activity.userSignInSuccess()
} else {
FirestoreClass().registerUser(activity, userDetails)
}
}
.addOnFailureListener { e ->
}
}
private fun registerUser(activity: SigninWithPhoneActivity, userInfo: User) {
mFireStore.collection(Constants.USERS)
.document(userInfo.user_id)
.set(userInfo, SetOptions.merge())
.addOnSuccessListener {
activity.userRegistrationSuccess()
}
.addOnFailureListener { e ->
activity.hideProgressDialog()
}
}
I had Enabled the Google Android Device Verification API.
I had added the SHA-256 onto Firebase setting and updated the GSON file.
and After adding :
Firebase.auth.firebaseAuthSettings.setAppVerificationDisabledForTesting(true)
I am getting error that SafetyNet or Captcha are not succeded (kind of error).
Can anyone tell me how can i disable the captcha check ?
Here is my code
class OTPNewActivity : AppCompatActivity(), OnKeyboardVisibilityListener, View.OnClickListener {
var TAG = "OTPNewActivity"
lateinit var binding: ActivityOtpnewBinding
val action = "android.provider.Telephony.SMS_RECEIVED"
var userEnteredCode = ""
var systemGeneratedCode = ""
var phoneNumer = ""
var phoneDigits = ""
private lateinit var auth: FirebaseAuth
private lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
private var callbacks: PhoneAuthProvider.OnVerificationStateChangedCallbacks =
object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
Log.d(TAG, "onVerificationCompleted: $credential")
val code = credential.smsCode
if (code != null) {
binding.otpView.setText(code)
verifyPhoneNumberWithCode(systemGeneratedCode, code!!)
}
}
override fun onVerificationFailed(e: FirebaseException) {
Log.d(TAG, "onVerificationFailed $e")
if (e is FirebaseAuthInvalidCredentialsException) {
Constants.showToast(
this#OTPNewActivity,
Constants.TOAST_TYPE_FAIL,
"Invalid request"
)
} else if (e is FirebaseTooManyRequestsException) {
Constants.showToast(
this#OTPNewActivity,
Constants.TOAST_TYPE_FAIL,
"The SMS quota for the project has been exceeded $e"
)
} else {
Constants.showToast(
this#OTPNewActivity,
Constants.TOAST_TYPE_FAIL, "Something wents wrong"
)
}
}
override fun onCodeSent(
verificationId: String,
token: PhoneAuthProvider.ForceResendingToken
) {
// The SMS verification code has been sent to the provided phone number, we
// now need to ask the user to enter the code and then construct a credential
// by combining the code with a verification ID.
Log.d(TAG, "onCodeSent: $verificationId")
systemGeneratedCode = verificationId
resendToken = token
countdownTimer()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_otpnew)
initListeners()
}
private fun initListeners() {
LocalSharedPreference.getInstance(this).isPhoneNumberVerified = false
// Firebase.auth.firebaseAuthSettings.setAppVerificationDisabledForTesting(true)
auth = Firebase.auth
setKeyboardVisibilityListener(this)
binding.btnNext.setOnClickListener(this)
binding.tvCount.setOnClickListener(this)
binding.icBack.setOnClickListener(this)
val intent = intent
intent?.let {
phoneNumer = intent.getStringExtra(Constants.PHONE_NUMBER).toString()
phoneDigits = intent.getStringExtra(Constants.SAVE_PHONE_DIGITS).toString()
binding.textView.text =
"${this.resources.getString(R.string.digit_code)} $phoneNumer"
val options = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber(phoneNumer)
.setTimeout(15L, TimeUnit.SECONDS)
.setActivity(this)
.setCallbacks(callbacks)
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
binding.otpView.setOtpCompletionListener(OnOtpCompletionListener { otp -> // do Stuff
userEnteredCode = otp
binding.icNext.visibility = View.VISIBLE
binding.pbNext.visibility = View.GONE
verifyPhoneNumberWithCode(systemGeneratedCode, userEnteredCode)
})
}
private fun verifyPhoneNumberWithCode(verificationId: String?, code: String) {
try {
val credential = PhoneAuthProvider.getCredential(verificationId!!, code)
signInWithPhoneAuthCredential(credential);
} catch (e: Exception) {
binding.otpView.setText("")
Constants.showToast(
this#OTPNewActivity,
Constants.TOAST_TYPE_FAIL,
this#OTPNewActivity.resources.getString(R.string.wrong_Code)
)
e.printStackTrace()
}
}
private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
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")
LocalSharedPreference.getInstance(this).isPhoneNumberVerified = true
if (phoneNumer.contains("+52")) {
LocalSharedPreference.getInstance(this).setSaveCountry("MX")
} else if (phoneNumer.contains("+92")) {
LocalSharedPreference.getInstance(this).setSaveCountry("PK")
} else if (phoneNumer.contains("+1")) {
LocalSharedPreference.getInstance(this).setSaveCountry("US")
}
LocalSharedPreference.getInstance(this).savePhoneNumber(phoneNumer)
LocalSharedPreference.getInstance(this).setPhoneDigits(phoneDigits)
val user = task.result?.user
val intent = Intent(this#OTPNewActivity, ProfileActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
startActivity(intent)
finish()
} else {
// Sign in failed, display a message and update the UI
Log.w(TAG, "signInWithCredential:failure", task.exception)
if (task.exception is FirebaseAuthInvalidCredentialsException) {
Constants.showToast(
this#OTPNewActivity,
Constants.TOAST_TYPE_FAIL,
"${task.exception}"
)
}
// Update UI
}
}
}
private fun setKeyboardVisibilityListener(onKeyboardVisibilityListener: OnKeyboardVisibilityListener) {
val parentView: View = (findViewById<View>(android.R.id.content) as ViewGroup).getChildAt(0)
parentView.getViewTreeObserver()
.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
private var alreadyOpen = false
private val defaultKeyboardHeightDP = 100
private val EstimatedKeyboardDP =
defaultKeyboardHeightDP + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 48 else 0
private val rect: Rect = Rect()
override fun onGlobalLayout() {
val estimatedKeyboardHeight = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
EstimatedKeyboardDP.toFloat(),
parentView.getResources().getDisplayMetrics()
)
.toInt()
parentView.getWindowVisibleDisplayFrame(rect)
val heightDiff: Int =
parentView.getRootView().getHeight() - (rect.bottom - rect.top)
val isShown = heightDiff >= estimatedKeyboardHeight
if (isShown == alreadyOpen) {
Log.d("Keyboard state", "Ignoring global layout change...")
return
}
alreadyOpen = isShown
onKeyboardVisibilityListener.onVisibilityChanged(isShown)
}
})
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Checks whether a hardware keyboard is available
if (newConfig.hardKeyboardHidden === Configuration.HARDKEYBOARDHIDDEN_NO) {
Toast.makeText(this, "keyboard visible", Toast.LENGTH_SHORT).show()
} else if (newConfig.hardKeyboardHidden === Configuration.HARDKEYBOARDHIDDEN_YES) {
Toast.makeText(this, "keyboard hidden", Toast.LENGTH_SHORT).show()
}
}
override fun onVisibilityChanged(visible: Boolean) {
if (!visible) {
val imm: InputMethodManager =
getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(binding.otpView, InputMethodManager.SHOW_IMPLICIT)
}
}
override fun onResume() {
super.onResume()
binding.otpView.requestFocus()
val imm: InputMethodManager =
getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(binding.otpView, InputMethodManager.SHOW_IMPLICIT)
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
registerReceiver(receiver, IntentFilter(action))
}
private fun countdownTimer() {
binding.pbNext.visibility = View.VISIBLE
binding.icNext.visibility = View.GONE
object : CountDownTimer(15000, 1000) {
override fun onTick(millisUntilFinished: Long) {
binding.tvCount.setText("Resend Code in : " + millisUntilFinished / 1000)
}
override fun onFinish() {
binding.tvCount.setText("I didn`t receive a code")
binding.icNext.visibility = View.VISIBLE
binding.pbNext.visibility = View.GONE
}
}.start()
}
override fun onClick(view: View) {
when (view.id) {
R.id.btn_next -> {
if (binding.otpView.text.toString().length == 6) {
LocalSharedPreference.getInstance(this#OTPNewActivity).isPhoneNumberVerified =
true
verifyPhoneNumberWithCode(systemGeneratedCode, userEnteredCode)
}
}
R.id.tv_count -> {
if (binding.tvCount.text.equals(this#OTPNewActivity.resources.getString(R.string.i_dont_received_code)))
resendVerificationCode(phoneNumer, resendToken)
}
R.id.ic_back -> {
finish()
}
}
}
private fun resendVerificationCode(
phoneNumber: String,
token: PhoneAuthProvider.ForceResendingToken?
) {
val optionsBuilder = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber(phoneNumber) // Phone number to verify
.setTimeout(15L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this) // Activity (for callback binding)
.setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
if (token != null) {
optionsBuilder.setForceResendingToken(token) // callback's ForceResendingToken
}
PhoneAuthProvider.verifyPhoneNumber(optionsBuilder.build())
}
var receiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
if (intent.action == "android.provider.Telephony.SMS_RECEIVED") {
val bundle = intent.extras
var msgs: Array<SmsMessage?>? = null
var msg_from: String? = ""
Log.d(TAG, "onReceive called ")
if (bundle != null) {
try {
val pdus = bundle["pdus"] as Array<Any>?
msgs = arrayOfNulls(pdus!!.size)
for (i in msgs.indices) {
msgs[i] = SmsMessage.createFromPdu(pdus[i] as ByteArray)
msg_from = msgs[i]!!.getOriginatingAddress()
val msgBody: String = msgs[i]!!.getMessageBody()
if (msgBody.contains("is your verification code for running-errands.firebaseapp.com")) {
val _1: Char = msgBody[0]
val _2: Char = msgBody[1]
val _3: Char = msgBody[2]
val _4: Char = msgBody[3]
val _5: Char = msgBody[4]
val _6: Char = msgBody[5]
val code: String =
_1.toString() + _2.toString() + _3.toString() + _4.toString() + _5.toString() + _6.toString()
// binding.otpView.text = SpannableStringBuilder(code!!)
binding.otpView.setText(code)
verifyPhoneNumberWithCode(systemGeneratedCode, code!!)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(receiver);
}
}
I'm trying to get the user info with this code but is not showing on the activity
The profile picture and the name are not creating a new user on the base
What am I missing?
Does anyone had coded this using Kotlin?
private fun handleFacebookAccessToken(token: AccessToken) {
Log.d(TAG, "handleFacebookAccessToken:" + token)
val credential = FacebookAuthProvider.getCredential(token.token)
App.currentAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { Log.d(TAG, "signInWithCredential:success") }
.addOnSuccessListener(this) { authResult ->
if (authResult != null) {
val firebaseUser = authResult.user
if (App.database_table_users.child(firebaseUser.uid) == null) {
var facebookId = ""
firebaseUser.providerData
.filter { it.providerId == FacebookAuthProvider.PROVIDER_ID }
.forEach { facebookId = it.uid }
val photoUrl = "https://graph.facebook.com/$facebookId/picture?width=1024&height=1024"
App.database_table_users.child(firebaseUser.uid).setValue(
User(firebaseUser.uid,
firebaseUser.email.orEmpty(),
firebaseUser.displayName.orEmpty(),
photoUrl,
false
)
)
}
}
}
.addOnFailureListener(this) { ex ->
if (ex is FirebaseAuthUserCollisionException) {
LoginManager.getInstance().logOut()
val ad = AlertDialog.Builder(this#LoginActivity)
ad.setMessage(getString(R.string.auth_user_collision))
ad.setPositiveButton(getString(R.string.ok), null)
ad.show()
} else {
ex.printStackTrace()
}
}
}
You must use FirebaseAuth.getInstance() instead of App.currentAuth.
For example;
val mAuth = FirebaseAuth.getInstance()
val credential = FacebookAuthProvider.getCredential(token)
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
val user = mAuth.currentUser
} else {
task.exception?.printStackTrace()
}
}
Try This it's work for me
private fun loginWithFaceBook()
{
LoginManager.getInstance().registerCallback(callbackManager, facebookCallBack)
LoginManager.getInstance().logInWithReadPermissions(this, Arrays.asList("public_profile","email"))
}
private val facebookCallBack = object : FacebookCallback<LoginResult> {
override fun onSuccess(result: LoginResult?) {
val graphRequest = GraphRequest.newMeRequest(result?.accessToken) { _, response ->
val graphObject = response.jsonObject
val id = if(graphObject.has("id")) graphObject.getString("id") else null
val email = if(graphObject.has("email")) graphObject.getString("email") else null
val firstName = if(graphObject.has("first_name")) graphObject.getString("first_name") else null
val lastName = if(graphObject.has("last_name")) graphObject.getString("last_name") else null
val photoUrl = if(graphObject.has("picture")) {
val picture : JSONObject = graphObject.getJSONObject("picture")
if(picture.has("data") && picture.has("url") && picture.getString("url").isNotBlank()) {
picture.getString("url")
}
else
null
}
else
val bundle = Bundle()
bundle.putString("fields", "id,first_name,last_name,name,picture,email,gender,birthday,link")
graphRequest.parameters = bundle
graphRequest.executeAsync()
}
override fun onError(error: FacebookException) {
when{
error.message != null -> showSnackbar(error.message.toString())
}
}
override fun onCancel() {
}
}