Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
android:name=".features.lockscreen.ui.PasswordOverlayActivity"
android:excludeFromRecents="true"
android:exported="false"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:theme="@android:style/Theme.Material.NoActionBar.TranslucentDecor" />

<activity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,7 @@ private fun createBiometricPromptInfo(): BiometricPrompt.PromptInfo {
.setSubtitle(BIOMETRIC_SUBTITLE)
.setNegativeButtonText(BIOMETRIC_NEGATIVE_BUTTON)
.setAllowedAuthenticators(
BiometricManager.Authenticators.BIOMETRIC_WEAK or
BiometricManager.Authenticators.BIOMETRIC_STRONG
BiometricManager.Authenticators.BIOMETRIC_STRONG
)
.setConfirmationRequired(false)
.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,7 @@ class PasswordOverlayActivity : FragmentActivity() {
.setSubtitle(getString(R.string.confirm_biometric_subtitle))
.setNegativeButtonText(getString(R.string.use_pin_button))
.setAllowedAuthenticators(
BiometricManager.Authenticators.BIOMETRIC_WEAK or
BiometricManager.Authenticators.BIOMETRIC_STRONG
BiometricManager.Authenticators.BIOMETRIC_STRONG
)
.setConfirmationRequired(false)
.build()
Expand Down Expand Up @@ -321,6 +320,17 @@ class PasswordOverlayActivity : FragmentActivity() {
super.onPause()
movedToBackground = true
AppLockManager.isLockScreenShown.set(false)

// Cancel biometric prompt if it's showing
if (isBiometricPromptShowingLocal) {
try {
biometricPrompt.cancelAuthentication()
} catch (e: IllegalStateException) {
Log.e(TAG, "Error canceling biometric prompt: ${e.message}")
}
isBiometricPromptShowingLocal = false
}

if (!isFinishing && !isDestroyed) {
AppLockManager.reportBiometricAuthFinished()
finish()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,14 +257,21 @@ class AppLockAccessibilityService : AccessibilityService() {
return
}

// Return if app is temporarily unlocked
if (AppLockManager.isAppTemporarilyUnlocked(packageName)) {
return
val unlockDurationMinutes = appLockRepository.getUnlockTimeDuration()

// If duration is 0 (lock immediately), skip temporarily unlocked check
// and clear unlock state immediately
if (unlockDurationMinutes == 0) {
AppLockManager.appUnlockTimes.remove(packageName)
} else {
// Return if app is temporarily unlocked (only when duration > 0)
if (AppLockManager.isAppTemporarilyUnlocked(packageName)) {
return
}
}

AppLockManager.clearTemporarilyUnlockedApp()

val unlockDurationMinutes = appLockRepository.getUnlockTimeDuration()
val unlockTimestamp = AppLockManager.appUnlockTimes[packageName] ?: 0L

Log.d(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,27 +82,31 @@ class ExperimentalAppLockService : Service() {
timer?.cancel()
timer = Timer()
timer?.schedule(timerTask {
if (!appLockRepository.isProtectEnabled() || applicationContext.isDeviceLocked()) {
if (applicationContext.isDeviceLocked()) {
AppLockManager.appUnlockTimes.clear()
try {
if (!appLockRepository.isProtectEnabled() || applicationContext.isDeviceLocked()) {
if (applicationContext.isDeviceLocked()) {
AppLockManager.appUnlockTimes.clear()
}
return@timerTask
}
return@timerTask
}

val foregroundApp = getCurrentForegroundAppPackage() ?: return@timerTask
val currentPackage = foregroundApp.first
val triggeringPackage = previousForegroundPackage
previousForegroundPackage = currentPackage
val foregroundApp = getCurrentForegroundAppPackage() ?: return@timerTask
val currentPackage = foregroundApp.first
val triggeringPackage = previousForegroundPackage
previousForegroundPackage = currentPackage

if (isExclusionApp(currentPackage)) return@timerTask
if (isExclusionApp(currentPackage)) return@timerTask

if (triggeringPackage in appLockRepository.getTriggerExcludedApps()) {
return@timerTask
}
if (triggeringPackage in appLockRepository.getTriggerExcludedApps()) {
return@timerTask
}

if (currentPackage == triggeringPackage) return@timerTask
if (currentPackage == triggeringPackage) return@timerTask

checkAndLockApp(currentPackage, triggeringPackage, System.currentTimeMillis())
checkAndLockApp(currentPackage, triggeringPackage, System.currentTimeMillis())
} catch (e: Exception) {
Log.e(TAG, "Error in monitoring timer task", e)
}
}, 0, 250)
}

Expand Down Expand Up @@ -149,6 +153,12 @@ class ExperimentalAppLockService : Service() {
if (packageName !in lockedApps) return

val unlockDurationMinutes = appLockRepository.getUnlockTimeDuration()

// If duration is 0 (lock immediately), clear any unlock state
if (unlockDurationMinutes == 0) {
AppLockManager.appUnlockTimes.remove(packageName)
}

val unlockTimestamp = AppLockManager.appUnlockTimes[packageName] ?: 0L

Log.d(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,24 +161,28 @@ class ShizukuAppLockService : Service() {
private fun setupShizukuActivityManager() {
shizukuActivityManager =
ShizukuActivityManager(this, appLockRepository) { packageName, _, timeMillis ->
val triggeringPackage = previousForegroundPackage
previousForegroundPackage = packageName

if (AppLockManager.isLockScreenShown.get() || packageName == this.packageName) {
return@ShizukuActivityManager
}

val triggerExclusions = appLockRepository.getTriggerExcludedApps()
if (triggeringPackage in triggerExclusions) {
Log.d(
TAG,
"Trigger app $triggeringPackage is excluded, skipping lock for $packageName"
)
return@ShizukuActivityManager
try {
val triggeringPackage = previousForegroundPackage
previousForegroundPackage = packageName

if (AppLockManager.isLockScreenShown.get() || packageName == this.packageName) {
return@ShizukuActivityManager
}

val triggerExclusions = appLockRepository.getTriggerExcludedApps()
if (triggeringPackage in triggerExclusions) {
Log.d(
TAG,
"Trigger app $triggeringPackage is excluded, skipping lock for $packageName"
)
return@ShizukuActivityManager
}

Log.d(TAG, "Current package=$packageName, trigger=$triggeringPackage")
checkAndLockApp(packageName, triggeringPackage, timeMillis)
} catch (e: Exception) {
Log.e(TAG, "Error in ShizukuActivityManager callback", e)
}

Log.d(TAG, "Current package=$packageName, trigger=$triggeringPackage")
checkAndLockApp(packageName, triggeringPackage, timeMillis)
}
}

Expand All @@ -188,6 +192,12 @@ class ShizukuAppLockService : Service() {
if (packageName !in lockedApps) return

val unlockDurationMinutes = appLockRepository.getUnlockTimeDuration()

// If duration is 0 (lock immediately), clear any unlock state
if (unlockDurationMinutes == 0) {
AppLockManager.appUnlockTimes.remove(packageName)
}

val unlockTimestamp = AppLockManager.appUnlockTimes[packageName] ?: 0L

Log.d(
Expand Down