Merge pull request #12817 from nextcloud/enhance-passcode-activity

Enhance Passcode
This commit is contained in:
Tobias Kaminsky 2024-04-04 11:05:06 +02:00 committed by GitHub
commit a9ff057fe0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 33 additions and 52 deletions

View File

@ -113,6 +113,9 @@ import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.util.Pair;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.multidex.MultiDexApplication;
import dagger.android.AndroidInjector;
import dagger.android.DispatchingAndroidInjector;
@ -297,6 +300,8 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
setAppTheme(preferences.getDarkThemeMode());
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(lifecycleEventObserver);
insertConscrypt();
initSecurityKeyManager();
@ -362,6 +367,15 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
registerGlobalPassCodeProtection();
}
private final LifecycleEventObserver lifecycleEventObserver = ((lifecycleOwner, event) -> {
if (event == Lifecycle.Event.ON_START) {
Log_OC.d(TAG, "APP IN FOREGROUND");
} else if (event == Lifecycle.Event.ON_STOP) {
passCodeManager.setCanAskPin(true);
Log_OC.d(TAG, "APP IN BACKGROUND");
}
});
private void registerGlobalPassCodeProtection() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

View File

@ -49,12 +49,10 @@ class PassCodeManager(private val preferences: AppPreferences, private val clock
* the pass code being requested on screen rotations.
*/
private const val PASS_CODE_TIMEOUT = 5000
private const val TAG = "PassCodeManager"
}
private var visibleActivitiesCounter = 0
private var lastResumedActivity: Activity? = null
var canAskPin = true
private var askPinWhenDeviceLocked = false
private fun isExemptActivity(activity: Activity): Boolean {
return exemptOfPasscodeActivities.contains(activity.javaClass)
@ -69,7 +67,7 @@ class PassCodeManager(private val preferences: AppPreferences, private val clock
val passcodeRequested = passCodeShouldBeRequested(timestamp)
val credentialsRequested = deviceCredentialsShouldBeRequested(timestamp, activity)
val shouldHideView = passcodeRequested || credentialsRequested
toggleActivityVisibility(shouldHideView, activity)
getActivityRootView(activity)?.visibility = if (shouldHideView) View.GONE else View.VISIBLE
askedForPin = shouldHideView
if (passcodeRequested) {
@ -82,47 +80,16 @@ class PassCodeManager(private val preferences: AppPreferences, private val clock
}
}
if (!askedForPin && preferences.lockTimestamp != 0L) {
if (!askedForPin && preferences.lockTimestamp != 0L || askPinWhenDeviceLocked) {
updateLockTimestamp()
}
if (!isExemptActivity(activity)) {
addVisibleActivity(activity) // keep it AFTER passCodeShouldBeRequested was checked
askPinWhenDeviceLocked = false
}
return askedForPin
}
/**
* Used to hide root view while transitioning to passcode activity
*/
private fun toggleActivityVisibility(
hide: Boolean,
activity: Activity
) {
if (hide) {
getActivityRootView(activity)?.visibility = View.GONE
} else {
getActivityRootView(activity)?.visibility = View.VISIBLE
}
}
private fun addVisibleActivity(activity: Activity) {
// don't count the same activity twice
if (lastResumedActivity != activity) {
visibleActivitiesCounter++
lastResumedActivity = activity
}
}
private fun removeVisibleActivity() {
visibleActivitiesCounter--
lastResumedActivity = null
}
private fun setSecureFlag(activity: Activity) {
val window = activity.window
if (window != null) {
activity.window?.let { window ->
if (isPassCodeEnabled() || deviceCredentialsAreEnabled(activity)) {
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
} else {
@ -132,38 +99,38 @@ class PassCodeManager(private val preferences: AppPreferences, private val clock
}
private fun requestPasscode(activity: Activity) {
val i = Intent(MainApp.getAppContext(), PassCodeActivity::class.java)
i.action = PassCodeActivity.ACTION_CHECK
i.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
val i = Intent(MainApp.getAppContext(), PassCodeActivity::class.java).apply {
action = PassCodeActivity.ACTION_CHECK
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
}
activity.startActivityForResult(i, PASSCODE_ACTIVITY)
}
private fun requestCredentials(activity: Activity) {
val i = Intent(MainApp.getAppContext(), RequestCredentialsActivity::class.java)
i.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
val i = Intent(MainApp.getAppContext(), RequestCredentialsActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
}
activity.startActivityForResult(i, PASSCODE_ACTIVITY)
}
fun onActivityStopped(activity: Activity) {
if (visibleActivitiesCounter > 0 && !isExemptActivity(activity)) {
removeVisibleActivity()
}
val powerMgr = activity.getSystemService(Context.POWER_SERVICE) as PowerManager
if ((isPassCodeEnabled() || deviceCredentialsAreEnabled(activity)) && !powerMgr.isScreenOn) {
activity.moveTaskToBack(true)
if ((isPassCodeEnabled() || deviceCredentialsAreEnabled(activity)) && !powerMgr.isInteractive) {
askPinWhenDeviceLocked = true
}
}
fun updateLockTimestamp() {
preferences.lockTimestamp = clock.millisSinceBoot
canAskPin = false
}
/**
* `true` if the time elapsed since last unlock is longer than [PASS_CODE_TIMEOUT] and no activities are visible
*/
private fun shouldBeLocked(timestamp: Long) =
abs(clock.millisSinceBoot - timestamp) > PASS_CODE_TIMEOUT &&
visibleActivitiesCounter <= 0
private fun shouldBeLocked(timestamp: Long): Boolean {
return (abs(clock.millisSinceBoot - timestamp) > PASS_CODE_TIMEOUT && canAskPin) || askPinWhenDeviceLocked
}
@VisibleForTesting
fun passCodeShouldBeRequested(timestamp: Long): Boolean {