Skip to content

Commit

Permalink
Merge pull request #12819 from nextcloud/backport/12817/stable-3.28
Browse files Browse the repository at this point in the history
[stable-3.28] Enhance Passcode
  • Loading branch information
tobiasKaminsky committed Apr 4, 2024
2 parents 5e3bde0 + 73fd2ea commit 1d3ec9d
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 52 deletions.
14 changes: 14 additions & 0 deletions app/src/main/java/com/owncloud/android/MainApp.java
Expand Up @@ -112,6 +112,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;
Expand Down Expand Up @@ -295,6 +298,8 @@ public void onCreate() {
setAppTheme(preferences.getDarkThemeMode());
super.onCreate();

ProcessLifecycleOwner.get().getLifecycle().addObserver(lifecycleEventObserver);

insertConscrypt();

initSecurityKeyManager();
Expand Down Expand Up @@ -353,6 +358,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() {

Expand Down
Expand Up @@ -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)
Expand All @@ -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) {
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down

0 comments on commit 1d3ec9d

Please sign in to comment.