From 2ab744c525e2c6c94bcac7d4cc3848830a50c991 Mon Sep 17 00:00:00 2001 From: stevenyomi <95685115+stevenyomi@users.noreply.github.com> Date: Sun, 23 Oct 2022 03:07:44 +0800 Subject: [PATCH] Fix app lock and make delay not survive app being killed (#8272) * Fix app lock * Always require unlock if app is killed --- app/src/main/java/eu/kanade/tachiyomi/App.kt | 4 +- .../base/delegate/SecureActivityDelegate.kt | 87 ++++++++----------- .../util/system/AuthenticatorUtil.kt | 15 ---- 3 files changed, 37 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 23956a826b..da938cd13e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -169,8 +169,8 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { }.build() } - override fun onCreate(owner: LifecycleOwner) { - SecureActivityDelegate.onApplicationCreated() + override fun onStart(owner: LifecycleOwner) { + SecureActivityDelegate.onApplicationStart() } override fun onStop(owner: LifecycleOwner) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt index 7b5d3f6540..178a8704f4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt @@ -17,55 +17,59 @@ import kotlinx.coroutines.flow.onEach import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy -import java.util.Date interface SecureActivityDelegate { fun registerSecureActivity(activity: AppCompatActivity) companion object { - fun onApplicationCreated() { - val lockDelay = Injekt.get().lockAppAfter().get() - if (lockDelay <= 0) { - // Restore always active/on start app lock - // Delayed lock will be restored later on activity resume - lockState = LockState.ACTIVE - } - } + /** + * Set to true if we need the first activity to authenticate. + * + * Always require unlock if app is killed. + */ + var requireUnlock = true fun onApplicationStopped() { val preferences = Injekt.get() if (!preferences.useAuthenticator().get()) return - if (lockState != LockState.ACTIVE) { - preferences.lastAppClosed().set(Date().time) - } + if (!AuthenticatorUtil.isAuthenticating) { - val lockAfter = preferences.lockAppAfter().get() - lockState = if (lockAfter > 0) { - LockState.PENDING - } else if (lockAfter == -1) { - // Never lock on idle - LockState.INACTIVE - } else { - LockState.ACTIVE + // Return if app is closed in locked state + if (requireUnlock) return + // Save app close time if lock is delayed + if (preferences.lockAppAfter().get() > 0) { + preferences.lastAppClosed().set(System.currentTimeMillis()) } } } + /** + * Checks if unlock is needed when app comes foreground. + */ + fun onApplicationStart() { + val preferences = Injekt.get() + if (!preferences.useAuthenticator().get()) return + + val lastClosedPref = preferences.lastAppClosed() + + // `requireUnlock` can be true on process start or if app was closed in locked state + if (!AuthenticatorUtil.isAuthenticating && !requireUnlock) { + requireUnlock = when (val lockDelay = preferences.lockAppAfter().get()) { + -1 -> false // Never + 0 -> true // Always + else -> lastClosedPref.get() + lockDelay * 60_000 <= System.currentTimeMillis() + } + } + + lastClosedPref.delete() + } + fun unlock() { - lockState = LockState.INACTIVE - Injekt.get().lastAppClosed().delete() + requireUnlock = false } } } -private var lockState = LockState.INACTIVE - -private enum class LockState { - INACTIVE, - PENDING, - ACTIVE, -} - class SecureActivityDelegateImpl : SecureActivityDelegate, DefaultLifecycleObserver { private lateinit var activity: AppCompatActivity @@ -100,32 +104,11 @@ class SecureActivityDelegateImpl : SecureActivityDelegate, DefaultLifecycleObser private fun setAppLock() { if (!securityPreferences.useAuthenticator().get()) return if (activity.isAuthenticationSupported()) { - updatePendingLockStatus() - if (!isAppLocked()) return + if (!SecureActivityDelegate.requireUnlock) return activity.startActivity(Intent(activity, UnlockActivity::class.java)) activity.overridePendingTransition(0, 0) } else { securityPreferences.useAuthenticator().set(false) } } - - private fun updatePendingLockStatus() { - val lastClosedPref = securityPreferences.lastAppClosed() - val lockDelay = 60000 * securityPreferences.lockAppAfter().get() - if (lastClosedPref.isSet() && lockDelay > 0) { - // Restore pending status in case app was killed - lockState = LockState.PENDING - } - if (lockState != LockState.PENDING) { - return - } - if (Date().time >= lastClosedPref.get() + lockDelay) { - // Activate lock after delay - lockState = LockState.ACTIVE - } - } - - private fun isAppLocked(): Boolean { - return lockState == LockState.ACTIVE - } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/AuthenticatorUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/AuthenticatorUtil.kt index 379c776edf..1de4158189 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/AuthenticatorUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/AuthenticatorUtil.kt @@ -76,11 +76,6 @@ object AuthenticatorUtil { activity?.toast(errString.toString()) cont.resume(false) } - - override fun onAuthenticationFailed(activity: FragmentActivity?) { - super.onAuthenticationFailed(activity) - cont.resume(false) - } }, ) } @@ -136,15 +131,5 @@ object AuthenticatorUtil { ) { isAuthenticating = false } - - /** - * Called when an authentication attempt by the user has been rejected. - * - * @param activity The activity that is currently hosting the prompt. - */ - @CallSuper - override fun onAuthenticationFailed(activity: FragmentActivity?) { - isAuthenticating = false - } } }