0

My App could be locked with pin or fingerprint. I was able to do this on App Start with an "Start Up" Activity handle the pin/fingerprint stuff. But when it is once handled it is unlocked. But I want that when app was in background the lock screen is shown when the app is resumed. How can i manage this?

I was trying to start an intent when OnResume() of MainActivity is called.

@Override
protected void onResume() {
    super.onResume();

    Intent settingsIntent = new Intent(this, StartUpActivity.class);
    startActivity(settingsIntent);

}

But then it goes to an infinity loop ... :(. And with the resume I can not distinguish whether i came from another activity in my app or if the app was getting back in foreground.

I was also searching a bit but i didn't find a solution to this problem. If i was missed a solution, please provide a link.

Thanks, Sebi

Sebi
  • 133
  • 1
  • 9
  • just use something like this I guess https://stackoverflow.com/questions/3446202/android-detect-phone-unlock-event-not-screen-on – SomethingCool Sep 02 '19 at 13:04
  • It is not that i want to know when the phone is unlocked/locked but when my app comes to foreground and then redirekt to my startup activity. But without the infinity loop. but thanks for the link. – Sebi Sep 02 '19 at 13:08

3 Answers3

1

onResume is a proper place to start. But you need to add also something which handles lock/unlock logic and define non-lockable screens to avoid loops.

Lock/unlock logic could be placed into something like PinManager

interface PinManager {

  /**
   * it's up to you how to define logic inside.
   * It could be locked after some time 
   * or locked when app is destroyed and removed from memory
   */
  fun isLocked():Boolean

  fun unlock(pin:List<Integer>)

  fun clear()
}

To avoid loops you can define interface:

interface NonLockedActivity {

}

And use it with actvity which verifies pin:

class VerifiyPinActivity: BaseActivity(), NonLockedActivity {
  fun verifiy(pin:List<Int>){

    if(pinManager.unlock(pin)){
      finish()//and show previous activity
    } else {
      //show invalid pin message
    } 
  }
}

and in base activities onResume could look like this

class BaseActivity: Activity(){
  fun onResume(){

    if(pinManager.isLocked()){
      navigator.verifyPin(this)
    }

  }
}

And hide implementation of opening activity in navigator:

class Navigator {
  fun verifyPin(acitvity:Activity) {
    if(activity is not NonLockedActivity) {
      startActivity(VerifiyPinActivity::class)
    }
  }
}
eleven
  • 6,779
  • 2
  • 32
  • 52
  • 1
    Yes I was doing a similar thing to avoid loops but the problem with this was, that i could't distinguish if the app was in background or the onStart()/onResume() was called from an internal activity. – Sebi Sep 02 '19 at 13:29
0

I was able to do the check described in this answer: How to detect when an Android app goes to the background and come back to the foreground

With this I could check if the app came from the background or from an internal activity. And then I could call the Intent to my Start Up Activity.

Sebi
  • 133
  • 1
  • 9
0

It depends of how you've done your pin locking.

From the question I assume you've used some library or self made approach for that. In this case you may store some value isLocked in SharedPreferences and change it every time in onDestroy or in onStop to true. When user enters your app you should check if isLocked == true and prompt pin screen and change it to false on successful unlock, and if isLocked == false you can proceed with you app flow. If you want this to do it easier way - you may just have some static variable and manipulate its value - but on the app process recreation it will be changed to default value.

But I would recommend you to look into these methods - they are default for the Android OS.

With KeyguardManager you should use Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(title, description) in conjunction with startActivityForResult(intent) which will handle all the stuff you need and in onActivityResult you can handle moving forward.

Starting from API 28 you can use BiometricPrompt. You can use its Builder's method setDeviceCredentialAllowed(true) that will handle the pin stuff in similar way as KeyguardManager only with face/fingerprint options. BiometricPrompt has method authenticate that will actually prompt pin screen. It receives listener as argument so you won't need onActivityResult.

Pavlo Ostasha
  • 14,527
  • 11
  • 35
  • That is an interesting point, i will look into the KeyguardMangager. And you are right I use my own Activity for displaying and handling the PIN/Fingerprint stuff. – Sebi Sep 02 '19 at 13:31