Let me describe the application im trying to do using Kotlin, on Android Studio.
Splash Screen => Login Screen => Main App
Splash Screen: Just a photo
Login Screen: Provides different ways of logging (Google, Facebook, etc)
MainActivity: Allows you to log off, in that case, you must return to "Login Screen"
So far I have been working only with Facebook Login.
I managed to place the button, make it work, and get a proper uid. The trouble is that, when that button is clicked, it automatically switches to "Log Out". So, when I go back from my MainActivity to my Login Screen, instead of having the button to Login again, im having a "Log Out" button, when account is actually already logged out.
Is there a way to prevent this button from changing? I have been reading tons of documentation, but havent found anything useful.
Is my idea incorrect? Or is there a better way to do this?
Note that everytime I Leave the LoginScreen, I place a finish(). The reason of this was to try to reset the activity, and make it work as if the program was running from scratch.
Variables defined on LoginScreen
private var mCallBackManager : CallbackManager?= null
private var mFirebaseAuth : FirebaseAuth?= null
On create function
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.lay_login_screen)
//-----------Inicializadores-Facebook---------------
mFirebaseAuth = FirebaseAuth.getInstance()
FacebookSdk.sdkInitialize(getApplicationContext())
mCallBackManager = CallbackManager.Factory.create()
//--------------------------------------------------
//-----------Boton-Facebook-------------------------
Button_LoginScreen_LoginFace.setOnClickListener()
{
iniciarSesionFacebook();
}
//--------------------------------------------------
}
private fun iniciarSesionFacebook()
{
Button_LoginScreen_LoginFace.registerCallback(mCallBackManager, object : FacebookCallback<LoginResult>
{
override fun onSuccess(result: LoginResult?)
{
d(getString(R.string.TAG_FacebookLogin),"Login Correct")
handleFacebookToken(result!!.accessToken)
}
override fun onCancel()
{
d(getString(R.string.TAG_FacebookLogin),"Login cancelled")
}
override fun onError(error: FacebookException?)
{
d(getString(R.string.TAG_FacebookLogin),"Login Error")
}
})
}
private fun handleFacebookToken(accessToken: AccessToken?)
{
val credential = FacebookAuthProvider.getCredential(accessToken!!.token)
mFirebaseAuth!!.signInWithCredential(credential).addOnFailureListener()
{error->
d(getString(R.string.TAG_FacebookLogin),"Error 1"+error.message)
}
.addOnSuccessListener { resultado->
startActivity(Intent(this, MainActivity::class.java))
finish()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
{
super.onActivityResult(requestCode, resultCode, data)
mCallBackManager!!.onActivityResult(requestCode,resultCode,data)
}
Finally, this is how I "Log Out" from MainActivity, and return to LoginScreen
class MainActivity : AppCompatActivity()
{
//----------Variables-Globales----------------
private var mFirebaseAuth : FirebaseAuth?= null
//--------------------------------------------
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//-------Inicializo-Variables------------------------
mFirebaseAuth = FirebaseAuth.getInstance()
//---------------------------------------------------
Button_MainActity_LogOf.setOnClickListener{
val firebaseaux=mFirebaseAuth
firebaseaux?.signOut()
startActivity(Intent(this, ActivityLoginScreen::class.java))
}
}
}
This is how the LoginScreen looks the first time is ran.
This is how it looks after manually logging of. Note that is not only the appearence of the code, the code itself changes. Now the button doesnt allow you to LogIn.
Just to add some extra information, i have found this property on the docs
Configuration: auto_logout_link
HTML5 Attribute: data-auto-logout-link
Description: If its activated, the button will be replaced by a LogOut button if the user has already logged in
Options: True,False
This es EXACTLY what im looking for. But, from what I can see, that is only ment for webpages and not android. Does somebody know how to touch this configuration in android? or the equivalent adroid option?
I will add the link where I found the property.
https://developers.facebook.com/docs/facebook-login/web/login-button/
Thanks in advance
Ok, after some time I managed to solve the Issue.
I was logging out from the Firebase Authentication, but not from Facebook authentication.
I didnt manage to stop the button from behaving like it does, but at least the behaviour now is correct.
I will share my new LogOut code.
Button_MainActity_LogOf.setOnClickListener{
FirebaseAuth.getInstance().signOut() //Log out from Firebase
if(isFacebookLogin()) //Check if logged in on facebook
{
LoginManager.getInstance().logOut() //Log out from facebook
}
//Here i should log out from other providers
startActivity(Intent(this, ActivityLoginScreen::class.java))
}
private fun isFacebookLogin(): Boolean
{
return AccessToken.getCurrentAccessToken() !=null
}
Related
hi guys i'm trying to do auto login in my app but before login done i wonder if the user verified his email or no.
the problem : even if i verified my account the code doesn't see this and said false.
and here is my code.
class SignInActivity : BaseActivity<SignInViewModel, ActivitySignInBinding>(), Navigator {
private lateinit var preferenceManger: PreferenceManger
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
preferenceManger = PreferenceManger(applicationContext)
autoLogin()
binding.vm = viewModel
viewModel.navigator = this
addPrefManger()
}
private fun autoLogin() {
DataUtils.firebaseUser = Firebase.auth.currentUser
if (preferenceManger.getBoolean(Constants.KEY_IS_SIGNED_IN)) {
when {
DataUtils.firebaseUser!!.isEmailVerified -> {
startActivity(Intent(this, HomeActivity::class.java))
finish()
}
else -> {
startActivity(Intent(this, VerificationActivity::class.java))
finish()
}
}
}
}
this line is always false even if i verified my account.
DataUtils.firebaseUser!!.isEmailVerified
While the verification status of the user profile is updated on the server as soon as they've clicked the link, it may take up to an hour before that information is synchronized to the Android app.
If you want to detect the email verification in the app before it is automatically synchronized, you can:
Sign the user out and in again.
Force reloading of the user profile (after the user has clicked the link) by calling reload on the user object. You can put a button in your UI to do this, or automatically call that, for example in the onResume of the activity.
Also see:
How to verify email without the need of signing in again while using FirebaseUI-auth?
Verification email activity not refreshing
ok I am working on concept idea my dad has pitched to me. I have an app that runs AdMobs. On the interstitial ads based off button. The idea of the app is you press the start button and you watch an ad. However, when the ad is closed out, the value should increase in the Ads Watched Field.
I have created a function that increases the TextView no problem. My issue is with AdMob functions, when I call the function in AdDismissed, it does not change the value. I can plug the function into the Start Button and it increases value, but when the Ad is dismissed it zeros out the textView.
I am showing the demo portion of the app, this is still experimental, but also learning with Admobs and the coding on functions. Any advice would be appreciated. Also the adCounter is in the stop button, that was just to make sure the increments where firing. Which it does work perfectly. My thing is when the ad ends keeping the value.
SO in example the Ads Watched: 167,897,256 should increment by one when the ad is dismissed. However placing adCount() in the dismissed section of the ad does not work it just zeros out that textView.
MainActivity
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.google.android.gms.ads.*
import com.google.android.gms.ads.interstitial.InterstitialAd
import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback
class MainActivity : AppCompatActivity() {
lateinit var mAdView : AdView
private var mInterstitialAd: InterstitialAd? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loadBanner()
loadInterAd()
val interAdBtnStart : Button = findViewById(R.id.btnStartAds)
val interAdBtnStop : Button = findViewById(R.id.btnStopAds)
interAdBtnStart.setOnClickListener {
showInterAd()
}
interAdBtnStop.setOnClickListener {
adCountInc()
}
}
fun adCountInc(){
val tvAdsAmount : TextView = findViewById(R.id.tvAdsAmount)
var i : Int = tvAdsAmount.text.toString().toInt()
tvAdsAmount.text = "${++i}"
}
private fun showInterAd() {
if (mInterstitialAd != null)
{
mInterstitialAd?.fullScreenContentCallback = object : FullScreenContentCallback(){
override fun onAdClicked() {
super.onAdClicked()
}
override fun onAdDismissedFullScreenContent() {
super.onAdDismissedFullScreenContent()
val intent = Intent(this#MainActivity, MainActivity::class.java)
startActivity(intent)
}
override fun onAdFailedToShowFullScreenContent(p0: AdError) {
super.onAdFailedToShowFullScreenContent(p0)
}
override fun onAdImpression() {
super.onAdImpression()
}
override fun onAdShowedFullScreenContent() {
super.onAdShowedFullScreenContent()
}
}
mInterstitialAd?.show(this)
}
else
{
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}
}
private fun loadInterAd() {
var adRequest = AdRequest.Builder().build()
InterstitialAd.load(this,"ca-app-pub-3940256099942544/1033173712", adRequest, object : InterstitialAdLoadCallback() {
override fun onAdFailedToLoad(adError: LoadAdError) {
mInterstitialAd = null
}
override fun onAdLoaded(interstitialAd: InterstitialAd) {
mInterstitialAd = interstitialAd
}
})
}
private fun loadBanner() {
MobileAds.initialize(this) {}
mAdView = findViewById(R.id.adView)
val adRequest = AdRequest.Builder().build()
mAdView.loadAd(adRequest)
mAdView.adListener = object: AdListener() {
override fun onAdLoaded() {
// Code to be executed when an ad finishes loading.
}
override fun onAdFailedToLoad(adError : LoadAdError) {
// Code to be executed when an ad request fails.
}
override fun onAdOpened() {
// Code to be executed when an ad opens an overlay that
// covers the screen.
}
override fun onAdClicked() {
// Code to be executed when the user clicks on an ad.
}
override fun onAdClosed() {
// Code to be executed when the user is about to return
// to the app after tapping on an ad.
}
}
}
}
this is the full code to the app so far. Any advice will help. If i place the adCounter() anywhere in the ads section it will not update the textfield at all. Even after the textfield shows 1 then an ad is displayed it will always zero out the text field.
The value is not updated because you are opening the same Activity (MainActivity) on onAdDismissedFullScreenContent again.
First create a global TextView variable like:
private lateinit var tvAdsAmount : TextView`\
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tvAdsAmount = findViewById(R.id.tvAdsAmount)
// Other things...
}
Then simply use:
override fun onAdDismissedFullScreenContent() {
val value = tvAdsAmount.text.toString().toInt()
// make sure that value is an Integer.
val updateValue = value++
tvAdsAmount.text = "$updatedValue"
}
Some points you should learn:
Every time you start a new Activity, you're getting a new TextView that has no memory of what was in a TextView of some previous Activity.
You should never use a UI component like TextView to store application state. It's just not reliable. UI components are intended to be a bridge between your application state and the user. They aren't supposed to be the application state themselves. This is the programming principle of separation of concerns.
Since you're not finishing the previous Activity, you're building up a large stack of duplicate Activities. The user will be surprised when they push the back button to see an outdated copy of the Activity, one after another.
Whenever there's a configuration change (such as a screen rotation, or the user changing some setting in the Android settings like the device language), Android destroys all of the Activities that you have open and creates new instances of them. So any application state you were holding in them is going to be lost. This is why there is a ViewModel class for holding state that will survive configuration changes.
To fix your app:
Change your logic so you aren't starting new Activities. Keep everything in the same Activity instance. If you want to load a new ad, just call the function that loads ads rather than creating a brand new Activity.
Create a ViewModel to hold your application state. In this case, it will just need a LiveData<Int> to hold your count. You can observe this LiveData in your Activity and update the value of the TextView in the observer function. Your ViewModel can have an increment function that increases the LiveData's integer value, and you'll call this after ads are dismissed.
Long term, you can consider backing up this value with SharedPreferences, so the value will persist between sessions of your app.
Points 2 and 3 have many tutorials online and questions on this site about them, so I'm not going to explain them in detail.
I implemented Facebook Login functionality in my android app. But there is a unwanted behaviour that appears.
loginButton.registerCallback(callbackManager,
object : FacebookCallback<LoginResult> {
override fun onSuccess(result: LoginResult?) {
Log.d("mytag", "onSuccess: ${result?.accessToken?.userId}")
}
override fun onCancel() {
}
override fun onError(error: FacebookException?) {
}
})
So when onSuccess is called, everything is okay, i get the userId. But internally this saves some user authentication data inside SharedPreferences. Which is not what i want, my intention is to get only userId and send it to my server and that is it. (I mean it is not actually my aim to use facebook login for app, i just want to get userProfile image and send it to server).
How can i achieve this result?
I am working on an app where I need to set security feature by setting passcode/password/pin for the user so that whenever they open the app from the background, the app asks for password/passcode/pin. I read a few articles/solutions like this but they didn't help me. The same functionality we found in normal banking apps in which whenever you open an app, they will ask for passcode/fingerprint.
I have already set up the logic to save the passcode/pin in shared preference but I am not sure about when to ask it. I know that we can't replace splash screen with passcode/pin activity, because sometimes from app's homeScreen/MainActivity, user press home button and when they again open the app from recent apps, the app should ask for passcode/pin to resume the app use.
Any help would be appreciated.
This is an interesting question, I will share my thought on this question and give a solution as well.
Terminology:
App Lock Type: A generic name for pin/pincode/password/passcode, etc. (in the following section, I will use the pin name to demonstrate)
PinActivity: A screen where users input their pin to verify themself
Story:
For apps that require users to input pin, they usually want to make sure sensitive information is not leaked/stolen by other people. So we will categorize app activities into 2 groups.
Normal activities: Doesn't contain any sensitive information, usually before users logged in to the app, such as SplashActivity, LoginActivity, RegistrationActivity, PinActivity, etc.
Secured activities: Contain sensitive information, usually after users logged in, such as MainActivity, HomeActivity, UserInfoActivity, etc.
Conditions:
For secured activities, we must make sure users always input their pin before viewing the content by showing the PinActivity. This activity will be shown in the following scenarios:
[1] When users open a secured activity form a normal activity, such as from SplashActivity to MainActivity
[2] When users open a secured activity by tapping on Notifications, such as they tap on a notification to open MainActivity
[3] When users tap on the app from the Recents screen
[4] When the app starts a secured activity from another place like Services, Broadcast Receiver, etc.
Implementation:
For case [1] [2] and [4], before start a secured activity we will add an extra to the original intent. I will create a file named IntentUtils.kt
IntentUtils.kt
const val EXTRA_IS_PIN_REQUIRED = "EXTRA_IS_PIN_REQUIRED"
fun Intent.secured(): Intent {
return this.apply {
putExtra(EXTRA_IS_PIN_REQUIRED, true)
}
}
Use this class from normal activities, notifications, services, etc.
startActivity(Intent(this, MainActivity::class.java).secured())
For case [3], I will use 2 APIs:
ProcessLifecycleOwner: To detect whether the app go to background. A typical scenario is when users click on Home/Menu key on their devices.
ActivityLifecycleCallbacks: To detect whether an activity is resumed by relying on onActivityResumed(activity) method.
First I create a base activity, all normal activitis must extend from this class
BaseActivity.kt
open class BaseActivity : AppCompatActivity() {
// This method indicates that a pin is required if
// users want to see the content inside.
open fun isPinRequired() = false
}
Second I create a secured activity, all secured activities must extend from this class
SecuredActivity.kt
open class SecuredActivity : BaseActivity() {
override fun isPinRequired() = true
// This is useful when launch a secured activity with
// singleTop, singleTask, singleInstance launch mode
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setIntent(intent)
}
}
Third I create a class that extends from the Application, all logic are inside this class
MyApplication.kt
class MyApplication : Application() {
private var wasEnterBackground = false
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(ActivityLifecycleCallbacksImpl())
ProcessLifecycleOwner.get().lifecycle.addObserver(LifecycleObserverImpl())
}
private fun showPinActivity() {
startActivity(Intent(this, PinActivity::class.java))
}
inner class LifecycleObserverImpl : LifecycleObserver {
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onEnterBackground() {
wasEnterBackground = true
}
}
inner class ActivityLifecycleCallbacksImpl : ActivityLifecycleCallbacks {
override fun onActivityResumed(activity: Activity) {
val baseActivity = activity as BaseActivity
if (!wasEnterBackground) {
// Handle case [1] [2] and [4]
val removed = removeIsPinRequiredKeyFromActivity(activity)
if (removed) {
showPinActivity()
}
} else {
// Handle case [3]
wasEnterBackground = false
if (baseActivity.isPinRequired()) {
removeIsPinRequiredKeyFromActivity(activity)
showPinActivity()
}
}
}
private fun removeIsPinRequiredKeyFromActivity(activity: Activity): Boolean {
val key = EXTRA_IS_PIN_REQUIRED
if (activity.intent.hasExtra(key)) {
activity.intent.removeExtra(key)
return true
}
return false
}
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivityDestroyed(activity: Activity) {}
}
}
Conclusion:
This solution works for those cases that I mentioned before, but I haven't tested the following scenarios:
When start a secured activity has launch mode singleTop|singleTask|singleInstance
When application killed by the system on low memory
Other scenarios that someone might encounter (if yes please let me know in the comments section).
Hey Guys Im trying to push the user data in kotlin to firebase but when i click the create account button nothing happends here is the code for Create account class
class CreateAccount : AppCompatActivity() {
var mAuth:FirebaseAuth?=null
var mdata:DatabaseReference?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create_account)
mAuth= FirebaseAuth.getInstance()
Createacc.setOnClickListener{
var email=acemail.text.toString().trim()
var pass=acpass.text.toString().trim()
var name=acname.text.toString().trim()
if(!TextUtils.isEmpty(email)||!TextUtils.isEmpty(name)||!TextUtils.isEmpty(pass)){
createAccount(email,pass,name)
}
else{
Toast.makeText(this,"Please fill all the details",Toast.LENGTH_LONG).show()
}
}
}
fun createAccount(email: String,password:String,dispname:String){
mAuth!!.createUserWithEmailAndPassword(email,password).addOnCompleteListener(this,{
task: Task<AuthResult> ->
if(task.isSuccessful){
var curruser=mAuth!!.currentUser
var userid=curruser!!.uid
Toast.makeText(this,"Building user wait",Toast.LENGTH_LONG).show()
var uobject=HashMap<String,String>()
uobject.put("Display_name",dispname)
uobject.put("Status","Hi I'm New")
uobject.put("image","default")
uobject.put("thumb image","default")
mdata=FirebaseDatabase.getInstance().reference.child("Users").child(userid)
mdata!!.setValue(uobject).addOnCompleteListener{
task:Task<Void> ->
if(task.isSuccessful){
Toast.makeText(this,"User Created",Toast.LENGTH_LONG).show()
}
else{
Toast.makeText(this,"OOPS!! User not Created",Toast.LENGTH_LONG).show()
}
}
}
})
}
}
Main problem is in create account function ,it is being called correctly but right after the createUserWithEmailAndPassword function the task is not successfull hence the if loop does not run. There nothing is printed in the toast Neither "User created " nor "OOPS not created" i dont know whats going on.
I have installed the firebase dependency and my app is connected to a firebase database.