On Android, it is possible for users to use the Settings -> Application Manager -> App -> Clear Data feature and clear all the stored data for the app. However, if the user uses the app switcher to switch back to the app it will switch back to the activity last used. In some cases, say with an app that requires login, the activity will be inappropriate for the case where there is no data. How should application handle his case? Should each Activity be derived from a base Activity class that checks if the data has been deleted and then launch the appropriate Activity (say, the login Activity)? Is there a more elegant solution than that?
Instead of checking if data has been deleted, just check if the user is signed in. If he isn't, you can just send him back to the login screen as you suggested.
In any case, if you are using oAuth, or ever intend to implement it for login, checking if the user is logged in should be implemented since the oAuth tokens eventually expire. In this case, no data has been deleted, but the user is no longer signed-in, which would lead to them getting stuck in the inappropriate Activity anyway.
Just create a super-class for your ActivityThatRequiresLogin that will check if the user is logged in, and have all ActivityThatRequiresLogin extend that class. Then, you can call super whenever the onCreate and onResume method is called.
If the user wipes their data, they are automatically signed out, so all you have to do is check if they're signed in or not.
Pressing Clear Data stops your app's process, so your code will not be running.
Unfortunately there is no way to catch intent of such action unless you'r a system app.
The best practice way to handle this situation would use a SharedPreference mechanism and a base activity class.
Related
when I am in the last activity and I press back, my app goes to the background but when I return my app restarts going back to the "login" screen, if I am in "Home" and I go back it goes to the background because my login activity finished, I understand this is part of how the Android system works. Having an app with an sdk that uses bluetooh with asynTask tasks, I would like to be able to force an activity not to close or cancel when it goes to the background, I am looking for alternative solutions such as making the app stay in "widget" mode or being able to launch some kind of "service" that forces my activity as such not to close or restart when it goes to the background, I'm quite new to all this, any suggestion on how to solve this problem will be welcome
Backing out of the last Activity on the stack treats the app as "closed", and there are expected behaviours associated with that:
The user's assumption in these complete dismissal cases is that they have permanently navigated away from the activity, and if they re-open the activity they expect the activity to start from a clean state. The underlying system behavior for these dismissal scenarios matches the user expectation - the activity instance will get destroyed and removed from memory, along with any state stored in it and any saved instance state record associated with the activity.
So while it is possible to restore the previous state (the example they give is a web browser opening at the same page it was on) the system and components like Navigation are built around this idea that state shouldn't be preserved. You'd have to put in effort to work around that.
Running a Service only keeps your app's process alive - it won't do anything for background Activities, which the system will destroy if it needs the memory. And besides, like it says above, if you back out of an Activity it's considered dismissed and its state is wiped, whether it's been kicked out of memory or not.
Honestly it sounds like you just want to avoid redisplaying the login screen if the user's already logged in? That shouldn't be anything to do with Activity state, you should be storing that data somewhere so you can check it when the app starts, so you can send them to the appropriate screen
There's a whole section about this exact scenario in the Navigation docs. They don't show their UserViewModel (which we're supposed to imagine handling logged-in state, and actually doing the user/password auth if necessary) but the idea is pretty simple - you have a component that exposes a value saying whether the user is logged in or not (which could be stored in e.g. SharedPreferences) and it can automatically navigate away from the login screen based on that.
I was advised to do, in each Activity and Fragment onCreate callback, an if(signed_user_id == null) { showErrorPopIn(); startSplashScreenActivity(); return; } (a check that the user is not logged in, in which case we display an error and redirect the user from the Android app to the splash screen, and we don't execute the rest of the Activity and Fragment code). This code would be used in all activities (except SplashScreen of course) and in all Fragments, in the onCreate method. Cf. another SO question (Check if user is logged in on every activity, or only at the beginning?).
But I find it makes the code a lot heavier, and it seems to be useless. Indeed:
A hacker can change the activity code and the fragment code and therefore remove this condition, right?
And most importantly: checking that the user is logged in is only useful on the server side, not on the Android app side. Indeed, the critical points are the read and write accesses to the databases. But I don't give a damn if the not-connected user can see the graphical part of a Fragment or an Activity if this part doesn't display anything from a database or doesn't allow any modification in a database after a click on a button for example. Right?
So in the end I can remove all those if(signed_user_id == null) conditions I've put in all my Fragments and Activities?
PS 1 : signed_user_id is just FirebaseAuth::getInstance().getUser().getUId() roughly.
PS 2 : if I'm right, it means the first answer of the above linked SO question should be edited to indicate to the original poster that it's useless to do these checks in Android app side.
The problem is in this statement you make:
And most importantly: checking that the user is logged in is only useful on the server side, not on the Android app side.
There are two reasons to check whether a user is authenticated and/or authorized:
To reject unauthorized operations. This check should always happen on the server, as malicious user could bypass the check if (only) implemented on the client.
To show the correct authentication/authorization state to the user, and to allow them to change it (within the rules of your application). These checks happen on the client.
The goal of the second type of check is to show your user a clear UI, and provide them a path forward.
For example, you'll typically want to detect if the user is signed in, and if not show them the sign-in screen of your app. If you don't do this, the first time they know something is wrong is when the database rejects their operation with a "access denied" or similar message. This latter flow may be correct for your app, but it is very common to detect sign-in state on start-up and then first get the user to sign in (either anonymously or identified).
Another example could be if you have a premium user level who are allowed to write more data to your database. Of course the actual check of whether a write is allowed should be done server-side. But you might want to update the UI in some way if a non-premium user has reached their limit, for example disabling the UI elements that would update the database (and thus fail), or maybe show them a "you've reached the limits of your plan, click here to upgrade" banner.
So neither the server-side check nor the client-side check is useless, but they serve different purposes. Server-side checks are required to ensure your data stays uncorrupted, and your business rules are followed. Client-side checks are recommended to give your users a better (UI) experience.
I think this will be much easier if you are using BaseActivity and BaseFragment that all activities and fragment extends from it so you will write this code in BaseActivity/BaseFragment oncreate method only.
I am looking for a way to logout the user of my app automatically when the application has been terminated. I dont believe there is anyway to do this as only the activities have an onTerminate() function call. I am coming from an ios background where i an app, i could call a logout() function when the user entered the background. Is there a similar sort of parallel for android?
The reason i am looking for this option is because i have a global helper class that extends Application to store some user credentials and other info. If the application gets terminated by the os, this data is lost from what i have read. So i would like to force the user to log back in again to repopulate this data if it was destroyed.
Save user credentials to shared preference, Then when press logout button clear data in shared preference and finish the activities and cancel all background services related to your app
I'm asking this question because I want to be sure which is the best way to store the user "logged in" / "logged out" state in my android application.
Here is what I am doing. In my application I connect to the server, send him username and password and if everything is ok it returns me OK. So now I want to be able to save the user logged in state all over my application because I need to change the content depends on that if user is logged in or not.
And the other thing is that I need to be able to save the user's login state, so the next time when he start the application he will be automatically logged in.
Any suggestions or ideas which is the best way to do that?
I made a little research over internet and find a few ways to do that :
MyApplication class which extends android.app.Application
SharedPreference
Or maybe a SQLite
There can be many reasons when your app looses focus, like pressing home button incoming call, etc but no matter what happens your onPause method of current Activity is called so what you have to is-
Override onPause method of every activity
Use SharedPreference to save the state of Application
I use static classes or SharedPreference - it'is easy and it's works.
SQLite it not good way (in my opinion)
your option SharedPreference is the perfect one in this condition as you need to store only boolean and you will access if often in your app to change the content.
The problem with storing the state on the device (using either the SharedPreferences or SQLite) is that the user can manipulate it. So if you simply store "isLoggedIn" in your SQLite-Database, this entry can be manipulated using dpms (for example).
So if you need to store the state, you should use the Application-class (this can be manipulated, too, but it's harder to do so). If the user closes the application, you destroy the state-variable so he needs to do the login when the application is opened the next time.
For usability, you could store username and (if the user wants so) the password.
Also, if you have a web-service that you use to check if the users login-data is correct, why don't you use for example OAuth to authentify the user on the server and deliver the content from it? This would basically make your application a pure "client".
SharedPreference is the best option to access single value in terms of timing which i observe to be true as compared to sql lite.
I am working on an Android app that deals with sensitive user information. One of the requirements is that the user is required to log back into the application whenever they leave it and come back. This is easily dealt with for the case when the user presses the Home button and then relaunches the app (android:clearTaskOnLaunch attribute on the Activity in AndroidManifest.xml). However, we need to do the same thing when the user long presses the Home button, switches to another application, then comes back.
I have researched this every way that I can think of and have not found a workable solution. Is this even possible with Android?
When answering, please keep in mind that this is a business requirement which I have no control over.
Well, I had the same problem yesterday. This is what I did and it works fine:
Added android:launchMode="singleTask" to the main activity in the AndroidManifest.xml
Called my boss and say: ey, this is going to take a long while... hold on!
Went and drank beer all night.
Just to clarify, my main activity only has a button that says login and launches the login page.
What have you tried? You can always clear whatever session you are saving in the proper Activity lifecycle method.
If I understand you correctly that you want to require an authorisation every time someone backs into the app, whether afresh or coming back to it, then you can override the onRestart() activity lifecycle event on the activity (or activities). So in onRestart() you can redirect the user to the login screen (you may also wish to consider onResume() depending on your requirements)
The lifecycle chart on this page will make this clearer:
http://developer.android.com/reference/android/app/Activity.html
Would it be possible to make it a time based thing, rather than strictly left the app and returned?
You could have a separate service that keeps track of when the last time the user accessed the application was.
I.e, in each onPause the Activity tells the service that an Activity was paused. The service records the time of that.
In each onResume, the Activity informs the Service that it wishes to resume. If some amount of time has passed since the last onPause, then the Service indicates that a login is required.
I think this would make a nicer user experience than just every time they leave the app. That could be very frustrating, to take 30 seconds to read a text, and then have to sign in again.
I suppose if you tweak it to have the timeout be very short, it has very similar behavior to what you requested anyways, but with the option of making it less draconion.
I think the easiest way to implement this, would be to add a field to your main activity like private boolean isLocked = true;.
To lock the app when another one is shown, set isLocked = true in the onPause() method. To make sure, that your don't lock your app, when returning from your own activities, start them via startActivityForResult() and unlock it in onActivityResult.
You can now check in onResume() wether your app is locked and redirect the user to your login screen.