diff --git a/app/src/main/java/com/owncloud/android/MainApp.java b/app/src/main/java/com/owncloud/android/MainApp.java index a8b19e9eaeda..a735e11d1339 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.java +++ b/app/src/main/java/com/owncloud/android/MainApp.java @@ -113,6 +113,9 @@ 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 void onCreate() { setAppTheme(preferences.getDarkThemeMode()); super.onCreate(); + ProcessLifecycleOwner.get().getLifecycle().addObserver(lifecycleEventObserver); + insertConscrypt(); initSecurityKeyManager(); @@ -362,6 +367,15 @@ public void onCreate() { 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() { diff --git a/app/src/main/java/com/owncloud/android/authentication/PassCodeManager.kt b/app/src/main/java/com/owncloud/android/authentication/PassCodeManager.kt index fed4cf3f434e..062e6acb4f6c 100644 --- a/app/src/main/java/com/owncloud/android/authentication/PassCodeManager.kt +++ b/app/src/main/java/com/owncloud/android/authentication/PassCodeManager.kt @@ -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 {