9

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.

  1. 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.

  2. 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.

Community
  • 1
  • 1
achie
  • 4,716
  • 7
  • 45
  • 59
  • not sure, but if u can make a service and every say 1 or 2 secs call isapponforeground, and change a variable to true/false, and in activity on resume, just check for true/false – Amit Sep 20 '12 at 00:00
  • For #1, what about an encrypted ONE TIME USE session/cookie type string stored in a *private* SharedPreference -- you could set the timeout for a few minutes and this could allow users to leave and return to your app. – pjco Sep 20 '12 at 01:17
  • another possible solution is become a device admin to utilize the device lock instead of a custom app pin lock. this can be better or worse depending on how you look at it. if you have lots of apps that require security, it's a single lock for all apps. if you just have one app, users are annoyed because your app is forcing them to have a lock screen. – Jeffrey Blattman Sep 20 '12 at 01:37
  • 1
    When you start an external app, you could startActivityForResult, then using onactivityresult essentially cancel the pin lock screen from opening. I THINK this could work (using your first approach) – Reed Sep 20 '12 at 04:16
  • @Jakar: Yes that might help and I was actually testing out using that approach for my case where I start external apps. I will have to check for result_ok. – achie Sep 20 '12 at 06:04

1 Answers1

5

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.

Jeffrey Blattman
  • 22,176
  • 9
  • 79
  • 134
  • The only difference with `onResume()` vs `onStart()` is that `onResume()` can be called after a dialog has closed. That could be an advantage or a disadvantage I guess. – pjco Sep 20 '12 at 01:22
  • @pjco i think `onStart/Stop()` is probably a better choice for the reason you identified. – Jeffrey Blattman Sep 20 '12 at 01:35
  • @Jeff: Thank you. I was actually doing a BaseActivity from which almost all of my Activities are subclassed from and I implement the passcode check in the onStart and onStop methods. I do not care about that when users open dialogs as they are already in the app. I completely agree on the battery impact thing and I would definitely not take the background service approach for just this check. And regarding requiring a passcode, yes it is very important for my app. Users actually demand it and give negative feedback since I do not have it. Of course I will make it optional for who want it. – achie Sep 20 '12 at 06:14
  • 4
    @pjco onStart/onStop is not the right choice since if a second activity is started from first activity, onStop of first activity is called after onStart of second activity. onResume/onPause is the right choice – Gautham Jan 06 '13 at 16:05