Browse Source

Adjust app lock mechanism (#7924)

Now uses enum to also handle timed lock
Ivan Iskandar 2 years ago
parent
commit
774a87a42a

+ 1 - 6
app/src/main/java/eu/kanade/tachiyomi/App.kt

@@ -39,7 +39,6 @@ import eu.kanade.tachiyomi.glance.UpdatesGridGlanceWidget
 import eu.kanade.tachiyomi.network.NetworkHelper
 import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
 import eu.kanade.tachiyomi.util.preference.asHotFlow
-import eu.kanade.tachiyomi.util.system.AuthenticatorUtil
 import eu.kanade.tachiyomi.util.system.WebViewUtil
 import eu.kanade.tachiyomi.util.system.animatorDurationScale
 import eu.kanade.tachiyomi.util.system.isDevFlavor
@@ -60,7 +59,6 @@ import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
 import uy.kohesive.injekt.injectLazy
 import java.security.Security
-import java.util.Date
 
 class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
 
@@ -175,10 +173,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
     }
 
     override fun onStop(owner: LifecycleOwner) {
-        preferences.lastAppClosed().set(Date().time)
-        if (!AuthenticatorUtil.isAuthenticating && preferences.lockAppAfter().get() >= 0) {
-            SecureActivityDelegate.locked = true
-        }
+        SecureActivityDelegate.onApplicationStopped()
     }
 
     override fun getPackageName(): String {

+ 4 - 0
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt

@@ -53,6 +53,10 @@ class PreferencesHelper(val context: Context) {
 
     fun lockAppAfter() = flowPrefs.getInt("lock_app_after", 0)
 
+    /**
+     * For app lock. Will be set when there is a pending timed lock.
+     * Otherwise this pref should be deleted.
+     */
     fun lastAppClosed() = flowPrefs.getLong("last_app_closed", 0)
 
     fun secureScreen() = flowPrefs.getEnum("secure_screen_v2", Values.SecureScreenMode.INCOGNITO)

+ 48 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/base/delegate/SecureActivityDelegate.kt

@@ -8,11 +8,14 @@ import androidx.lifecycle.lifecycleScope
 import eu.kanade.tachiyomi.data.preference.PreferenceValues
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.ui.security.UnlockActivity
+import eu.kanade.tachiyomi.util.system.AuthenticatorUtil
 import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.isAuthenticationSupported
 import eu.kanade.tachiyomi.util.view.setSecureScreen
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.launchIn
 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
 
@@ -20,10 +23,36 @@ interface SecureActivityDelegate {
     fun registerSecureActivity(activity: AppCompatActivity)
 
     companion object {
-        var locked: Boolean = true
+        fun onApplicationStopped() {
+            val preferences = Injekt.get<PreferencesHelper>()
+            if (!preferences.useAuthenticator().get()) return
+            if (lockState != LockState.ACTIVE) {
+                preferences.lastAppClosed().set(Date().time)
+            }
+            if (!AuthenticatorUtil.isAuthenticating) {
+                lockState = if (preferences.lockAppAfter().get() >= 0) {
+                    LockState.PENDING
+                } else {
+                    LockState.ACTIVE
+                }
+            }
+        }
+
+        fun unlock() {
+            lockState = LockState.INACTIVE
+            Injekt.get<PreferencesHelper>().lastAppClosed().delete()
+        }
     }
 }
 
+private var lockState = LockState.INACTIVE
+
+private enum class LockState {
+    INACTIVE,
+    PENDING,
+    ACTIVE
+}
+
 class SecureActivityDelegateImpl : SecureActivityDelegate, DefaultLifecycleObserver {
 
     private lateinit var activity: AppCompatActivity
@@ -57,6 +86,7 @@ class SecureActivityDelegateImpl : SecureActivityDelegate, DefaultLifecycleObser
     private fun setAppLock() {
         if (!preferences.useAuthenticator().get()) return
         if (activity.isAuthenticationSupported()) {
+            updatePendingLockStatus()
             if (!isAppLocked()) return
             activity.startActivity(Intent(activity, UnlockActivity::class.java))
             activity.overridePendingTransition(0, 0)
@@ -65,9 +95,23 @@ class SecureActivityDelegateImpl : SecureActivityDelegate, DefaultLifecycleObser
         }
     }
 
+    private fun updatePendingLockStatus() {
+        val lastClosedPref = preferences.lastAppClosed()
+        val lockDelay = 60000 * preferences.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 {
-        if (!SecureActivityDelegate.locked) return false
-        return preferences.lockAppAfter().get() <= 0 ||
-            Date().time >= preferences.lastAppClosed().get() + 60 * 1000 * preferences.lockAppAfter().get()
+        return lockState == LockState.ACTIVE
     }
 }

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/security/UnlockActivity.kt

@@ -37,7 +37,7 @@ class UnlockActivity : BaseActivity() {
                     result: BiometricPrompt.AuthenticationResult,
                 ) {
                     super.onAuthenticationSucceeded(activity, result)
-                    SecureActivityDelegate.locked = false
+                    SecureActivityDelegate.unlock()
                     finish()
                 }
             },