add custom wipe on inactivity timings

This commit is contained in:
lucky 2022-06-28 07:45:33 +03:00
parent 1abfef163a
commit 4e8737e50e
19 changed files with 95 additions and 61 deletions

View File

@ -22,7 +22,7 @@ message with authentication code. On trigger, using
locks a device and optionally runs wipe. locks a device and optionally runs wipe.
Also you can: Also you can:
* wipe a device when it was not unlocked for N days * wipe a device when it was not unlocked for N time
* wipe a device using a duress password (companion app: [Duress](https://github.com/x13a/Duress)) * wipe a device using a duress password (companion app: [Duress](https://github.com/x13a/Duress))
The app works in `Work Profile` too. Use [Shelter](https://github.com/PeterCxy/Shelter) to install The app works in `Work Profile` too. Use [Shelter](https://github.com/PeterCxy/Shelter) to install

View File

@ -9,4 +9,4 @@
## Reporting a Vulnerability ## Reporting a Vulnerability
Contact: mailto:44uaanjm0@relay.firefox.com Contact: 44uaanjm0@relay.firefox.com

View File

@ -10,8 +10,8 @@ android {
applicationId "me.lucky.wasted" applicationId "me.lucky.wasted"
minSdk 23 minSdk 23
targetSdk 32 targetSdk 32
versionCode 25 versionCode 26
versionName "1.4.0" versionName "1.4.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }

View File

@ -12,9 +12,11 @@ import android.view.View
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.widget.doAfterTextChanged
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import java.util.* import java.util.*
import java.util.regex.Pattern
import kotlin.concurrent.timerTask import kotlin.concurrent.timerTask
import me.lucky.wasted.databinding.ActivityMainBinding import me.lucky.wasted.databinding.ActivityMainBinding
@ -22,6 +24,9 @@ import me.lucky.wasted.databinding.ActivityMainBinding
open class MainActivity : AppCompatActivity() { open class MainActivity : AppCompatActivity() {
companion object { companion object {
private const val CLIPBOARD_CLEAR_DELAY = 30_000L private const val CLIPBOARD_CLEAR_DELAY = 30_000L
private const val MODIFIER_DAYS = 'd'
private const val MODIFIER_HOURS = 'h'
private const val MODIFIER_MINUTES = 'm'
} }
private lateinit var binding: ActivityMainBinding private lateinit var binding: ActivityMainBinding
@ -29,6 +34,8 @@ open class MainActivity : AppCompatActivity() {
private lateinit var admin: DeviceAdminManager private lateinit var admin: DeviceAdminManager
private val shortcut by lazy { ShortcutManager(this) } private val shortcut by lazy { ShortcutManager(this) }
private val job by lazy { WipeJobManager(this) } private val job by lazy { WipeJobManager(this) }
private val wipeOnInactivityTimeRegex by lazy {
Pattern.compile("^[1-9]\\d*[$MODIFIER_DAYS$MODIFIER_HOURS$MODIFIER_MINUTES]$") }
private var clipboardManager: ClipboardManager? = null private var clipboardManager: ClipboardManager? = null
private var clipboardClearTask: Timer? = null private var clipboardClearTask: Timer? = null
@ -81,6 +88,7 @@ open class MainActivity : AppCompatActivity() {
wipeOnInactivitySwitch.isChecked = prefs.isWipeOnInactivity wipeOnInactivitySwitch.isChecked = prefs.isWipeOnInactivity
toggle.isChecked = prefs.isEnabled toggle.isChecked = prefs.isEnabled
} }
initWipeOnInactivityTime()
} }
private fun hideEmbeddedSim() { private fun hideEmbeddedSim() {
@ -96,22 +104,23 @@ open class MainActivity : AppCompatActivity() {
} }
} }
private fun initWipeOnInactivityTime() {
val count = prefs.wipeOnInactivityCount
val time = when {
count % (24 * 60) == 0 -> "${count / 24 / 60}$MODIFIER_DAYS"
count % 60 == 0 -> "${count / 60}$MODIFIER_HOURS"
else -> "$count$MODIFIER_MINUTES"
}
binding.wipeOnInactivityTime.editText?.setText(time)
}
private fun setup() { private fun setup() {
binding.apply { binding.apply {
authenticationCode.setOnClickListener { authenticationCode.setOnClickListener {
showTriggersSettings() showTriggersSettings()
} }
authenticationCode.setOnLongClickListener { authenticationCode.setOnLongClickListener {
clipboardManager copyAuthenticationCode()
?.setPrimaryClip(ClipData.newPlainText("", prefs.authenticationCode))
if (clipboardManager != null) {
scheduleClipboardClear()
Snackbar.make(
authenticationCode,
R.string.copied_popup,
Snackbar.LENGTH_SHORT,
).show()
}
true true
} }
wipeData.setOnCheckedChangeListener { _, isChecked -> wipeData.setOnCheckedChangeListener { _, isChecked ->
@ -125,9 +134,32 @@ open class MainActivity : AppCompatActivity() {
setWipeOnInactivityState(prefs.isEnabled && isChecked) setWipeOnInactivityState(prefs.isEnabled && isChecked)
prefs.isWipeOnInactivity = isChecked prefs.isWipeOnInactivity = isChecked
} }
wipeOnInactivitySwitch.setOnLongClickListener { wipeOnInactivityTime.editText?.doAfterTextChanged {
showWipeOnInactivitySettings() if (wipeOnInactivityTimeRegex.matcher(it?.toString() ?: "").matches()) {
true wipeOnInactivityTime.error = null
} else {
wipeOnInactivityTime.error = getString(R.string.wipe_on_inactivity_time_error)
}
}
wipeOnInactivityTime.setEndIconOnClickListener {
if (wipeOnInactivityTime.error != null) return@setEndIconOnClickListener
val time = wipeOnInactivityTime.editText?.text?.toString() ?: ""
if (time.length < 2) return@setEndIconOnClickListener
val modifier = time.last()
val i: Int
try {
i = time.dropLast(1).toInt()
} catch (exc: NumberFormatException) { return@setEndIconOnClickListener }
prefs.wipeOnInactivityCount = when (modifier) {
MODIFIER_DAYS -> i * 24 * 60
MODIFIER_HOURS -> i * 60
MODIFIER_MINUTES -> i
else -> return@setEndIconOnClickListener
}
if (prefs.isEnabled && prefs.isWipeOnInactivity) {
if (job.schedule() == JobScheduler.RESULT_FAILURE)
showWipeJobScheduleFailedPopup()
}
} }
toggle.setOnCheckedChangeListener { _, isChecked -> toggle.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) requestAdmin() else setOff() if (isChecked) requestAdmin() else setOff()
@ -135,6 +167,18 @@ open class MainActivity : AppCompatActivity() {
} }
} }
private fun copyAuthenticationCode() {
clipboardManager?.setPrimaryClip(ClipData.newPlainText("", prefs.authenticationCode))
if (clipboardManager != null) {
scheduleClipboardClear()
Snackbar.make(
binding.authenticationCode,
R.string.copied_popup,
Snackbar.LENGTH_SHORT,
).show()
}
}
private fun scheduleClipboardClear() { private fun scheduleClipboardClear() {
clipboardClearTask?.cancel() clipboardClearTask?.cancel()
clipboardClearTask = Timer() clipboardClearTask = Timer()
@ -174,27 +218,6 @@ open class MainActivity : AppCompatActivity() {
.show() .show()
} }
private fun showWipeOnInactivitySettings() {
val items = resources.getStringArray(R.array.wipe_on_inactivity_days)
var days = prefs.wipeOnInactivityCount / 24 / 60
var checked = items.indexOf(days.toString())
if (checked == -1) checked = items
.indexOf((Preferences.DEFAULT_WIPE_ON_INACTIVITY_COUNT / 24 / 60).toString())
MaterialAlertDialogBuilder(this)
.setTitle(R.string.wipe_on_inactivity_days)
.setSingleChoiceItems(items, checked) { _, which ->
days = items[which].toInt()
}
.setPositiveButton(android.R.string.ok) { _, _ ->
prefs.wipeOnInactivityCount = days * 24 * 60
if (prefs.isEnabled && prefs.isWipeOnInactivity) {
if (job.schedule() == JobScheduler.RESULT_FAILURE)
showWipeJobScheduleFailedPopup()
}
}
.show()
}
private fun updateCodeColorState() { private fun updateCodeColorState() {
binding.authenticationCode.setBackgroundColor(getColor( binding.authenticationCode.setBackgroundColor(getColor(
if (prefs.triggers != 0) R.color.code_on else R.color.code_off if (prefs.triggers != 0) R.color.code_on else R.color.code_off

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
</vector>

View File

@ -21,6 +21,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginVertical="16dp" android:layout_marginVertical="16dp"
android:isScrollContainer="false"
app:layout_constraintBottom_toTopOf="@+id/toggle" app:layout_constraintBottom_toTopOf="@+id/toggle"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@ -91,6 +92,28 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/wipe_on_inactivity_description" /> android:text="@string/wipe_on_inactivity_description" />
<Space
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"/>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/wipeOnInactivityTime"
app:helperText="@string/wipe_on_inactivity_time_helper_text"
app:helperTextEnabled="true"
app:errorEnabled="true"
app:endIconMode="custom"
app:endIconDrawable="@drawable/ic_baseline_check_circle_24"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/wipe_on_inactivity_time_hint" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

View File

@ -15,7 +15,6 @@
<string name="shortcut_label">Panik</string> <string name="shortcut_label">Panik</string>
<string name="wipe_on_inactivity_switch">Bei Inaktivität löschen</string> <string name="wipe_on_inactivity_switch">Bei Inaktivität löschen</string>
<string name="wipe_on_inactivity_description">Den Speicher des Geräts löschen, wenn es für N Tage nicht entsperrt wurde.</string> <string name="wipe_on_inactivity_description">Den Speicher des Geräts löschen, wenn es für N Tage nicht entsperrt wurde.</string>
<string name="wipe_on_inactivity_days">Tage</string>
<string name="notification_channel_default_name">Standard</string> <string name="notification_channel_default_name">Standard</string>
<string name="wipe_job_description">Den Speicher bei Inaktivität löschen</string> <string name="wipe_job_description">Den Speicher bei Inaktivität löschen</string>
<string name="wipe_job_schedule_failed_popup">Fehler bei der Durchführung des Wipes</string> <string name="wipe_job_schedule_failed_popup">Fehler bei der Durchführung des Wipes</string>

View File

@ -15,7 +15,6 @@
<string name="shortcut_label">Pánico</string> <string name="shortcut_label">Pánico</string>
<string name="wipe_on_inactivity_switch">Borrar por inactividad</string> <string name="wipe_on_inactivity_switch">Borrar por inactividad</string>
<string name="wipe_on_inactivity_description">Limpia un dispositivo cuando no fue desbloqueado por N días.</string> <string name="wipe_on_inactivity_description">Limpia un dispositivo cuando no fue desbloqueado por N días.</string>
<string name="wipe_on_inactivity_days">Días</string>
<string name="notification_channel_default_name">Predeterminado</string> <string name="notification_channel_default_name">Predeterminado</string>
<string name="wipe_job_description">Borrar un dispositivo por inactividad</string> <string name="wipe_job_description">Borrar un dispositivo por inactividad</string>
<string name="wipe_job_schedule_failed_popup">Error al programar un trabajo de borrado</string> <string name="wipe_job_schedule_failed_popup">Error al programar un trabajo de borrado</string>

View File

@ -15,7 +15,6 @@
<string name="shortcut_label">Panico</string> <string name="shortcut_label">Panico</string>
<string name="wipe_on_inactivity_switch">Cancella in caso di inattività</string> <string name="wipe_on_inactivity_switch">Cancella in caso di inattività</string>
<string name="wipe_on_inactivity_description">Cancella i dati quando il dispositivo non viene sbloccato per N giorni.</string> <string name="wipe_on_inactivity_description">Cancella i dati quando il dispositivo non viene sbloccato per N giorni.</string>
<string name="wipe_on_inactivity_days">Giorni</string>
<string name="notification_channel_default_name">Predefinito</string> <string name="notification_channel_default_name">Predefinito</string>
<string name="wipe_job_description">Cancella i dati in caso di inattività</string> <string name="wipe_job_description">Cancella i dati in caso di inattività</string>
<string name="wipe_job_schedule_failed_popup">Impossibile pianificare un processo di cancellazione</string> <string name="wipe_job_schedule_failed_popup">Impossibile pianificare un processo di cancellazione</string>

View File

@ -15,7 +15,6 @@
<string name="shortcut_label">Тревога</string> <string name="shortcut_label">Тревога</string>
<string name="wipe_on_inactivity_switch">Стереть при неактивности</string> <string name="wipe_on_inactivity_switch">Стереть при неактивности</string>
<string name="wipe_on_inactivity_description">Стереть данные когда устройство не разблокируется N дней.</string> <string name="wipe_on_inactivity_description">Стереть данные когда устройство не разблокируется N дней.</string>
<string name="wipe_on_inactivity_days">Дней</string>
<string name="notification_channel_default_name">По умолчанию</string> <string name="notification_channel_default_name">По умолчанию</string>
<string name="wipe_job_description">Стереть данные при неактивности</string> <string name="wipe_job_description">Стереть данные при неактивности</string>
<string name="wipe_job_schedule_failed_popup">Не удалось запланировать сервис стирания данных</string> <string name="wipe_job_schedule_failed_popup">Не удалось запланировать сервис стирания данных</string>

View File

@ -15,7 +15,6 @@
<string name="shortcut_label">Panik</string> <string name="shortcut_label">Panik</string>
<string name="wipe_on_inactivity_switch">Kullanılmadığında sil</string> <string name="wipe_on_inactivity_switch">Kullanılmadığında sil</string>
<string name="wipe_on_inactivity_description">N gün boyunca kilidi açılmamış bir cihazı silin.</string> <string name="wipe_on_inactivity_description">N gün boyunca kilidi açılmamış bir cihazı silin.</string>
<string name="wipe_on_inactivity_days">Gün</string>
<string name="notification_channel_default_name">Varsayılan</string> <string name="notification_channel_default_name">Varsayılan</string>
<string name="wipe_job_description">Cihaz kullanılmadığında siler</string> <string name="wipe_job_description">Cihaz kullanılmadığında siler</string>
<string name="wipe_job_schedule_failed_popup">Silme işi zamanlanamadı</string> <string name="wipe_job_schedule_failed_popup">Silme işi zamanlanamadı</string>

View File

@ -15,7 +15,6 @@
<string name="shortcut_label">Тривога</string> <string name="shortcut_label">Тривога</string>
<string name="wipe_on_inactivity_switch">Wipe on inactivity</string> <string name="wipe_on_inactivity_switch">Wipe on inactivity</string>
<string name="wipe_on_inactivity_description">Видалення пристрою, коли його не було розблоковано протягом N днів.</string> <string name="wipe_on_inactivity_description">Видалення пристрою, коли його не було розблоковано протягом N днів.</string>
<string name="wipe_on_inactivity_days">Днів</string>
<string name="notification_channel_default_name">За замовчуванням</string> <string name="notification_channel_default_name">За замовчуванням</string>
<string name="wipe_job_description">Wipe a device on inactivity</string> <string name="wipe_job_description">Wipe a device on inactivity</string>
<string name="wipe_job_schedule_failed_popup">Failed to schedule a wipe job</string> <string name="wipe_job_schedule_failed_popup">Failed to schedule a wipe job</string>

View File

@ -15,7 +15,6 @@
<string name="shortcut_label">紧急</string> <string name="shortcut_label">紧急</string>
<string name="wipe_on_inactivity_switch">在不使用时擦除</string> <string name="wipe_on_inactivity_switch">在不使用时擦除</string>
<string name="wipe_on_inactivity_description">当设备在N天内没被解锁时擦除</string> <string name="wipe_on_inactivity_description">当设备在N天内没被解锁时擦除</string>
<string name="wipe_on_inactivity_days">天数</string>
<string name="notification_channel_default_name">默认设置</string> <string name="notification_channel_default_name">默认设置</string>
<string name="wipe_job_description">擦除不使用的设备</string> <string name="wipe_job_description">擦除不使用的设备</string>
<string name="wipe_job_schedule_failed_popup">无法制定擦除计划</string> <string name="wipe_job_schedule_failed_popup">无法制定擦除计划</string>

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="wipe_on_inactivity_days">
<item>1</item>
<item>2</item>
<item>3</item>
<item>5</item>
<item>7</item>
<item>10</item>
<item>15</item>
<item>30</item>
</string-array>
</resources>

View File

@ -14,8 +14,10 @@
<string name="tile_label">Airplane mode</string> <string name="tile_label">Airplane mode</string>
<string name="shortcut_label">Panic</string> <string name="shortcut_label">Panic</string>
<string name="wipe_on_inactivity_switch">Wipe on inactivity</string> <string name="wipe_on_inactivity_switch">Wipe on inactivity</string>
<string name="wipe_on_inactivity_description">Wipe a device when it was not unlocked for N days.</string> <string name="wipe_on_inactivity_description">Wipe a device when it was not unlocked for N time.</string>
<string name="wipe_on_inactivity_days">Days</string> <string name="wipe_on_inactivity_time_hint">time</string>
<string name="wipe_on_inactivity_time_error">7d / 48h / 120m</string>
<string name="wipe_on_inactivity_time_helper_text">[d]ays [h]ours [m]inutes</string>
<string name="notification_channel_default_name">Default</string> <string name="notification_channel_default_name">Default</string>
<string name="wipe_job_description">Wipe a device on inactivity</string> <string name="wipe_job_description">Wipe a device on inactivity</string>
<string name="wipe_job_schedule_failed_popup">Failed to schedule a wipe job</string> <string name="wipe_job_schedule_failed_popup">Failed to schedule a wipe job</string>

View File

@ -0,0 +1 @@
add custom wipe on inactivity timings

View File

@ -4,7 +4,7 @@ You can use PanicKit, tile, shortcut or send a message with authentication code.
Device Administration API, it locks a device and optionally runs wipe. Device Administration API, it locks a device and optionally runs wipe.
Also you can: Also you can:
* wipe a device when it was not unlocked for N days * wipe a device when it was not unlocked for N time
* wipe a device using a duress password (companion app: [Duress](https://github.com/x13a/Duress)) * wipe a device using a duress password (companion app: [Duress](https://github.com/x13a/Duress))
The app works in Work Profile too. Use Shelter to install risky apps and Wasted in it. Then you can The app works in Work Profile too. Use Shelter to install risky apps and Wasted in it. Then you can

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB