Skip to content

Commit

Permalink
Merge pull request #6 from nain-F49FF806/configurable-autolock-delay
Browse files Browse the repository at this point in the history
Configurable autolock delay

resolves #5
  • Loading branch information
nain-F49FF806 authored Dec 7, 2024
2 parents bb84db5 + 15588ff commit aa88f06
Show file tree
Hide file tree
Showing 14 changed files with 140 additions and 31 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Moreover it provides ways for the user to export contents from other apps and sa
- An optional shortcut for devices that do not expose the system Files app is offered
- Lock access to the private storage
- Quick tile
- Auto lock after 15 minutes
- **Auto lock after set delay**
- Password for locking access to the files
- Import content using the share Android functionality
- **Option to select which private storage location to use**
Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ android {
defaultConfig {
minSdk = rootProject.extra["minSdkVersion"] as Int
targetSdk = rootProject.extra["targetSdkVersion"] as Int
versionCode = 1730403000
versionName = "2024.10.31"
versionCode = 1733570000
versionName = "2024.12.07"
applicationId = "alt.nainapps.aer"
vectorDrawables {
useSupportLibrary = true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
/*
* Copyright (c) 2022 2bllw8
* Copyright (c) 2024 nain
* SPDX-License-Identifier: GPL-3.0-only
*/
package alt.nainapps.aer.config

import alt.nainapps.aer.R
import alt.nainapps.aer.config.autolock.buildValidatedAutoLockDelayListener
import alt.nainapps.aer.config.password.ChangePasswordDialog
import alt.nainapps.aer.config.password.SetPasswordDialog
import alt.nainapps.aer.lock.LockStore
Expand All @@ -13,8 +15,10 @@ import alt.nainapps.aer.shell.AnemoShell
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.view.View
import android.widget.CompoundButton
import android.widget.EditText
import android.widget.Switch
import android.widget.TextView
import java.util.function.Consumer
Expand Down Expand Up @@ -68,6 +72,13 @@ class ConfigurationActivity : Activity() {
lockStore.isAutoLockEnabled = isChecked
}

val autoLockDelayMinutesEditable = findViewById<EditText>(R.id.config_auto_lock_delay_minutes)
autoLockDelayMinutesEditable.text = Editable.Factory.getInstance().newEditable(
lockStore.autoLockDelayMinutes.toString()
)
val autoLockDelayListener = buildValidatedAutoLockDelayListener(this.baseContext, lockStore, autoLockDelayMinutesEditable)
autoLockDelayMinutesEditable.addTextChangedListener(autoLockDelayListener)

biometricSwitch = findViewById(R.id.configuration_biometric_unlock)
biometricSwitch!!.visibility = if (lockStore.canAuthenticateBiometric()) View.VISIBLE else View.GONE
biometricSwitch!!.isChecked = lockStore.isBiometricUnlockEnabled
Expand Down Expand Up @@ -120,4 +131,4 @@ class ConfigurationActivity : Activity() {
},
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2024 nain
* SPDX-License-Identifier: GPL-3.0-only
*/

package alt.nainapps.aer.config.autolock

import alt.nainapps.aer.R
import alt.nainapps.aer.lock.LockStore
import android.content.Context
import android.text.Editable
import android.text.TextWatcher
import android.widget.EditText

fun interface AutoLockDelayMinutesTextListener : TextWatcher {

override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable) {
afterTextChanged(s.toString())
}
// this will be provided as lambda
fun afterTextChanged(text: String)
}

fun buildValidatedAutoLockDelayListener(context: Context, lockstore: LockStore, input: EditText): AutoLockDelayMinutesTextListener {
return AutoLockDelayMinutesTextListener { text ->
// validate text isNumber
try {
text.toLong()
} catch (error: NumberFormatException) {
input.setError("NaN: Not a Number",
context.getDrawable(R.drawable.ic_error))
return@AutoLockDelayMinutesTextListener
}
val minutes: Long = text.toLong()
// validate not zero
if (minutes == 0L) {
input.setError("Auto lock delay can't be zero",
context.getDrawable(R.drawable.ic_error))
}
lockstore.autoLockDelayMinutes = minutes
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ class ChangePasswordDialog(activity: Activity, lockStore: LockStore, onSuccess:
private fun buildTextListener(
passwordField: EditText, repeatField: EditText,
positiveBtn: Button
): TextListener {
return TextListener {
): PasswordTextListener {
return PasswordTextListener {
val passwordValue = passwordField.text.toString()
val repeatValue = repeatField.text.toString()
if (passwordValue.length < MIN_PASSWORD_LENGTH) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ package alt.nainapps.aer.config.password
import android.text.Editable
import android.text.TextWatcher

fun interface TextListener : TextWatcher {
fun interface PasswordTextListener : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ class SetPasswordDialog(activity: Activity, lockStore: LockStore, onSuccess: Run
private fun buildValidator(
passwordField: EditText, repeatField: EditText,
positiveBtn: Button
): TextListener {
return TextListener {
): PasswordTextListener {
return PasswordTextListener {
val passwordValue = passwordField.text.toString()
val repeatValue = repeatField.text.toString()
if (passwordValue.length < MIN_PASSWORD_LENGTH) {
Expand Down
29 changes: 25 additions & 4 deletions app/src/main/java/alt/nainapps/aer/lock/LockStore.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2021 2bllw8
* Copyright (c) 2024 nain
* SPDX-License-Identifier: GPL-3.0-only
*/
package alt.nainapps.aer.lock
Expand Down Expand Up @@ -114,6 +115,22 @@ class LockStore private constructor(context: Context) : OnSharedPreferenceChange
}
}

@get:Synchronized
@set:Synchronized
var autoLockDelayMinutes: Long
get() = preferences.getLong(KEY_AUTO_LOCK_DELAY_MINUTES, DEFAULT_AUTO_LOCK_DELAY_MINUTES)
set(delayMinutes) {
preferences.edit().putLong(KEY_AUTO_LOCK_DELAY_MINUTES, delayMinutes).apply()

if (!isLocked) {
if (isAutoLockEnabled) {
// If auto-lock is enabled while the storage is unlocked, schedule new job
cancelAutoLock()
scheduleAutoLock()
}
}
}

fun canAuthenticateBiometric(): Boolean {
return Build.VERSION.SDK_INT >= 29 && biometricManager != null && biometricManager.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS
}
Expand Down Expand Up @@ -146,7 +163,7 @@ class LockStore private constructor(context: Context) : OnSharedPreferenceChange
private fun scheduleAutoLock() {
jobScheduler.schedule(
JobInfo.Builder(AUTO_LOCK_JOB_ID, autoLockComponent)
.setMinimumLatency(AUTO_LOCK_DELAY)
.setMinimumLatency(millisFromMinutes(autoLockDelayMinutes))
.build()
)
}
Expand All @@ -166,24 +183,28 @@ class LockStore private constructor(context: Context) : OnSharedPreferenceChange
}
}

// convert minutes to milliseconds
private fun millisFromMinutes(minutes: Long): Long {
return minutes * 60L * 1000L
}

companion object {
private const val TAG = "LockStore"

private const val LOCK_PREFERENCES = "lock_store"
private const val KEY_LOCK = "is_locked"
private const val KEY_PASSWORD = "password_hash"
private const val KEY_AUTO_LOCK = "auto_lock"
private const val KEY_AUTO_LOCK_DELAY_MINUTES = "auto_lock_delay_minutes"
private const val KEY_BIOMETRIC_UNLOCK = "biometric_unlock"
private const val DEFAULT_LOCK_VALUE = false
private const val DEFAULT_AUTO_LOCK_VALUE = false
private const val DEFAULT_AUTO_LOCK_DELAY_MINUTES = 15L

private const val HASH_ALGORITHM = "SHA-256"

private const val AUTO_LOCK_JOB_ID = 64

// 15 minutes in milliseconds
private const val AUTO_LOCK_DELAY = 1000L * 60L * 15L

@Volatile
private var instance: LockStore? = null

Expand Down
12 changes: 6 additions & 6 deletions app/src/main/java/alt/nainapps/aer/lock/UnlockActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
*/
package alt.nainapps.aer.lock

import alt.nainapps.aer.R
import alt.nainapps.aer.config.ConfigurationActivity
import alt.nainapps.aer.config.password.PasswordTextListener
import alt.nainapps.aer.lock.LockStore.Companion.getInstance
import alt.nainapps.aer.shell.LauncherActivity
import android.app.Activity
import android.content.DialogInterface
import android.content.Intent
Expand All @@ -15,11 +20,6 @@ import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import androidx.annotation.RequiresApi
import alt.nainapps.aer.R
import alt.nainapps.aer.config.ConfigurationActivity
import alt.nainapps.aer.config.password.TextListener
import alt.nainapps.aer.lock.LockStore.Companion.getInstance
import alt.nainapps.aer.shell.LauncherActivity

class UnlockActivity : Activity() {
private var lockStore: LockStore? = null
Expand Down Expand Up @@ -50,7 +50,7 @@ class UnlockActivity : Activity() {
val unlockBtn = findViewById<Button>(R.id.unlockButton)
val cancelBtn = findViewById<Button>(R.id.cancelButton)

passwordField.addTextChangedListener(TextListener { text: String? ->
passwordField.addTextChangedListener(PasswordTextListener { text: String? ->
unlockBtn.isEnabled = passwordField.text.length >= MIN_PASSWORD_LENGTH
})

Expand Down
38 changes: 34 additions & 4 deletions app/src/main/res/layout/configuration.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<!--
~ Copyright (c) 2022 2bllw8
~ Copyright (c) 2024 nain
~ SPDX-License-Identifier: GPL-3.0-only
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
Expand Down Expand Up @@ -56,23 +57,52 @@
tools:text="@string/configuration_password_set" />

<Switch
android:id="@+id/configuration_auto_lock"
android:id="@+id/configuration_biometric_unlock"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?android:attr/selectableItemBackground"
android:minHeight="56dp"
android:paddingHorizontal="16dp"
android:text="@string/configuration_storage_lock_auto"
android:text="@string/configuration_storage_unlock_biometric"
android:textSize="16sp" />

<Switch
android:id="@+id/configuration_biometric_unlock"
android:id="@+id/configuration_auto_lock"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?android:attr/selectableItemBackground"
android:minHeight="56dp"
android:paddingHorizontal="16dp"
android:text="@string/configuration_storage_unlock_biometric"
android:text="@string/configuration_storage_lock_auto"
android:textSize="16sp" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">

<TextView
android:id="@+id/configuration_auto_lock_delay_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:labelFor="@+id/config_auto_lock_delay_minutes"
android:paddingHorizontal="16dp"
android:text="@string/configuration_auto_lock_delay_minutes_label"
android:textColor="?android:textColorPrimary"
android:textSize="16sp"
tools:text="@string/configuration_auto_lock_delay_minutes_label" />

<EditText
android:id="@+id/config_auto_lock_delay_minutes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autofillHints="autoLockDelayMinutes"
android:minHeight="56dp"
android:minEms="3"
android:maxEms="5"
android:inputType="number" />
</LinearLayout>


</LinearLayout>
</ScrollView>
3 changes: 2 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,13 @@
<string name="configuration_storage_lock">Lock storage access</string>
<string name="configuration_storage_unlock">Unlock storage access</string>
<string name="configuration_storage_unlock_biometric">Allow storage unlock with biometric access</string>
<string name="configuration_storage_lock_auto">Automatically lock access after 15 minutes</string>
<string name="configuration_storage_lock_auto">Automatically lock access after delay</string>
<string name="title_activity_storage_pref">StoragePrefActivity</string>
<string name="shortcut_storageconfig_long">Storage Configuration</string>
<string name="shortcut_storageconfig_short">Storage Config</string>
<string name="shortcut_storageconfig_disabled">Storage Config (Disabled)</string>
<string name="storage_config_select_help">Tap to select / Drag to reorder:</string>
<string name="storage_config_screen_title">Aer Storage Backend</string>
<string name="configuration_auto_lock_delay_minutes_label">Auto lock delay (in minutes)</string>

</resources>
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ if (file('local.properties').exists()) {

ext {
minSdkVersion = 26
targetSdkVersion = 34
targetSdkVersion = 35

sourceCompatibilityVersion = JavaVersion.VERSION_17
targetCompatibilityVersion = JavaVersion.VERSION_17
Expand Down
10 changes: 5 additions & 5 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[versions]
annotation = "1.8.2"
coreKtx = "1.13.1"
annotation = "1.9.1"
coreKtx = "1.15.0"
eitherLib = "3.4.0"
agp = "8.6.1"
kotlin = "2.0.20"
exifinterface = "1.3.7"
lifecycleRuntimeKtx = "2.8.6"
activityCompose = "1.9.2"
composeBom = "2024.09.02"
lifecycleRuntimeKtx = "2.8.7"
activityCompose = "1.9.3"
composeBom = "2024.11.00"
reorderable = "2.3.3"


Expand Down
2 changes: 1 addition & 1 deletion metadata/en-US/full_description.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Features
- The system Files app is also used as file picker, so you can pick Aer files to share
- Lock access to the private storage
- Quick tile
- Auto lock after 15 minutes
- Auto lock after set delay
- Password for locking access to the files
- Import content into Aer using the Android share functionality

Expand Down

0 comments on commit aa88f06

Please sign in to comment.