I have an app that I use that automatically locks (requires a password entry screen)...
a) when the app starts for the first time
b) when another app is started and takes over the device
c) when the device "sleeps" automatically
d) when the user "sleeps" the device manually
(note: with c & d, if the user "awakens" the app within 5 seconds, it does NOT ask for the password)
I would like to do this for an app that I am writing as well so I created an activity (PasswordActivity) with the necessary verification steps and have it working properly.
I originally placed it in the ONCREATE of the MainActivity (that was LAUNCHED in the AndroidManifest). That seemed to work fine. But then started on the re-lock capability. So tried moving it to the ONSTART or ONRESUME. But then when another ACTIVITY in my APP took focus, or the screen rotated, then the PasswordActivity fired again. That won't work.
On here I found a thread recommending making it the LAUNCHER app in the Manifest and then when the password is OK, call the MainActivity. That seemed to work better... but then ran into an issue that it "re-locks" only when the user pressed the back button off the main screen (I assume stopping my app) and starts the app again. Doesn't catch another APP taking over the device although.
So based on that, and after looking at all documentation I can find on lifecycles (although most of those are ACTIVITY based, not APPLICATION based) not sure how to catch when the APP itself loses focus (another app takes over) and how to handle the automatic or manual sleep (C & D above) along with the time delay checking. I am assuming it is going to be a combination of several calls or steps, but not sure exactly which ones at this point.
Any recommendations?
I think I figured it out using some of the suggestions as well as some research. I am posting my solution here in case it can help someone else, someone sees a definite flaw I didn't see or encounter yet, or someone has some other input that may improved it.
As mentioned, the biggest problem as I can tell is there isn't any built-in function calls that can determine when "your app" is not in the foreground. The onPause and onResume are activity based, not app based... so changing from activity to activity in your app and even screen rotation, fires them.
To get around this... I created a global variable called gv.appPauseTime. I created two separate universal utility functions I can call from anywhere in my app.
public static void lockAppStoreTime() {
gv.appPauseTime=new Date();
}
public static void lockAppCheck(Activity act) {
boolean bLock=false;
// Check to see if this is the first time through app
if (gv.appPauseTime==null) {
bLock = true;
} else {
Date currTime = new Date();
long diffMillis = currTime.getTime() - gv.appPauseTime.getTime();
long diffInSec = TimeUnit.MILLISECONDS.toSeconds(diffMillis);
// Lock app if 120 seconds (2 minutes) has lapsed
if (diffInSec > 120) {
bLock=true;
}
}
gv.appLastPause = new Date();
if (bLock) {
Intent j = new Intent(act, PasswordActivity.class);
act.startActivity(j);
}
}
In every activity, I create (or modified) the onPause and onResume like so...
#Override
public void onPause(){
super.onPause();
Util.lockAppStoreTime();
}
#Override
public void onResume(){
super.onResume();
Util.lockAppCheck(this);
}
When the onPause fires, it stores the current date (time). When an onResume fires in any function, it compares the current date (time) to the stored one. If 120 seconds (2 minutes) has lapsed, it displays the PasswordActivity to get the password verified. It does "store" the current date(time) before it calls the PasswordActivity so that it doesn't keep re-iterating it.
Basically, if there is a 2 minute gap, between an activity pausing and any activity, IN MY APP, resuming (or starting), it prompts for the password. If the user opens a different APP, and then returns to my APP... again, if it is at least a 2 minute lapse, then the password is asked for. If the user powers off or closes the app, then the restart will also trigger the password.
I chose 2 minutes, because that seems to be a decent "time lapse" in our app in general. Of course, that can be changed too.
So far, so good. Hope this helps anyone else.
Related
I wondered if anyone can shed some light on this,
I have one activity app which has a listview. In onCreate() I populate some data in that listview (reading it from sqlite database). I have a close button which triggers finish(); too. now when I press close button, activity disappears but when I click on app icon on desktop (or selecting it from phone history button) I see all previous data in the listview. the function that I am looking for is to start app fresh after clicking close button for next run. (something like banking app log-out button). (list view here is only an example to put across the need, so clearing list-view before finish(); is not acceptable. It is very simple and plain request and I do not think any code is necessary but if anyone interested I will post some code too.
What I want is same behavior as a banking app in exit, when user leave the main screen or click sign out, the App closes altogether. I can achieve this by using following methods (number 2 and 3) but apparently these solutions are not best practices. Then what method a banking App uses to close the app instantly? I doubt they use something which is not best practice such as System.exit(0)?! or do they!
Many developers claiming closing an App or killing parent activity
is OS job
Some say use use :
int pid = android.as.Process.myPid();
android.os.Process.killProcess(pid);
(this solution according to this is not a good idea because in next run app acts like it has been crashed last time https://stackoverflow.com/a/24015569/4173238 )
some say use System.exit(0); according to this
https://stackoverflow.com/a/5846275/4173238 is not recommended either
some say use finish(); but finish does not do what I want
Thanks for any input
If you have a mechanism that allows it so that you only deliver messages to the main thread when the application is resumed, then you can register your activities on an event bus like Otto and send an event that every Activity is subscribed to on which they call finish() on themselves.
Another possible solution is starting every activity with startActivityForResult(), and if you click the exit button, then you would say
public static final int KILL_ACTIVITY_RESULT_CODE = 0xD34DB33F; //why not
public boolean onOptionsMenuItemSelected(MenuItem menuItem) {
if(menuItem.getId() == R.menu.kill_activity) {
setResult(KILL_ACTIVITY_RESULT_CODE);
finish();
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == KILL_ACTIVITY_RESULT_CODE) {
setResult(KILL_ACTIVITY_RESULT_CODE);
finish();
}
}
}
...and one time I've seen someone make static references to every single activity they had, and called finish() on each and every one of them. But don't do that, that essentially means you have failed as an Android programmer, and there is nothing to redeem you of your sins.
As brilliant CommonsWare, has pointed out in his comment "Static" was the issue! I was using static variables to store data to fill My listView. Apparently even if you have only one Activity and close it, Static variables remain intact! on app re run!
If you asking why I used static variable at the first place, I have to say, right or wrong, I wanted to share that variable between my other java class (my databaseHandler.class).
Why Android not clear all (including static variables) resources when closing the main and only Activity of app, remains a question and this is my next reading topic! but many thanks for anyone who post a comment on this question,
I will also change the question from:
How Banking Apps close? finish() does not do the same job for me
to
closing an activity using finish(); wont make app start fresh in next
run! why?
I need to calculate the time taken by my app to start. Do you have any ideas when to start and when to stop timing?
Use your timer at the beginning of oncreate() and stop it at the end of onResume().
According to lifecycle of an Activity.
To do this, you probably should be clear on what "start my app" means - if you are referring to an activity, then you should probably override the Activity constructor (not "onCreate" except in most cases there isn't any measurable time from the constructor before onCreate is called) and capture:
SystemClock.upTimeMillis()
then you need to create a listener for onGlobalLayout to determine when the activity is actually finished displaying on the screen and get the upTime again. For the listener, do it like in this post:
Activity lifecycle - receiving notification that layout is complete
And then take the difference between the times... however, that is really the "activity" startup time.
If you are certain your app is not running, and you want to see how long it takes to "start your app" when it is not loaded in memory at all, you should extend the Application class:
public class MyApp extends Application {
public MyApp() {
// get the time
}
}
and then override the constructor to capture the timestamp like above and store it. Your app's application class is constructed first, then activities are instantiated.
Then capture the listener time in the first activity to display, as mentioned above. That will probably tell you best how much time it took from when your app "starts" to when the user actually could see it.
There are a few things that happen between when a user action occurs that is intended to "start your app" that are not included, but you have no control over that, even though that should be included if you are trying to measure how long it takes from the user's perspective.
My application has sensitive user information and we need to implement a passcode screen to be displayed whenever the user opens the application.
Here are the two approaches I tried after reading this post.
Use a static variable and reset it in onStop() of each activity and check it again in the onStart() of each activity and show the passcode screen if the time crossed a minimum threshhold say 1-2 secs. The problem with this approach is that my application also uses intents to call camera and barcode scanners and the users may spend longer periods in these external apps. I can increase the threshold in this case but it makes the calculations complicated and is not a very good solution.
I tried the other approach by using this method.
protected boolean isAppOnForeground(final Context context) {
List<RunningAppProcessInfo> appProcesses = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (RunningAppProcessInfo appProcess : appProcesses) {
if ((appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) &&
appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
But this will always return true when I check for it in the onStart method of each activity since the process already started by the time it is in onStart
Is there any other approach that I can take to display a passcode when ever the user opens the application? It should be displayed even when user clicks on home screen to go out of the app and then comes back to the app from recent apps.
i've implemented this exact feature. i essentially did your #1, but in a little cleaner way.
what i did was write an abstract subclass of Activity, and override onResume(). in there, decide if you need to show the pin lock screen. if you do, finish yourself and start the pin lock activity. have all your activities extend this activity.
to remember where you were at, you can add a "starting intent" extra to the intent used to start the pin lock activity. when the app is unlocked, the pin lock activity can use that extra to put the user right back where they were.
if your app was fragment-based, this would be simple. whenever the activity that hosts all of the fragments is resumed, you show the pin lock fragment. that's all.
the problem with an app consisting of a bunch of activities is that there is no clear defining moment of "starting" the app. the concept doesn't exist. this is essentially the problem you found with your #1 solution. onResume() seems like a good choice but that can be called for lots of reasons. for example, the user start activity A, which starts activity B. now they press back. show the pin lock, or not?
any solution that utilizes a thread that checks foreground processes is a terrible idea because of the battery impact.
finally, you might want to question the requirement of having a pin lock every time the app is brought into the foreground. it seems excessive if i bounce out to read a text message and come back 10s later i'm forced to re-enter a pin. time based seems more appropriate.
I have an android app in development which enables the user to protect the data inside the app by entering a password or pin. Is there a method to check if the app hasn't been used for lets say 10 minutes to then change a setting in the app prefs file.
I was thinking of maybe a service, or a class within the app that runs instead another thread with a timer but not sure if this would be suitable.
Another method, I was thinking is there a way so that when the user presses the home button, the home button does its normal task of return to the android home screen but it also changes a setting within the apps prefs file.
Thanks for any help you can provide.
#Joseph Earl comment on my question is the answer. Works perfectly.
Use the onPause method and get the time of android and save it to the app config.
then use the onResume to get the current time of android and the time from the config and get the time in minutes.
Works perfectly.
you can use something like this
private long lastTimeUpdating;
all where you have an actions
lastTimeUpdating = System.currentTimeMillis();
and you must have a thread which is updating every 50 milliseconds, in this thread check this
if(System.currentTimeMillis() - lastTimeUpdating >= 5 * 60 * 1000) {
/*change your settings here*/
}
You can use the Chronometer control for timing an action.
Use the start() and stop() methods, to determine state.
Example:
final Chronometer timer =
(Chronometer) findViewById(R.id.Chronometer1);
long base1 = timer.getBase();
timer.setBase(0);
timer.start();
listen for changes using the Chronometer.OnChronometerTickListener interface
I have an app that starts playing sounds and begins/resumes gameplay in the onResume() method, but what I'm noticing is that if my app was the last run application when I put the phone into standby (screen off), and I just press the Menu button to check the time, then the phone starts playing the game and sounds in the background (the app isn't actually visible, only the screen with the date/time is, yet onResume must have been called in my app). What am I to do here? Is there a way to discern what is reactivating the app, and then add a conditional statement that only starts the game when the app is actually visible?
Here is a snippet from my onResume:
#Override
protected void onResume()
{
mySaveGame = Utilities.loadSavegame(this);
//check the savegame
if(mySaveGame!=null)
{
//start game using savegame values
this.startFromSavedGame(mySaveGame.getIsLevelComplete());
}
else
{
//run the 1st-run components
this.startFirstRun();
}
super.onResume();
}
The only thing I can think of doing to prevent the game from starting whenever the screen gets turned on (even when the app isn't visible) is to put this.finish() as the last line in onPause()... but that forces you to restart the app every time you want to go back to it because the precess itself was killed (which is fine because my onPause saves persistent data, but it's not an elegant solution).
Please help.
Have you considered switching to onStart() and onStop(), rather than onResume() and onPause()?
I was having the same problem (I had my music player resume/pause at onResume()/onPause()) and the best solution I found is to pause and resume my activity when it is on the foreground which you can get with public void onWindowFocusChanged (boolean hasFocus) callback.
Edit: This in an old and slightly incorrect answer - correct response is described in the Android Developers Blog: making android games that play nice