Android: Firebase Anonymous Authentication - android

When using anonymous authentication with firebase, the first time the app is launched from android studio (if it's uninstalled), a firebase account is created as intended, but the firebase database references don't connect. Only when launching the app a second time, the references work as intended and I can upload and retrieve data with my code. I'm guessing some stuff isn't initialized properly.
My code for anonymous authentication
class MainActivity : AppCompatActivity() {
var challenges = ArrayList<Challenge?>()
val recyclerViewAdapter = RecyclerViewAdapter(challenges)
var currentChallengeActive: Boolean = false
companion object{
var mAuth: FirebaseAuth? = FirebaseAuth.getInstance()
val userId = mAuth?.currentUser?.uid
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mAuth = FirebaseAuth.getInstance()
startService(Intent(this, MyService::class.java))
setFragment()
val currentUser = mAuth?.currentUser
if (currentUser == null){
anonymousLogin()
}
private fun anonymousLogin() {
mAuth?.signInAnonymously()?.addOnCompleteListener { task ->
if (task.isSuccessful) {
Snackbar.make(
findViewById(R.id.constraint_layout),
"Logged in anonymously",
Snackbar.LENGTH_SHORT
).show()
} else {
Toast.makeText(this, "Login fehlgeschlagen", Toast.LENGTH_SHORT).show()
}
}
}
My firebase references
class FirebaseConfig {
companion object{
var database: FirebaseDatabase? = null
var myRootRef: DatabaseReference? = null
var completedChallengesRef: DatabaseReference? = null
var openChallengesRef: DatabaseReference? = null
var swappedChallengesRef: DatabaseReference? = null
init {
database = FirebaseDatabase.getInstance()
myRootRef = userId?.let { database?.getReference("users")?.child(it) }
completedChallengesRef = userId?.let { database?.getReference("users")?.child(it)?.child("completed") }
openChallengesRef = userId?.let { database?.getReference("users")?.child(it)?.child("open") }
swappedChallengesRef = userId?.let { database?.getReference("users")?.child(it)?.child("swapped") }
}
}
}

Related

How to handle those specific exceptions from repository? (Android Kotlin)

I'm new to android and I'm developing a few applications for studying.
I've been trying to improve a code that I have but I got stuck in the following problem:
I'm creating a new user, validating it with Google Firebase. I managed to create a user normally but I'm not able to handle with one exception from the register moment which is the "FirebaseAuthUserCollisionException".
I created a class to handle a most of exceptions from email/password mistakes:
class AddUser(private val repository: UserRepository) {
#Throws(InvalidUserException::class)
suspend operator fun invoke(user: UserModel) {
if(user.email.isEmpty()) {
throw InvalidUserException("Email cannot be empty")
}
if(!Patterns.EMAIL_ADDRESS.matcher(user.email).matches()) {
throw InvalidUserException("Email is not valid")
}
if(user.password.length <= 5) {
throw InvalidUserException("Password should contain at least 6 characters")
}
if(user.password.isEmpty()) {
throw InvalidUserException("Password cannot be empty")
}
if(user.confirmPassword.isEmpty()) {
throw InvalidUserException("Confirm password cannot be empty")
}
if(user.password != user.confirmPassword) {
throw InvalidUserException("Passwords does not match")
}
repository.insert(user)
}
}
My repository:
class UserRepositoryImpl: UserRepository {
private var auth: FirebaseAuth = Firebase.auth
private var database: DatabaseReference = FirebaseDatabase.getInstance().getReference("users")
override suspend fun insert(user: UserModel) {
auth = FirebaseAuth.getInstance()
auth.createUserWithEmailAndPassword(user.email, user.password).addOnCompleteListener {
if(it.isSuccessful) {
database.child(user.id.toString()).setValue(user)
} else {
//exception here
}
}
}
}
When this function is triggered, it navigates to another fragment and toasts the successful message, which is incorrect because the exception happens.
Fragment:
private fun configEventFlow() = lifecycleScope.launch {
viewModel.eventFlow.collectLatest { event ->
when(event) {
is RegisterViewModel.UiEvent.ShowToast -> {
toast(event.message)
}
is RegisterViewModel.UiEvent.SaveUser -> {
val action = RegisterFragmentDirections.actionRegisterFragmentToMainFragment()
findNavController().navigate(action)
toast(getString(R.string.register_successfully))
}
}
}
}
private fun configUserRegistration() = with(binding) {
fabRegister.setOnClickListener {
val email = editRegisterEmail.text.toString()
viewModel.onEvent(RegisterUserEvents.EnteredEmail(email))
val password = editRegisterPassword.text.toString()
viewModel.onEvent(RegisterUserEvents.EnteredPassword(password))
val confirmPassword = editRegisterPasswordConfirm.text.toString()
viewModel.onEvent(RegisterUserEvents.EnteredConfirmPassword(confirmPassword))
viewModel.onEvent(RegisterUserEvents.SaveUser)
}
}
ViewModel:
#HiltViewModel
class RegisterViewModel #Inject constructor(private val useCases: UserUseCases): ViewModel() {
private val _email = MutableStateFlow<ResourceState<String>>(ResourceState.Empty())
private val email: StateFlow<ResourceState<String>> = _email
private val _password = MutableStateFlow<ResourceState<String>>(ResourceState.Empty())
private val password: StateFlow<ResourceState<String>> = _password
private val _confirmPassword = MutableStateFlow<ResourceState<String>>(ResourceState.Empty())
private val confirmPassword: StateFlow<ResourceState<String>> = _confirmPassword
private val _eventFlow = MutableSharedFlow<UiEvent>()
val eventFlow = _eventFlow.asSharedFlow()
fun onEvent(event: RegisterUserEvents) {
when(event) {
is RegisterUserEvents.EnteredEmail -> {
_email.value = ResourceState.Success(event.value)
}
is RegisterUserEvents.EnteredPassword -> {
_password.value = ResourceState.Success(event.value)
}
is RegisterUserEvents.EnteredConfirmPassword -> {
_confirmPassword.value = ResourceState.Success(event.value)
}
is RegisterUserEvents.SaveUser -> {
viewModelScope.launch {
try {
useCases.addUser(
UserModel(
id = System.currentTimeMillis().toInt(),
email = email.value.data!!,
password = password.value.data!!,
confirmPassword = confirmPassword.value.data!!
)
)
_eventFlow.emit(UiEvent.SaveUser)
} catch(e: InvalidUserException) {
_eventFlow.emit(UiEvent.ShowToast(message = e.message!!))
}
}
}
}
}
sealed class UiEvent {
data class ShowToast(val message: String): UiEvent()
object SaveUser: UiEvent()
}
}
Is there a way that I can manage this specific exception in this pattern? Even if I catch the exception there, the action is completed and my application follows at it was registered but in the database it does not occur because of the exception. Im sure that I'll have to face it again when login to handle specific exceptions from Firebase, which I cannot create this way but I have to receive them and display to the user.
Any suggestions??
Sorry if it's missing any content, tell me and I update asap.
Thanks in advance.

How to fetch data Firestore subcollection Kotlin?

I want to get data from Firebase Firestore subcollection for recyclerView. But I dont know if I write codes correctly or no. I also checked another variant with another collection without any subcollection and I see there I succesfully get data from Firestore. But with subcollection part which is i uploaded it with image below I can not fetch data and my recyclerView is empty.How can i fix that? Thanks in advance
Here is my Firebase Firestore collection
Here is my Firebase Firestore subcollection
And my codes
class Posts : AppCompatActivity(), RecAdapterPosts.ClickListener {
var modalList : ArrayList<ModalImageList> = ArrayList()
private lateinit var binding: PostsBinding
private lateinit var auth: FirebaseAuth
private var userAdapter = RecAdapterPosts(modalList, this)
private var db = Firebase.firestore
private var database: FirebaseFirestore = FirebaseFirestore.getInstance()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = PostsBinding.inflate(layoutInflater)
val view = (binding.root)
setContentView(view)
auth = FirebaseAuth.getInstance()
database = FirebaseFirestore.getInstance()
gridPosts.adapter = userAdapter
gridPosts.layoutManager = GridLayoutManager(this,2)
get_information()
}
private fun get_information() {
val cu = auth.currentUser!!.uid
database.collection("İmagesPosts",).document(cu!!).collection("ImagesList").orderBy("date",
Query.Direction.DESCENDING
).addSnapshotListener { snaphot, exception ->
if (exception != null) {
Toast.makeText(this, exception.localizedMessage, Toast.LENGTH_LONG)
.show()
} else {
if (snaphot != null) {
if (!snaphot.isEmpty) {
val documents = snaphot.documents
modalList.clear()
for (document in documents) {
val imgUrl = document.get("downloadUs") as String
val imgName = document.get("imgName") as String
val download_post = ModalImageList(
imgUrl,
imgName,
)
modalList.add(download_post)
}
}
userAdapter.notifyDataSetChanged()
}
}
}
}

Android : Firebase current user returning null even if I've logged in before

I'm implementing SignIn with Google on my app, the sign it works, but now I'm planning to on my SplashActivity check if someone is logged in to the app or not to show either the login or the home page.
So I've planned like this :
This is my ViewModel:
class SplashViewModel #Inject constructor(
private val authenticatedUserRepository: AuthenticatedUserRepository
) : ViewModel() {
private val _splashViewState =
MutableLiveData<SplashViewState>()
val splashViewState: LiveData<SplashViewState>
get() = _splashViewState
private lateinit var userAuthenticated: LiveData<FirebaseUser>
fun checkIfUserIsAuthenticatedInFirebase() {
userAuthenticated = authenticatedUserRepository.isLogged()
if (userAuthenticated.value == null) {
_splashViewState.postValue(SplashViewState.UserNotAuthenticated)
} else {
_splashViewState.postValue(SplashViewState.UserAuthenticated)
}
}
}
sealed class SplashViewState {
object UserAuthenticated : SplashViewState()
object UserNotAuthenticated : SplashViewState()
}
And this is my repository
interface AuthenticatedUserRepository {
fun isLogged(): MutableLiveData<FirebaseUser>
}
class AuthenticatedUserRepositoryImpl #Inject constructor(private val firebaseAuth: FirebaseAuth) :
AuthenticatedUserRepository {
override fun isLogged(): MutableLiveData<FirebaseUser> {
val authenticatedUser: MutableLiveData<FirebaseUser> =
MutableLiveData()
val currentUser = firebaseAuth.currentUser
if (currentUser != null) authenticatedUser.postValue(currentUser)
else authenticatedUser.postValue(null)
return authenticatedUser
}
}
And the thing is always I'm returning null, even if I've logged in and closed the app and open again.
I've also read the medium post from #AlexMamo but he's using Firestore to check if the user is registered or not, is it possible to use my own backend to make it free?
You do not need to return a MutableLiveData<FirebaseUser>, you can just return the FirebaseUser and on your view-model, you just check if that's null or not.
fun checkIfUserIsAuthenticatedInFirebase() {
val firebaseUser = authenticatedUserRepository.isLogged()
if (firebaseUser == null) {
_splashViewState.postValue(SplashViewState.UserNotAuthenticated)
} else {
_splashViewState.postValue(SplashViewState.UserAuthenticated)
}
}
And your Repository
interface AuthenticatedUserRepository {
fun isLogged(): FirebaseUser?
}
class AuthenticatedUserRepositoryImpl #Inject constructor(private val firebaseAuth: FirebaseAuth) :
AuthenticatedUserRepository {
override fun isLogged() = firebaseAuth.currentUser
}
And it should work.

failed: DatabaseError: Permission denied Firebase the user is being created but database is not updating

This is account create activity : Here the user is being created but the unless i change the rules to read write rules to true the database is not getting updated.
I only want the users database who is authorized.
Please help
class CreateAccountActivity : AppCompatActivity() {
var mAuth: FirebaseAuth? = null
var mDatabase: DatabaseReference? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create_account)
mAuth = FirebaseAuth.getInstance();
idbuttonsignup.setOnClickListener{
var email = idemail.text.toString().trim()
var password = idpassword.text.toString().trim()
var displayName = iddisplayname.text.toString().trim()
if(!TextUtils.isEmpty(email) || !TextUtils.isEmpty(password) || !TextUtils.isEmpty(displayName)){
createAccount(email,password,displayName)
}else{
Toast.makeText(this,"Please fill out all the fields", Toast.LENGTH_LONG).show()
}
}
}
private fun createAccount(email: String, password: String, displayName: String){
mAuth!!.createUserWithEmailAndPassword(email,password)
.addOnCompleteListener{
task: Task<AuthResult> ->
if(task.isSuccessful){
var currentUserID = mAuth!!.currentUser
var userID = currentUserID!!.uid
Toast.makeText(this,"Task is sucessfull", Toast.LENGTH_LONG).show()
mDatabase = FirebaseDatabase.getInstance().reference.child("Users").child(userID)
var userObject = HashMap<String, String>()
userObject.put("display_name",displayName)
userObject.put("status", "Hello there...")
userObject.put("image", "default")
userObject.put("thumb_image","default")
mDatabase!!.setValue(userObject).addOnCompleteListener{
task: Task<Void> ->
if(task.isSuccessful){
var dashboardIntentOkc = Intent(this, DashboardActivity::class.java)
dashboardIntentOkc.putExtra( "name", displayName)
startActivity(dashboardIntentOkc)
finish()
Toast.makeText(this,"User Created", Toast.LENGTH_LONG).show()
}else{
Toast.makeText(this,"User Not Created", Toast.LENGTH_LONG).show()
}
}
}
}
}
}
_______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ please help
Have you define the rules in the Firebase Database for read and write operations. Check the Firebase official page if not.
Get Started with Database Rules

Database exception while displaying Chatlist in Android Kotlin Chat app

I have been developing a chatting app in Android using Kotlin and Firebase. Registering, searching and sending message to a user, all of this has been successful. But I'm unable to generate a chatlist which is a list of the recent chats of the user. The user can tap on it to access that particular chat, just like any other chatting app.
The user is stored in a User model and the data is registered in the database in that same format.
I am able to display the profile picture of the user using the addValueEventListener method but when the similar method is invoked for the chatlist, it throws an error -
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type kushwaha.samir.boop.models.User
This is the code where the error occurs -
val user = snapshot.getValue<User>(User::class.java!!)
present in the function - chatList()
Database view
MainActivityChat code >
class MainActivityChat : Fragment() {
lateinit var profile_image: CircleImageView
lateinit var firebaseUser: FirebaseUser
lateinit var reference: DatabaseReference
lateinit var referenceusers: DatabaseReference
lateinit var referenceuserschats: DatabaseReference
lateinit var referencechatlist: DatabaseReference
var root: View? = null
lateinit var auth: FirebaseAuth
lateinit var fragment: Fragment
var recyclerView: RecyclerView? = null
var userAdapter: UserAdapter? = null
var mUsers: MutableList<User>? = null
var fuser: FirebaseUser?=null
private var usersList: MutableList<Chatlist>? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
root = inflater.inflate(R.layout.activity_mainchat, container, false)
setHasOptionsMenu(true)
firebaseUser = FirebaseAuth.getInstance().currentUser!!
val uid = firebaseUser.uid
val floatingActionButton = root!!.findViewById(R.id.searchPerson) as FloatingActionButton
floatingActionButton.setOnClickListener {
val intent = Intent(activity, SearchActivity::class.java)
startActivity(intent)
}
fuser = FirebaseAuth.getInstance().currentUser!!
usersList = ArrayList()
reference = FirebaseDatabase.getInstance().getReference("Chatlist").child(fuser!!.uid)
referencechatlist = FirebaseDatabase.getInstance().getReference("Chatlist").child(fuser!!.uid)
profile_image = root!!.findViewById(R.id.profile_image)
firebaseUser = FirebaseAuth.getInstance().currentUser!!
FirebaseDatabase.getInstance().reference.child("Users").child(uid)
.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val user = dataSnapshot.getValue(User::class.java)
// usernamedisplay.text = user!!.username
if (user!!.profileImageUrl == "default") {
profile_image.setImageResource(R.mipmap.ic_launcher)
Log.d(ProfileFragment.TAG, "No image retrieved/found")
} else {
//change this
context?.let { Glide.with(it).load(user.profileImageUrl).into(profile_image) }!!
Log.d(ProfileFragment.TAG, "Image set")
}
}
override fun onCancelled(databaseError: DatabaseError) {
}
})
reference = FirebaseDatabase.getInstance().getReference("Chats")
reference.addValueEventListener(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
var unread = 0
for (snapshot in dataSnapshot.children) {
val chat = snapshot.getValue<Chat>(Chat::class.java!!)
if (chat!!.receiver == firebaseUser!!.uid && !chat!!.isIsseen!!) {
unread++
}
}
reference = FirebaseDatabase.getInstance().getReference("Chatlist").child(fuser!!.uid)
reference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
usersList!!.clear()
for (snapshot in dataSnapshot.children) {
val chatlist = snapshot.getValue<Chatlist>(Chatlist::class.java!!)
usersList!!.add(chatlist!!)
}
chatList()
}
override fun onCancelled(databaseError: DatabaseError) {
}
})
}
})
updateToken(FirebaseInstanceId.getInstance().token)
return root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView = view!!.findViewById(R.id.recycler_viewmain)
recyclerView!!.setHasFixedSize(true)
recyclerView!!.layoutManager = LinearLayoutManager(context)
}
private fun updateToken(token: String?) {
val reference = FirebaseDatabase.getInstance().getReference("Tokens")
val token1 = Token(token!!)
reference.child(fuser!!.uid).setValue(token1)
}
private fun chatList() {
mUsers = ArrayList()
reference = FirebaseDatabase.getInstance().getReference("Users")
reference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
mUsers!!.clear()
for (snapshot in dataSnapshot.children) {
**val user = snapshot.getValue<User>(User::class.java!!)**
for (chatlist in usersList!!) {
if (user!!.id == chatlist.id) {
mUsers!!.add(user)
}
}
}
userAdapter = UserAdapter(context!!, mUsers!!, true)
recyclerView!!.adapter = userAdapter
}
override fun onCancelled(databaseError: DatabaseError) {
}
})
}
private fun status(status: String) {
reference = FirebaseDatabase.getInstance().getReference("Users").child(firebaseUser!!.uid)
val hashMap = HashMap<String, Any>()
hashMap["status"] = status
reference.updateChildren(hashMap)
}
override fun onResume() {
super.onResume()
status("online")
}
override fun onPause() {
super.onPause()
status("offline")
}
companion object {
val TAG = "MainActivityChat"
}
}
User Model
class User {
var id: String? = null
var phoneno: String? = null
var profileImageUrl: String? = null
var search: String? = null
var status: String? = null
var username: String? = null
constructor(id: String, phoneno: String, profileImageUrl: String, search: String, status: String, username: String) {
this.id = id
this.phoneno = phoneno
this.profileImageUrl = profileImageUrl
this.search = search
this.status = status
this.username = username
}
constructor() {
}
}
Chatlist model
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
#Parcelize
class Chatlist(val id: String):
Parcelable {
constructor() : this("")
}
Logcat
2019-03-02 22:20:52.446 20562-20562/kushwaha.samir.boop E/AndroidRuntime: FATAL EXCEPTION: main
Process: kushwaha.samir.boop, PID: 20562
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type kushwaha.samir.boop.models.User
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(com.google.firebase:firebase-database##16.0.5:423)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(com.google.firebase:firebase-database##16.0.5:214)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(com.google.firebase:firebase-database##16.0.5:79)
at com.google.firebase.database.DataSnapshot.getValue(com.google.firebase:firebase-database##16.0.5:212)
at kushwaha.samir.boop.MainActivityChat$chatList$1.onDataChange(MainActivityChat.kt:187)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database##16.0.5:75)
at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database##16.0.5:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database##16.0.5:55)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6762)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
According to your comment, you say that when you try to log the content of your snapshot object you get:
{ key = status, value = offline }
Which obviously means that you are using a wrong reference. So you get that result because you are getting a reference in database for the status property which of type String and that's why you get that error:
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type kushwaha.samir.boop.models.User
To solve this, please change the following line of code:
reference.addValueEventListener(object : ValueEventListener {}
to
val rootRef = FirebaseDatabase.getInstance().getReference()
val usersRef = rootRef.child("Users")
usersRef.addValueEventListener(object : ValueEventListener {}

Categories

Resources