v1.4.0
remove all preferences migrations, you have to reconfigure Wasted !! .CodeReceiver renamed to .TriggerReceiver !! remove max failed password attempts, migrate to Sentry add copy authentication code with a long click add Chinese Simplified, German, Spanish, Turkish, Ukrainian translations update Italian translation under the hood improvements Thanks to: Alex Ortiz Alexander Sergevich Noah Fisker SuperM TolDYuThad Wong Anny Giovanni Donisi (@gdonisi + @giovannidonisi)
|
@ -0,0 +1,10 @@
|
||||||
|
name: "Validate Gradle Wrapper"
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validation:
|
||||||
|
name: "Validation"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: gradle/wrapper-validation-action@v1
|
|
@ -1,6 +1,6 @@
|
||||||
# Wasted
|
# Wasted
|
||||||
|
|
||||||
Lock a device and wipe its data on danger.
|
Lock a device and wipe its data on emergency.
|
||||||
|
|
||||||
[<img
|
[<img
|
||||||
src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
|
@ -22,8 +22,8 @@ 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:
|
||||||
* limit the maximum number of failed password attempts
|
|
||||||
* wipe a device when it was not unlocked for N days
|
* wipe a device when it was not unlocked for N days
|
||||||
|
* 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
|
||||||
risky apps and `Wasted` in it. Then you can wipe this profile data with one click without wiping
|
risky apps and `Wasted` in it. Then you can wipe this profile data with one click without wiping
|
||||||
|
@ -43,7 +43,7 @@ Broadcast:
|
||||||
```sh
|
```sh
|
||||||
$ adb shell am broadcast \
|
$ adb shell am broadcast \
|
||||||
-a me.lucky.wasted.action.TRIGGER \
|
-a me.lucky.wasted.action.TRIGGER \
|
||||||
-n me.lucky.wasted/.CodeReceiver \
|
-n me.lucky.wasted/.TriggerReceiver \
|
||||||
-e code "b49a6576-0c27-4f03-b96b-da53501022ba"
|
-e code "b49a6576-0c27-4f03-b96b-da53501022ba"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ android {
|
||||||
applicationId "me.lucky.wasted"
|
applicationId "me.lucky.wasted"
|
||||||
minSdk 23
|
minSdk 23
|
||||||
targetSdk 32
|
targetSdk 32
|
||||||
versionCode 24
|
versionCode 25
|
||||||
versionName "1.3.4"
|
versionName "1.4.0"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
@ -39,10 +39,10 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.core:core-ktx:1.7.0'
|
implementation 'androidx.core:core-ktx:1.8.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
implementation 'androidx.appcompat:appcompat:1.4.2'
|
||||||
implementation 'com.google.android.material:material:1.5.0'
|
implementation 'com.google.android.material:material:1.6.1'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||||
testImplementation 'junit:junit:4.13.2'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".CodeReceiver"
|
android:name=".TriggerReceiver"
|
||||||
android:enabled="false"
|
android:enabled="false"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
tools:ignore="ExportedReceiver">
|
tools:ignore="ExportedReceiver">
|
||||||
|
|
|
@ -13,8 +13,7 @@ class DeviceAdminManager(private val ctx: Context) {
|
||||||
private val prefs by lazy { Preferences(ctx) }
|
private val prefs by lazy { Preferences(ctx) }
|
||||||
|
|
||||||
fun remove() = dpm?.removeActiveAdmin(deviceAdmin)
|
fun remove() = dpm?.removeActiveAdmin(deviceAdmin)
|
||||||
fun isActive(): Boolean = dpm?.isAdminActive(deviceAdmin) ?: false
|
fun isActive() = dpm?.isAdminActive(deviceAdmin) ?: false
|
||||||
fun getCurrentFailedPasswordAttempts(): Int = dpm?.currentFailedPasswordAttempts ?: 0
|
|
||||||
|
|
||||||
fun lockNow() { if (!lockPrivilegedNow()) dpm?.lockNow() }
|
fun lockNow() { if (!lockPrivilegedNow()) dpm?.lockNow() }
|
||||||
|
|
||||||
|
@ -31,25 +30,20 @@ class DeviceAdminManager(private val ctx: Context) {
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setMaximumFailedPasswordsForWipe(num: Int) {
|
|
||||||
dpm?.setMaximumFailedPasswordsForWipe(deviceAdmin, num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun wipeData() {
|
fun wipeData() {
|
||||||
var flags = 0
|
var flags = 0
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||||
flags = flags.or(DevicePolicyManager.WIPE_SILENTLY)
|
flags = flags.or(DevicePolicyManager.WIPE_SILENTLY)
|
||||||
if (prefs.isWipeESIM && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
if (prefs.isWipeEmbeddedSim && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
||||||
flags = flags.or(DevicePolicyManager.WIPE_EUICC)
|
flags = flags.or(DevicePolicyManager.WIPE_EUICC)
|
||||||
dpm?.wipeData(flags)
|
dpm?.wipeData(flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun makeRequestIntent(): Intent {
|
fun makeRequestIntent() =
|
||||||
return Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
|
Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
|
||||||
.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, deviceAdmin)
|
.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, deviceAdmin)
|
||||||
.putExtra(
|
.putExtra(
|
||||||
DevicePolicyManager.EXTRA_ADD_EXPLANATION,
|
DevicePolicyManager.EXTRA_ADD_EXPLANATION,
|
||||||
ctx.getString(R.string.device_admin_description),
|
ctx.getString(R.string.device_admin_description),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -3,30 +3,12 @@ package me.lucky.wasted
|
||||||
import android.app.admin.DeviceAdminReceiver
|
import android.app.admin.DeviceAdminReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.UserHandle
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
|
||||||
class DeviceAdminReceiver : DeviceAdminReceiver() {
|
class DeviceAdminReceiver : DeviceAdminReceiver() {
|
||||||
override fun onPasswordFailed(context: Context, intent: Intent, user: UserHandle) {
|
|
||||||
super.onPasswordFailed(context, intent, user)
|
|
||||||
val prefs = Preferences(context)
|
|
||||||
val maxFailedPasswordAttempts = prefs.maxFailedPasswordAttempts
|
|
||||||
if (!prefs.isServiceEnabled || maxFailedPasswordAttempts <= 0) return
|
|
||||||
val admin = DeviceAdminManager(context)
|
|
||||||
if (admin.getCurrentFailedPasswordAttempts() >= maxFailedPasswordAttempts)
|
|
||||||
admin.wipeData()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDisabled(context: Context, intent: Intent) {
|
override fun onDisabled(context: Context, intent: Intent) {
|
||||||
super.onDisabled(context, intent)
|
super.onDisabled(context, intent)
|
||||||
if (Preferences(context).isServiceEnabled)
|
if (Preferences(context).isEnabled)
|
||||||
Toast.makeText(context, R.string.service_unavailable_popup, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, R.string.service_unavailable_popup, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onEnabled(context: Context, intent: Intent) {
|
|
||||||
super.onEnabled(context, intent)
|
|
||||||
DeviceAdminManager(context)
|
|
||||||
.setMaximumFailedPasswordsForWipe(Preferences(context)
|
|
||||||
.maxFailedPasswordAttempts.shl(1))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,8 @@ class ForegroundService : Service() {
|
||||||
|
|
||||||
private class UnlockReceiver : BroadcastReceiver() {
|
private class UnlockReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
if (context?.getSystemService(KeyguardManager::class.java)?.isDeviceSecure != true ||
|
if (intent?.action != Intent.ACTION_USER_PRESENT ||
|
||||||
|
context?.getSystemService(KeyguardManager::class.java)?.isDeviceSecure != true ||
|
||||||
!Preferences(context).isWipeOnInactivity) return
|
!Preferences(context).isWipeOnInactivity) return
|
||||||
Thread(Runner(context, goAsync())).start()
|
Thread(Runner(context, goAsync())).start()
|
||||||
}
|
}
|
||||||
|
@ -64,9 +65,9 @@ class ForegroundService : Service() {
|
||||||
private val pendingResult: PendingResult,
|
private val pendingResult: PendingResult,
|
||||||
) : Runnable {
|
) : Runnable {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val manager = WipeJobManager(ctx)
|
val job = WipeJobManager(ctx)
|
||||||
var delay = 1000L
|
var delay = 1000L
|
||||||
while (manager.schedule() != JobScheduler.RESULT_SUCCESS) {
|
while (job.schedule() != JobScheduler.RESULT_SUCCESS) {
|
||||||
Thread.sleep(delay)
|
Thread.sleep(delay)
|
||||||
delay = delay.shl(1)
|
delay = delay.shl(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package me.lucky.wasted
|
package me.lucky.wasted
|
||||||
|
|
||||||
import android.app.job.JobScheduler
|
import android.app.job.JobScheduler
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
@ -13,15 +15,22 @@ import androidx.core.content.ContextCompat
|
||||||
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 kotlin.concurrent.timerTask
|
||||||
|
|
||||||
import me.lucky.wasted.databinding.ActivityMainBinding
|
import me.lucky.wasted.databinding.ActivityMainBinding
|
||||||
|
|
||||||
open class MainActivity : AppCompatActivity() {
|
open class MainActivity : AppCompatActivity() {
|
||||||
|
companion object {
|
||||||
|
private const val CLIPBOARD_CLEAR_DELAY = 30_000L
|
||||||
|
}
|
||||||
|
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
private lateinit var prefs: Preferences
|
private lateinit var prefs: Preferences
|
||||||
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 var clipboardManager: ClipboardManager? = null
|
||||||
|
private var clipboardClearTask: Timer? = null
|
||||||
|
|
||||||
private val registerForDeviceAdmin =
|
private val registerForDeviceAdmin =
|
||||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
|
@ -45,7 +54,7 @@ open class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun update() {
|
private fun update() {
|
||||||
if (prefs.isServiceEnabled && !admin.isActive())
|
if (prefs.isEnabled && !admin.isActive())
|
||||||
Snackbar.make(
|
Snackbar.make(
|
||||||
binding.toggle,
|
binding.toggle,
|
||||||
R.string.service_unavailable_popup,
|
R.string.service_unavailable_popup,
|
||||||
|
@ -56,35 +65,32 @@ open class MainActivity : AppCompatActivity() {
|
||||||
private fun init() {
|
private fun init() {
|
||||||
prefs = Preferences(this)
|
prefs = Preferences(this)
|
||||||
admin = DeviceAdminManager(this)
|
admin = DeviceAdminManager(this)
|
||||||
|
clipboardManager = getSystemService(ClipboardManager::class.java)
|
||||||
NotificationManager(this).createNotificationChannels()
|
NotificationManager(this).createNotificationChannels()
|
||||||
if (prefs.code == "") prefs.code = makeCode()
|
if (prefs.authenticationCode.isEmpty()) prefs.authenticationCode = makeAuthenticationCode()
|
||||||
updateCodeColorState()
|
updateCodeColorState()
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) hideESIM()
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) hideEmbeddedSim()
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
|
||||||
!packageManager.hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN))
|
!packageManager.hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN))
|
||||||
hideSecureLockScreenRequired()
|
hideSecureLockScreenRequired()
|
||||||
binding.apply {
|
binding.apply {
|
||||||
code.text = prefs.code
|
authenticationCode.text = prefs.authenticationCode
|
||||||
wipeData.isChecked = prefs.isWipeData
|
wipeData.isChecked = prefs.isWipeData
|
||||||
wipeESIM.isChecked = prefs.isWipeESIM
|
wipeEmbeddedSim.isChecked = prefs.isWipeEmbeddedSim
|
||||||
wipeESIM.isEnabled = wipeData.isChecked
|
wipeEmbeddedSim.isEnabled = wipeData.isChecked
|
||||||
maxFailedPasswordAttempts.value = prefs.maxFailedPasswordAttempts.toFloat()
|
|
||||||
wipeOnInactivitySwitch.isChecked = prefs.isWipeOnInactivity
|
wipeOnInactivitySwitch.isChecked = prefs.isWipeOnInactivity
|
||||||
toggle.isChecked = prefs.isServiceEnabled
|
toggle.isChecked = prefs.isEnabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hideESIM() {
|
private fun hideEmbeddedSim() {
|
||||||
binding.wipeESIMSpace.visibility = View.GONE
|
binding.wipeSpace.visibility = View.GONE
|
||||||
binding.wipeESIM.visibility = View.GONE
|
binding.wipeEmbeddedSim.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hideSecureLockScreenRequired() {
|
private fun hideSecureLockScreenRequired() {
|
||||||
binding.apply {
|
binding.apply {
|
||||||
divider.visibility = View.GONE
|
divider.visibility = View.GONE
|
||||||
maxFailedPasswordAttempts.visibility = View.GONE
|
|
||||||
maxFailedPasswordAttemptsDescription.visibility = View.GONE
|
|
||||||
wipeOnInactivitySpace.visibility = View.GONE
|
|
||||||
wipeOnInactivitySwitch.visibility = View.GONE
|
wipeOnInactivitySwitch.visibility = View.GONE
|
||||||
wipeOnInactivityDescription.visibility = View.GONE
|
wipeOnInactivityDescription.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
@ -92,30 +98,31 @@ open class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private fun setup() {
|
private fun setup() {
|
||||||
binding.apply {
|
binding.apply {
|
||||||
code.setOnClickListener {
|
authenticationCode.setOnClickListener {
|
||||||
showTriggersSettings()
|
showTriggersSettings()
|
||||||
}
|
}
|
||||||
code.setOnLongClickListener {
|
authenticationCode.setOnLongClickListener {
|
||||||
prefs.code = makeCode()
|
clipboardManager
|
||||||
code.text = prefs.code
|
?.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 ->
|
||||||
prefs.isWipeData = isChecked
|
prefs.isWipeData = isChecked
|
||||||
wipeESIM.isEnabled = isChecked
|
wipeEmbeddedSim.isEnabled = isChecked
|
||||||
}
|
}
|
||||||
wipeESIM.setOnCheckedChangeListener { _, isChecked ->
|
wipeEmbeddedSim.setOnCheckedChangeListener { _, isChecked ->
|
||||||
prefs.isWipeESIM = isChecked
|
prefs.isWipeEmbeddedSim = isChecked
|
||||||
}
|
|
||||||
maxFailedPasswordAttempts.addOnChangeListener { _, value, _ ->
|
|
||||||
val num = value.toInt()
|
|
||||||
prefs.maxFailedPasswordAttempts = num
|
|
||||||
try {
|
|
||||||
admin.setMaximumFailedPasswordsForWipe(num.shl(1))
|
|
||||||
} catch (exc: SecurityException) {}
|
|
||||||
}
|
}
|
||||||
wipeOnInactivitySwitch.setOnCheckedChangeListener { _, isChecked ->
|
wipeOnInactivitySwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||||
setWipeOnInactivityComponentsState(prefs.isServiceEnabled && isChecked)
|
setWipeOnInactivityState(prefs.isEnabled && isChecked)
|
||||||
prefs.isWipeOnInactivity = isChecked
|
prefs.isWipeOnInactivity = isChecked
|
||||||
}
|
}
|
||||||
wipeOnInactivitySwitch.setOnLongClickListener {
|
wipeOnInactivitySwitch.setOnLongClickListener {
|
||||||
|
@ -123,31 +130,21 @@ open class MainActivity : AppCompatActivity() {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
toggle.setOnCheckedChangeListener { _, isChecked ->
|
toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
when (isChecked) {
|
if (isChecked) requestAdmin() else setOff()
|
||||||
true -> if (!admin.isActive()) requestAdmin() else setOn()
|
|
||||||
false -> setOff()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
toggle.setOnLongClickListener {
|
|
||||||
if (!toggle.isChecked) return@setOnLongClickListener false
|
|
||||||
showPanicDialog()
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showPanicDialog() {
|
private fun scheduleClipboardClear() {
|
||||||
MaterialAlertDialogBuilder(this)
|
clipboardClearTask?.cancel()
|
||||||
.setTitle(R.string.dialog_confirm_panic_title)
|
clipboardClearTask = Timer()
|
||||||
.setMessage(R.string.dialog_confirm_panic_message)
|
clipboardClearTask?.schedule(timerTask {
|
||||||
.setPositiveButton(R.string.yes) { _, _ ->
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
try {
|
clipboardManager?.clearPrimaryClip()
|
||||||
admin.lockNow()
|
} else {
|
||||||
if (prefs.isWipeData) admin.wipeData()
|
clipboardManager?.setPrimaryClip(ClipData.newPlainText("", ""))
|
||||||
} catch (exc: SecurityException) {}
|
|
||||||
}
|
}
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
}, CLIPBOARD_CLEAR_DELAY)
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showTriggersSettings() {
|
private fun showTriggersSettings() {
|
||||||
|
@ -172,25 +169,25 @@ open class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
prefs.triggers = triggers
|
prefs.triggers = triggers
|
||||||
setTriggersState(prefs.isServiceEnabled)
|
setTriggersState(prefs.isEnabled)
|
||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showWipeOnInactivitySettings() {
|
private fun showWipeOnInactivitySettings() {
|
||||||
val items = resources.getStringArray(R.array.wipe_on_inactivity_days)
|
val items = resources.getStringArray(R.array.wipe_on_inactivity_days)
|
||||||
var days = prefs.wipeOnInactivityDays
|
var days = prefs.wipeOnInactivityCount / 24 / 60
|
||||||
var checked = items.indexOf(days.toString())
|
var checked = items.indexOf(days.toString())
|
||||||
if (checked == -1) checked = items
|
if (checked == -1) checked = items
|
||||||
.indexOf(Preferences.DEFAULT_WIPE_ON_INACTIVITY_DAYS.toString())
|
.indexOf((Preferences.DEFAULT_WIPE_ON_INACTIVITY_COUNT / 24 / 60).toString())
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(R.string.wipe_on_inactivity_days)
|
.setTitle(R.string.wipe_on_inactivity_days)
|
||||||
.setSingleChoiceItems(items, checked) { _, which ->
|
.setSingleChoiceItems(items, checked) { _, which ->
|
||||||
days = items[which].toInt()
|
days = items[which].toInt()
|
||||||
}
|
}
|
||||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
prefs.wipeOnInactivityDays = days
|
prefs.wipeOnInactivityCount = days * 24 * 60
|
||||||
if (prefs.isServiceEnabled && prefs.isWipeOnInactivity) {
|
if (prefs.isEnabled && prefs.isWipeOnInactivity) {
|
||||||
if (job.schedule() == JobScheduler.RESULT_FAILURE)
|
if (job.schedule() == JobScheduler.RESULT_FAILURE)
|
||||||
showWipeJobScheduleFailedPopup()
|
showWipeJobScheduleFailedPopup()
|
||||||
}
|
}
|
||||||
|
@ -199,18 +196,14 @@ open class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateCodeColorState() {
|
private fun updateCodeColorState() {
|
||||||
binding.code.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
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setOn() {
|
private fun setOn() {
|
||||||
if (!setWipeOnInactivityComponentsState(prefs.isWipeOnInactivity)) {
|
prefs.isEnabled = true
|
||||||
binding.toggle.isChecked = false
|
setWipeOnInactivityState(prefs.isWipeOnInactivity)
|
||||||
showWipeJobScheduleFailedPopup()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
prefs.isServiceEnabled = true
|
|
||||||
setTriggersState(true)
|
setTriggersState(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,13 +213,13 @@ open class MainActivity : AppCompatActivity() {
|
||||||
setPanicKitState(triggers.and(Trigger.PANIC_KIT.value) != 0)
|
setPanicKitState(triggers.and(Trigger.PANIC_KIT.value) != 0)
|
||||||
setTileState(triggers.and(Trigger.TILE.value) != 0)
|
setTileState(triggers.and(Trigger.TILE.value) != 0)
|
||||||
shortcut.setState(triggers.and(Trigger.SHORTCUT.value) != 0)
|
shortcut.setState(triggers.and(Trigger.SHORTCUT.value) != 0)
|
||||||
setCodeReceiverState(triggers.and(Trigger.BROADCAST.value) != 0)
|
setTriggerReceiverState(triggers.and(Trigger.BROADCAST.value) != 0)
|
||||||
setNotificationListenerState(triggers.and(Trigger.NOTIFICATION.value) != 0)
|
setNotificationListenerState(triggers.and(Trigger.NOTIFICATION.value) != 0)
|
||||||
} else {
|
} else {
|
||||||
setPanicKitState(false)
|
setPanicKitState(false)
|
||||||
setTileState(false)
|
setTileState(false)
|
||||||
shortcut.setState(false)
|
shortcut.setState(false)
|
||||||
setCodeReceiverState(false)
|
setTriggerReceiverState(false)
|
||||||
setNotificationListenerState(false)
|
setNotificationListenerState(false)
|
||||||
}
|
}
|
||||||
updateCodeColorState()
|
updateCodeColorState()
|
||||||
|
@ -241,16 +234,18 @@ open class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setOff() {
|
private fun setOff() {
|
||||||
prefs.isServiceEnabled = false
|
prefs.isEnabled = false
|
||||||
setWipeOnInactivityComponentsState(false)
|
setWipeOnInactivityState(false)
|
||||||
setTriggersState(false)
|
setTriggersState(false)
|
||||||
|
try {
|
||||||
admin.remove()
|
admin.remove()
|
||||||
|
} catch (exc: SecurityException) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun requestAdmin() = registerForDeviceAdmin.launch(admin.makeRequestIntent())
|
private fun requestAdmin() = registerForDeviceAdmin.launch(admin.makeRequestIntent())
|
||||||
private fun makeCode() = UUID.randomUUID().toString()
|
private fun makeAuthenticationCode() = UUID.randomUUID().toString()
|
||||||
private fun setCodeReceiverState(value: Boolean) =
|
private fun setTriggerReceiverState(value: Boolean) =
|
||||||
setComponentState(CodeReceiver::class.java, value)
|
setComponentState(TriggerReceiver::class.java, value)
|
||||||
private fun setRestartReceiverState(value: Boolean) =
|
private fun setRestartReceiverState(value: Boolean) =
|
||||||
setComponentState(RestartReceiver::class.java, value)
|
setComponentState(RestartReceiver::class.java, value)
|
||||||
private fun setTileState(value: Boolean) {
|
private fun setTileState(value: Boolean) {
|
||||||
|
@ -265,6 +260,11 @@ open class MainActivity : AppCompatActivity() {
|
||||||
setComponentState(PanicResponderActivity::class.java, value)
|
setComponentState(PanicResponderActivity::class.java, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setWipeOnInactivityState(value: Boolean) {
|
||||||
|
job.setState(value)
|
||||||
|
setForegroundState(value)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setComponentState(cls: Class<*>, value: Boolean) {
|
private fun setComponentState(cls: Class<*>, value: Boolean) {
|
||||||
packageManager.setComponentEnabledSetting(
|
packageManager.setComponentEnabledSetting(
|
||||||
ComponentName(this, cls),
|
ComponentName(this, cls),
|
||||||
|
@ -281,12 +281,8 @@ open class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setWipeOnInactivityComponentsState(value: Boolean): Boolean {
|
private fun setForegroundState(value: Boolean) {
|
||||||
val result = job.setState(value)
|
|
||||||
if (result) {
|
|
||||||
setForegroundServiceState(value)
|
setForegroundServiceState(value)
|
||||||
setRestartReceiverState(value)
|
setRestartReceiverState(value)
|
||||||
}
|
}
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,11 +22,11 @@ class NotificationListenerService : NotificationListenerService() {
|
||||||
override fun onNotificationPosted(sbn: StatusBarNotification?) {
|
override fun onNotificationPosted(sbn: StatusBarNotification?) {
|
||||||
super.onNotificationPosted(sbn)
|
super.onNotificationPosted(sbn)
|
||||||
if (sbn == null ||
|
if (sbn == null ||
|
||||||
!prefs.isServiceEnabled ||
|
!prefs.isEnabled ||
|
||||||
prefs.triggers.and(Trigger.NOTIFICATION.value) == 0) return
|
prefs.triggers.and(Trigger.NOTIFICATION.value) == 0) return
|
||||||
val code = prefs.code
|
val code = prefs.authenticationCode
|
||||||
if (code == "" ||
|
assert(code.isNotEmpty())
|
||||||
sbn.notification.extras[Notification.EXTRA_TEXT]?.toString() != code) return
|
if (sbn.notification.extras[Notification.EXTRA_TEXT]?.toString() != code) return
|
||||||
cancelAllNotifications()
|
cancelAllNotifications()
|
||||||
try {
|
try {
|
||||||
admin.lockNow()
|
admin.lockNow()
|
||||||
|
|
|
@ -13,7 +13,7 @@ class PanicResponderActivity : AppCompatActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
if (!Panic.isTriggerIntent(intent) ||
|
if (!Panic.isTriggerIntent(intent) ||
|
||||||
!prefs.isServiceEnabled ||
|
!prefs.isEnabled ||
|
||||||
prefs.triggers.and(Trigger.PANIC_KIT.value) == 0)
|
prefs.triggers.and(Trigger.PANIC_KIT.value) == 0)
|
||||||
{
|
{
|
||||||
finishAndRemoveTask()
|
finishAndRemoveTask()
|
||||||
|
|
|
@ -7,26 +7,18 @@ import androidx.security.crypto.MasterKeys
|
||||||
|
|
||||||
class Preferences(ctx: Context) {
|
class Preferences(ctx: Context) {
|
||||||
companion object {
|
companion object {
|
||||||
const val DEFAULT_WIPE_ON_INACTIVITY_DAYS = 7
|
const val DEFAULT_WIPE_ON_INACTIVITY_COUNT = 7 * 24 * 60
|
||||||
|
|
||||||
private const val SERVICE_ENABLED = "service_enabled"
|
private const val ENABLED = "enabled"
|
||||||
private const val CODE = "code"
|
private const val AUTHENTICATION_CODE = "authentication_code"
|
||||||
private const val WIPE_DATA = "wipe_data"
|
private const val WIPE_DATA = "wipe_data"
|
||||||
private const val WIPE_ESIM = "wipe_esim"
|
private const val WIPE_EMBEDDED_SIM = "wipe_embedded_sim"
|
||||||
private const val MAX_FAILED_PASSWORD_ATTEMPTS = "max_failed_password_attempts"
|
|
||||||
private const val WIPE_ON_INACTIVITY = "wipe_on_inactivity"
|
private const val WIPE_ON_INACTIVITY = "wipe_on_inactivity"
|
||||||
|
|
||||||
private const val TRIGGERS = "triggers"
|
private const val TRIGGERS = "triggers"
|
||||||
private const val WIPE_ON_INACTIVITY_DAYS = "wipe_on_inactivity_days"
|
private const val WIPE_ON_INACTIVITY_COUNT = "wipe_on_inactivity_count"
|
||||||
|
|
||||||
private const val FILE_NAME = "sec_shared_prefs"
|
private const val FILE_NAME = "sec_shared_prefs"
|
||||||
|
|
||||||
// migration
|
|
||||||
private const val DO_WIPE = "do_wipe"
|
|
||||||
private const val CODE_ENABLED = "code_enabled"
|
|
||||||
private const val WIPE_ON_INACTIVE = "wipe_on_inactive"
|
|
||||||
private const val WIPE_ON_INACTIVE_DAYS = "wipe_on_inactive_days"
|
|
||||||
private const val LAUNCHERS = "launchers"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val mk = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
|
private val mk = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
|
||||||
|
@ -38,49 +30,33 @@ class Preferences(ctx: Context) {
|
||||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
|
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
|
||||||
)
|
)
|
||||||
|
|
||||||
var isServiceEnabled: Boolean
|
var isEnabled: Boolean
|
||||||
get() = prefs.getBoolean(SERVICE_ENABLED, false)
|
get() = prefs.getBoolean(ENABLED, false)
|
||||||
set(value) = prefs.edit { putBoolean(SERVICE_ENABLED, value) }
|
set(value) = prefs.edit { putBoolean(ENABLED, value) }
|
||||||
|
|
||||||
var triggers: Int
|
var triggers: Int
|
||||||
get() = prefs.getInt(
|
get() = prefs.getInt(TRIGGERS, 0)
|
||||||
TRIGGERS,
|
|
||||||
prefs.getInt(
|
|
||||||
LAUNCHERS,
|
|
||||||
if (prefs.getBoolean(CODE_ENABLED, false)) Trigger.BROADCAST.value else 0
|
|
||||||
),
|
|
||||||
)
|
|
||||||
set(value) = prefs.edit { putInt(TRIGGERS, value) }
|
set(value) = prefs.edit { putInt(TRIGGERS, value) }
|
||||||
|
|
||||||
var code: String
|
var authenticationCode: String
|
||||||
get() = prefs.getString(CODE, "") ?: ""
|
get() = prefs.getString(AUTHENTICATION_CODE, "") ?: ""
|
||||||
set(value) = prefs.edit { putString(CODE, value) }
|
set(value) = prefs.edit { putString(AUTHENTICATION_CODE, value) }
|
||||||
|
|
||||||
var isWipeData: Boolean
|
var isWipeData: Boolean
|
||||||
get() = prefs.getBoolean(WIPE_DATA, prefs.getBoolean(DO_WIPE, false))
|
get() = prefs.getBoolean(WIPE_DATA, false)
|
||||||
set(value) = prefs.edit { putBoolean(WIPE_DATA, value) }
|
set(value) = prefs.edit { putBoolean(WIPE_DATA, value) }
|
||||||
|
|
||||||
var isWipeESIM: Boolean
|
var isWipeEmbeddedSim: Boolean
|
||||||
get() = prefs.getBoolean(WIPE_ESIM, false)
|
get() = prefs.getBoolean(WIPE_EMBEDDED_SIM, false)
|
||||||
set(value) = prefs.edit { putBoolean(WIPE_ESIM, value) }
|
set(value) = prefs.edit { putBoolean(WIPE_EMBEDDED_SIM, value) }
|
||||||
|
|
||||||
var maxFailedPasswordAttempts: Int
|
|
||||||
get() = prefs.getInt(MAX_FAILED_PASSWORD_ATTEMPTS, 0)
|
|
||||||
set(value) = prefs.edit { putInt(MAX_FAILED_PASSWORD_ATTEMPTS, value) }
|
|
||||||
|
|
||||||
var isWipeOnInactivity: Boolean
|
var isWipeOnInactivity: Boolean
|
||||||
get() = prefs.getBoolean(
|
get() = prefs.getBoolean(WIPE_ON_INACTIVITY, false)
|
||||||
WIPE_ON_INACTIVITY,
|
|
||||||
prefs.getBoolean(WIPE_ON_INACTIVE, false),
|
|
||||||
)
|
|
||||||
set(value) = prefs.edit { putBoolean(WIPE_ON_INACTIVITY, value) }
|
set(value) = prefs.edit { putBoolean(WIPE_ON_INACTIVITY, value) }
|
||||||
|
|
||||||
var wipeOnInactivityDays: Int
|
var wipeOnInactivityCount: Int
|
||||||
get() = prefs.getInt(
|
get() = prefs.getInt(WIPE_ON_INACTIVITY_COUNT, DEFAULT_WIPE_ON_INACTIVITY_COUNT)
|
||||||
WIPE_ON_INACTIVITY_DAYS,
|
set(value) = prefs.edit { putInt(WIPE_ON_INACTIVITY_COUNT, value) }
|
||||||
prefs.getInt(WIPE_ON_INACTIVE_DAYS, DEFAULT_WIPE_ON_INACTIVITY_DAYS),
|
|
||||||
)
|
|
||||||
set(value) = prefs.edit { putInt(WIPE_ON_INACTIVITY_DAYS, value) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Trigger(val value: Int) {
|
enum class Trigger(val value: Int) {
|
||||||
|
|
|
@ -7,11 +7,10 @@ import androidx.core.content.ContextCompat
|
||||||
|
|
||||||
class RestartReceiver : BroadcastReceiver() {
|
class RestartReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
if (context == null
|
if (intent?.action != Intent.ACTION_BOOT_COMPLETED &&
|
||||||
|| (intent?.action != Intent.ACTION_BOOT_COMPLETED
|
intent?.action != Intent.ACTION_MY_PACKAGE_REPLACED) return
|
||||||
&& intent?.action != Intent.ACTION_MY_PACKAGE_REPLACED)) return
|
val prefs = Preferences(context ?: return)
|
||||||
val prefs = Preferences(context)
|
if (!prefs.isEnabled || !prefs.isWipeOnInactivity) return
|
||||||
if (!prefs.isServiceEnabled || !prefs.isWipeOnInactivity) return
|
|
||||||
ContextCompat.startForegroundService(
|
ContextCompat.startForegroundService(
|
||||||
context.applicationContext,
|
context.applicationContext,
|
||||||
Intent(context.applicationContext, ForegroundService::class.java),
|
Intent(context.applicationContext, ForegroundService::class.java),
|
||||||
|
|
|
@ -10,7 +10,7 @@ class ShortcutActivity : AppCompatActivity() {
|
||||||
finishAndRemoveTask()
|
finishAndRemoveTask()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
CodeReceiver.panic(this, intent)
|
TriggerReceiver.panic(this, intent)
|
||||||
finishAndRemoveTask()
|
finishAndRemoveTask()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@ class ShortcutManager(private val ctx: Context) {
|
||||||
.setShortLabel(ctx.getString(R.string.shortcut_label))
|
.setShortLabel(ctx.getString(R.string.shortcut_label))
|
||||||
.setIcon(IconCompat.createWithResource(ctx, android.R.drawable.ic_delete))
|
.setIcon(IconCompat.createWithResource(ctx, android.R.drawable.ic_delete))
|
||||||
.setIntent(
|
.setIntent(
|
||||||
Intent(CodeReceiver.ACTION)
|
Intent(TriggerReceiver.ACTION)
|
||||||
.setClass(ctx, ShortcutActivity::class.java)
|
.setClass(ctx, ShortcutActivity::class.java)
|
||||||
.putExtra(CodeReceiver.KEY, prefs.code)
|
.putExtra(TriggerReceiver.KEY, prefs.authenticationCode)
|
||||||
)
|
)
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -32,14 +32,14 @@ class TileService : TileService() {
|
||||||
override fun onStartListening() {
|
override fun onStartListening() {
|
||||||
super.onStartListening()
|
super.onStartListening()
|
||||||
update(
|
update(
|
||||||
if (prefs.isServiceEnabled && admin.isActive()) Tile.STATE_INACTIVE
|
if (prefs.isEnabled && admin.isActive()) Tile.STATE_INACTIVE
|
||||||
else Tile.STATE_UNAVAILABLE
|
else Tile.STATE_UNAVAILABLE
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClick() {
|
override fun onClick() {
|
||||||
super.onClick()
|
super.onClick()
|
||||||
if (!prefs.isServiceEnabled || prefs.triggers.and(Trigger.TILE.value) == 0) return
|
if (!prefs.isEnabled || prefs.triggers.and(Trigger.TILE.value) == 0) return
|
||||||
if (!prefs.isWipeData) {
|
if (!prefs.isWipeData) {
|
||||||
try {
|
try {
|
||||||
admin.lockNow()
|
admin.lockNow()
|
||||||
|
|
|
@ -4,7 +4,7 @@ import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
|
||||||
class CodeReceiver : BroadcastReceiver() {
|
class TriggerReceiver : BroadcastReceiver() {
|
||||||
companion object {
|
companion object {
|
||||||
const val KEY = "code"
|
const val KEY = "code"
|
||||||
const val ACTION = "me.lucky.wasted.action.TRIGGER"
|
const val ACTION = "me.lucky.wasted.action.TRIGGER"
|
||||||
|
@ -12,9 +12,10 @@ class CodeReceiver : BroadcastReceiver() {
|
||||||
fun panic(context: Context, intent: Intent?) {
|
fun panic(context: Context, intent: Intent?) {
|
||||||
if (intent?.action != ACTION) return
|
if (intent?.action != ACTION) return
|
||||||
val prefs = Preferences(context)
|
val prefs = Preferences(context)
|
||||||
if (!prefs.isServiceEnabled) return
|
if (!prefs.isEnabled) return
|
||||||
val code = prefs.code
|
val code = prefs.authenticationCode
|
||||||
if (code == "" || intent.getStringExtra(KEY) != code) return
|
assert(code.isNotEmpty())
|
||||||
|
if (intent.getStringExtra(KEY) != code) return
|
||||||
val admin = DeviceAdminManager(context)
|
val admin = DeviceAdminManager(context)
|
||||||
try {
|
try {
|
||||||
admin.lockNow()
|
admin.lockNow()
|
||||||
|
@ -24,8 +25,7 @@ class CodeReceiver : BroadcastReceiver() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
if (context == null ||
|
if (Preferences(context ?: return).triggers.and(Trigger.BROADCAST.value) == 0) return
|
||||||
Preferences(context).triggers.and(Trigger.BROADCAST.value) == 0) return
|
|
||||||
panic(context, intent)
|
panic(context, intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,7 +16,7 @@ class WipeJobManager(private val ctx: Context) {
|
||||||
fun schedule(): Int {
|
fun schedule(): Int {
|
||||||
return scheduler?.schedule(
|
return scheduler?.schedule(
|
||||||
JobInfo.Builder(JOB_ID, ComponentName(ctx, WipeJobService::class.java))
|
JobInfo.Builder(JOB_ID, ComponentName(ctx, WipeJobService::class.java))
|
||||||
.setMinimumLatency(TimeUnit.DAYS.toMillis(prefs.wipeOnInactivityDays.toLong()))
|
.setMinimumLatency(TimeUnit.MINUTES.toMillis(prefs.wipeOnInactivityCount.toLong()))
|
||||||
.setBackoffCriteria(0, JobInfo.BACKOFF_POLICY_LINEAR)
|
.setBackoffCriteria(0, JobInfo.BACKOFF_POLICY_LINEAR)
|
||||||
.setPersisted(true)
|
.setPersisted(true)
|
||||||
.build()
|
.build()
|
||||||
|
|
|
@ -6,7 +6,7 @@ import android.app.job.JobService
|
||||||
class WipeJobService : JobService() {
|
class WipeJobService : JobService() {
|
||||||
override fun onStartJob(params: JobParameters?): Boolean {
|
override fun onStartJob(params: JobParameters?): Boolean {
|
||||||
val prefs = Preferences(this)
|
val prefs = Preferences(this)
|
||||||
if (!prefs.isServiceEnabled || !prefs.isWipeOnInactivity) return false
|
if (!prefs.isEnabled || !prefs.isWipeOnInactivity) return false
|
||||||
try {
|
try {
|
||||||
DeviceAdminManager(this).wipeData()
|
DeviceAdminManager(this).wipeData()
|
||||||
} catch (exc: SecurityException) {}
|
} catch (exc: SecurityException) {}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/code"
|
android:id="@+id/authenticationCode"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@color/code_off"
|
android:background="@color/code_off"
|
||||||
|
@ -57,13 +57,13 @@
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
android:id="@+id/wipeESIMSpace"
|
android:id="@+id/wipeSpace"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginVertical="2dp" />
|
android:layout_marginVertical="2dp" />
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/wipeESIM"
|
android:id="@+id/wipeEmbeddedSim"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
|
@ -78,27 +78,6 @@
|
||||||
android:layout_marginVertical="8dp"
|
android:layout_marginVertical="8dp"
|
||||||
android:background="?android:attr/listDivider" />
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
<com.google.android.material.slider.Slider
|
|
||||||
android:id="@+id/maxFailedPasswordAttempts"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:contentDescription="@string/max_failed_password_attempts_content_description"
|
|
||||||
android:valueFrom="0"
|
|
||||||
android:valueTo="10"
|
|
||||||
android:stepSize="1.0" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/maxFailedPasswordAttemptsDescription"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/max_failed_password_attempts_description" />
|
|
||||||
|
|
||||||
<Space
|
|
||||||
android:id="@+id/wipeOnInactivitySpace"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginVertical="8dp" />
|
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:id="@+id/wipeOnInactivitySwitch"
|
android:id="@+id/wipeOnInactivitySwitch"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Wasted</string>
|
||||||
|
<string name="description">Aktiviere Wasted, um dein Gerät im Notfall zu sperren. Du kannst hierfür PanicKit, Tile und Shortcut verwenden, oder eine Nachricht mit diesem Authentifizierungscode auf dein Gerät senden.</string>
|
||||||
|
<string name="device_admin_label">Wasted</string>
|
||||||
|
<string name="device_admin_description">Wasted erlauben das Gerät zu sperren und optional die Daten in einem Notfall zu löschen</string>
|
||||||
|
<string name="service_unavailable_popup">Geräteadministrator nicht verfügbar</string>
|
||||||
|
<string name="wipe_data_check_box">Daten löschen</string>
|
||||||
|
<string name="wipe_esim_check_box">eSim löschen</string>
|
||||||
|
<string name="panic_app_dialog_title">Bestätige Panik App</string>
|
||||||
|
<string name="panic_app_dialog_message">Bist du sicher, dass du %1$s erlauben willst, destruktive Aktionen auslösen zu lassen\?</string>
|
||||||
|
<string name="panic_app_unknown_app">eine unbekannte App</string>
|
||||||
|
<string name="allow">Zulassen</string>
|
||||||
|
<string name="tile_label">Flugmodus</string>
|
||||||
|
<string name="shortcut_label">Panik</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_days">Tage</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_schedule_failed_popup">Fehler bei der Durchführung des Wipes</string>
|
||||||
|
<string name="foreground_service_description">Receive events which require foreground service</string>
|
||||||
|
<string name="foreground_service_notification_title">Guard</string>
|
||||||
|
<string name="triggers_array_panic_kit">PanicKit</string>
|
||||||
|
<string name="triggers_array_tile">Tile</string>
|
||||||
|
<string name="triggers_array_shortcut">Shortcut</string>
|
||||||
|
<string name="triggers_array_broadcast">Broadcast</string>
|
||||||
|
<string name="triggers_array_notification">Benachrichtigung</string>
|
||||||
|
<string name="notification_listener_service_label">Viper</string>
|
||||||
|
<string name="notification_listener_service_description">Benachrichtigungen nach dem Authentifizierungscode absuchen</string>
|
||||||
|
<string name="triggers">Auslöser</string>
|
||||||
|
<string name="copied_popup">Kopiert</string>
|
||||||
|
</resources>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Wasted</string>
|
||||||
|
<string name="description">Active Wasted para bloquear un dispositivo en caso de emergencia. Puede usar PanicKit, title, acceso directo o enviar un mensaje con este código de autenticación.</string>
|
||||||
|
<string name="device_admin_label">Wasted</string>
|
||||||
|
<string name="device_admin_description">Permita que Wasted bloquee un dispositivo y, opcionalmente, borre sus datos en caso de emergencia</string>
|
||||||
|
<string name="service_unavailable_popup">Administrador de dispositivos no disponible</string>
|
||||||
|
<string name="wipe_data_check_box">Borrar datos</string>
|
||||||
|
<string name="wipe_esim_check_box">Borrar eSIM</string>
|
||||||
|
<string name="panic_app_dialog_title">Confirmar aplicación de pánico</string>
|
||||||
|
<string name="panic_app_dialog_message">¿Está seguro de que desea permitir que %1$s active acciones de pánico destructivas\?</string>
|
||||||
|
<string name="panic_app_unknown_app">una aplicación desconocida</string>
|
||||||
|
<string name="allow">Permitir</string>
|
||||||
|
<string name="tile_label">Modo avión</string>
|
||||||
|
<string name="shortcut_label">Pánico</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_days">Días</string>
|
||||||
|
<string name="notification_channel_default_name">Predeterminado</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="foreground_service_description">Recibir eventos que requieren servicio de primer plano</string>
|
||||||
|
<string name="foreground_service_notification_title">Guardia</string>
|
||||||
|
<string name="triggers_array_panic_kit">PanicKit</string>
|
||||||
|
<string name="triggers_array_tile">Título</string>
|
||||||
|
<string name="triggers_array_shortcut">Acceso directo</string>
|
||||||
|
<string name="triggers_array_broadcast">Transmisión</string>
|
||||||
|
<string name="triggers_array_notification">Notificación</string>
|
||||||
|
<string name="notification_listener_service_label">Viper</string>
|
||||||
|
<string name="notification_listener_service_description">Escanear notificaciones para el código de autenticación</string>
|
||||||
|
<string name="triggers">Activadores</string>
|
||||||
|
<string name="copied_popup">Copiado</string>
|
||||||
|
</resources>
|
|
@ -13,8 +13,6 @@
|
||||||
<string name="allow">Consenti</string>
|
<string name="allow">Consenti</string>
|
||||||
<string name="tile_label">Modalità aereo</string>
|
<string name="tile_label">Modalità aereo</string>
|
||||||
<string name="shortcut_label">Panico</string>
|
<string name="shortcut_label">Panico</string>
|
||||||
<string name="max_failed_password_attempts_description">Numero massimo di tentativi di password falliti.</string>
|
|
||||||
<string name="max_failed_password_attempts_content_description">Numero</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="wipe_on_inactivity_days">Giorni</string>
|
||||||
|
@ -23,9 +21,6 @@
|
||||||
<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>
|
||||||
<string name="foreground_service_description">Ricevi eventi che richiedono il servizio in primo piano</string>
|
<string name="foreground_service_description">Ricevi eventi che richiedono il servizio in primo piano</string>
|
||||||
<string name="foreground_service_notification_title">Guardia</string>
|
<string name="foreground_service_notification_title">Guardia</string>
|
||||||
<string name="dialog_confirm_panic_title">Attivare il panico\?</string>
|
|
||||||
<string name="dialog_confirm_panic_message">Questo bloccherà un dispositivo e, facoltativamente, cancellerà i suoi dati.</string>
|
|
||||||
<string name="yes">Sì</string>
|
|
||||||
<string name="triggers_array_panic_kit">PanicKit</string>
|
<string name="triggers_array_panic_kit">PanicKit</string>
|
||||||
<string name="triggers_array_tile">Toggle</string>
|
<string name="triggers_array_tile">Toggle</string>
|
||||||
<string name="triggers_array_shortcut">Scorciatoia</string>
|
<string name="triggers_array_shortcut">Scorciatoia</string>
|
||||||
|
@ -34,4 +29,5 @@
|
||||||
<string name="notification_listener_service_label">Viper</string>
|
<string name="notification_listener_service_label">Viper</string>
|
||||||
<string name="notification_listener_service_description">Scansiona le notifiche per il codice di autenticazione</string>
|
<string name="notification_listener_service_description">Scansiona le notifiche per il codice di autenticazione</string>
|
||||||
<string name="triggers">Attivatori</string>
|
<string name="triggers">Attivatori</string>
|
||||||
|
<string name="copied_popup">Copiato</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
<string name="allow">Разрешить</string>
|
<string name="allow">Разрешить</string>
|
||||||
<string name="tile_label">Режим полета</string>
|
<string name="tile_label">Режим полета</string>
|
||||||
<string name="shortcut_label">Тревога</string>
|
<string name="shortcut_label">Тревога</string>
|
||||||
<string name="max_failed_password_attempts_description">Максимальное количество неудачных попыток ввода пароля.</string>
|
|
||||||
<string name="max_failed_password_attempts_content_description">Количество</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="wipe_on_inactivity_days">Дней</string>
|
||||||
|
@ -23,9 +21,6 @@
|
||||||
<string name="wipe_job_schedule_failed_popup">Не удалось запланировать сервис стирания данных</string>
|
<string name="wipe_job_schedule_failed_popup">Не удалось запланировать сервис стирания данных</string>
|
||||||
<string name="foreground_service_description">Получать события для которых требуется сервис на переднем плане</string>
|
<string name="foreground_service_description">Получать события для которых требуется сервис на переднем плане</string>
|
||||||
<string name="foreground_service_notification_title">Охрана</string>
|
<string name="foreground_service_notification_title">Охрана</string>
|
||||||
<string name="dialog_confirm_panic_title">Активировать тревогу\?</string>
|
|
||||||
<string name="dialog_confirm_panic_message">Это заблокирует устройство и возможно сотрёт его данные.</string>
|
|
||||||
<string name="yes">Да</string>
|
|
||||||
<string name="triggers_array_panic_kit">Тревожная кнопка</string>
|
<string name="triggers_array_panic_kit">Тревожная кнопка</string>
|
||||||
<string name="triggers_array_tile">Плитка</string>
|
<string name="triggers_array_tile">Плитка</string>
|
||||||
<string name="triggers_array_shortcut">Ярлык</string>
|
<string name="triggers_array_shortcut">Ярлык</string>
|
||||||
|
@ -34,4 +29,5 @@
|
||||||
<string name="notification_listener_service_label">Вайпер</string>
|
<string name="notification_listener_service_label">Вайпер</string>
|
||||||
<string name="notification_listener_service_description">Сканирует уведомления на наличие кода аутентификации</string>
|
<string name="notification_listener_service_description">Сканирует уведомления на наличие кода аутентификации</string>
|
||||||
<string name="triggers">Триггеры</string>
|
<string name="triggers">Триггеры</string>
|
||||||
|
<string name="copied_popup">Скопировано</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Wasted</string>
|
||||||
|
<string name="description">Turn on Wasted to lock a device on emergency. You can use PanicKit, tile, shortcut or send a message with this authentication code.</string>
|
||||||
|
<string name="device_admin_label">Wasted</string>
|
||||||
|
<string name="device_admin_description">Allow Wasted to lock a device and optionally wipe its data on emergency</string>
|
||||||
|
<string name="service_unavailable_popup">Cihaz yöneticisi mevcut değil</string>
|
||||||
|
<string name="wipe_data_check_box">Verileri sil</string>
|
||||||
|
<string name="wipe_esim_check_box">eSIM\'i sil</string>
|
||||||
|
<string name="panic_app_dialog_title">Panik uygulamasını onayla</string>
|
||||||
|
<string name="panic_app_dialog_message">Yıkıcı panik eylemlerini tetiklemek için %1$s\'e izin vermek istediğinizden emin misiniz\?</string>
|
||||||
|
<string name="panic_app_unknown_app">bilinmeyen bir uygulama</string>
|
||||||
|
<string name="allow">İzin ver</string>
|
||||||
|
<string name="tile_label">Uçak modu</string>
|
||||||
|
<string name="shortcut_label">Panik</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_days">Gün</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_schedule_failed_popup">Silme işi zamanlanamadı</string>
|
||||||
|
<string name="foreground_service_description">Ön plan hizmeti gerektiren olayları al</string>
|
||||||
|
<string name="foreground_service_notification_title">Guard</string>
|
||||||
|
<string name="triggers_array_panic_kit">PanicKit</string>
|
||||||
|
<string name="triggers_array_tile">Tile</string>
|
||||||
|
<string name="triggers_array_shortcut">Kısayol</string>
|
||||||
|
<string name="triggers_array_broadcast">Yayın</string>
|
||||||
|
<string name="triggers_array_notification">Bildirim</string>
|
||||||
|
<string name="notification_listener_service_label">Viper</string>
|
||||||
|
<string name="notification_listener_service_description">Kimlik doğrulama kodu için bildirimleri tara</string>
|
||||||
|
<string name="triggers">Tetikleyiciler</string>
|
||||||
|
<string name="copied_popup">Kopyalandı</string>
|
||||||
|
</resources>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Wasted</string>
|
||||||
|
<string name="description">Turn on Wasted to lock a device on emergency. You can use PanicKit, tile, shortcut or send a message with this authentication code.</string>
|
||||||
|
<string name="device_admin_label">Wasted</string>
|
||||||
|
<string name="device_admin_description">Allow Wasted to lock a device and optionally wipe its data on emergency</string>
|
||||||
|
<string name="service_unavailable_popup">Адміністратор пристрою недоступний</string>
|
||||||
|
<string name="wipe_data_check_box">Стерти дані</string>
|
||||||
|
<string name="wipe_esim_check_box">Стерти дані eSIM</string>
|
||||||
|
<string name="panic_app_dialog_title">Confirm panic app</string>
|
||||||
|
<string name="panic_app_dialog_message">Are you sure that you want to allow %1$s to trigger destructive panic actions\?</string>
|
||||||
|
<string name="panic_app_unknown_app">невідомий додаток</string>
|
||||||
|
<string name="allow">Allow</string>
|
||||||
|
<string name="tile_label">Режим польоту</string>
|
||||||
|
<string name="shortcut_label">Тривога</string>
|
||||||
|
<string name="wipe_on_inactivity_switch">Wipe on inactivity</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="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="foreground_service_description">Receive events which require foreground service</string>
|
||||||
|
<string name="foreground_service_notification_title">Захисник</string>
|
||||||
|
<string name="triggers_array_panic_kit">PanicKit</string>
|
||||||
|
<string name="triggers_array_tile">Tile</string>
|
||||||
|
<string name="triggers_array_shortcut">Гарячі клавіші</string>
|
||||||
|
<string name="triggers_array_broadcast">Трансляція</string>
|
||||||
|
<string name="triggers_array_notification">Сповіщення</string>
|
||||||
|
<string name="notification_listener_service_label">Знищувач</string>
|
||||||
|
<string name="notification_listener_service_description">Сканувати сповіщення для коду автентифікації</string>
|
||||||
|
<string name="triggers">Тріггери</string>
|
||||||
|
<string name="copied_popup">Скопійовано</string>
|
||||||
|
</resources>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">自毁</string>
|
||||||
|
<string name="description">开启自毁,在紧急状况下锁定设备。您可以使用触发器、追踪器、快捷方式或者发送验证码信息。</string>
|
||||||
|
<string name="device_admin_label">自毁</string>
|
||||||
|
<string name="device_admin_description">允许自毁锁定设备以及可选择在紧急状况下擦除数据</string>
|
||||||
|
<string name="service_unavailable_popup">设备管理员不可用</string>
|
||||||
|
<string name="wipe_data_check_box">擦除数据</string>
|
||||||
|
<string name="wipe_esim_check_box">擦除eSIM</string>
|
||||||
|
<string name="panic_app_dialog_title">确认需要使用的紧急应用程序</string>
|
||||||
|
<string name="panic_app_dialog_message">你是否确定允许%1$s触发紧急自毁行为?</string>
|
||||||
|
<string name="panic_app_unknown_app">未知应用</string>
|
||||||
|
<string name="allow">允许</string>
|
||||||
|
<string name="tile_label">飞行模式</string>
|
||||||
|
<string name="shortcut_label">紧急</string>
|
||||||
|
<string name="wipe_on_inactivity_switch">在不使用时擦除</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="wipe_job_description">擦除不使用的设备</string>
|
||||||
|
<string name="wipe_job_schedule_failed_popup">无法制定擦除计划</string>
|
||||||
|
<string name="foreground_service_description">接收需要前台服务的事件</string>
|
||||||
|
<string name="foreground_service_notification_title">守卫</string>
|
||||||
|
<string name="triggers_array_panic_kit">恐慌触发器</string>
|
||||||
|
<string name="triggers_array_tile">追踪器</string>
|
||||||
|
<string name="triggers_array_shortcut">快捷方式</string>
|
||||||
|
<string name="triggers_array_broadcast">广播</string>
|
||||||
|
<string name="triggers_array_notification">通知</string>
|
||||||
|
<string name="notification_listener_service_label">哨兵</string>
|
||||||
|
<string name="notification_listener_service_description">扫描通知中的验证码</string>
|
||||||
|
<string name="triggers">触发器</string>
|
||||||
|
<string name="copied_popup">复制成功</string>
|
||||||
|
</resources>
|
|
@ -1,9 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Wasted</string>
|
<string name="app_name">Wasted</string>
|
||||||
<string name="description">Turn on Wasted to lock a device on danger. You can use PanicKit, tile, shortcut or send a message with this authentication code.</string>
|
<string name="description">Turn on Wasted to lock a device on emergency. You can use PanicKit, tile, shortcut or send a message with this authentication code.</string>
|
||||||
<string name="device_admin_label">Wasted</string>
|
<string name="device_admin_label">Wasted</string>
|
||||||
<string name="device_admin_description">Allow Wasted to lock a device and optionally wipe its data on danger</string>
|
<string name="device_admin_description">Allow Wasted to lock a device and optionally wipe its data on emergency</string>
|
||||||
<string name="service_unavailable_popup">Device admin unavailable</string>
|
<string name="service_unavailable_popup">Device admin unavailable</string>
|
||||||
<string name="wipe_data_check_box">Wipe data</string>
|
<string name="wipe_data_check_box">Wipe data</string>
|
||||||
<string name="wipe_esim_check_box">Wipe eSIM</string>
|
<string name="wipe_esim_check_box">Wipe eSIM</string>
|
||||||
|
@ -13,8 +13,6 @@
|
||||||
<string name="allow">Allow</string>
|
<string name="allow">Allow</string>
|
||||||
<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="max_failed_password_attempts_description">Maximum number of failed password attempts.</string>
|
|
||||||
<string name="max_failed_password_attempts_content_description">Count</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 days.</string>
|
||||||
<string name="wipe_on_inactivity_days">Days</string>
|
<string name="wipe_on_inactivity_days">Days</string>
|
||||||
|
@ -22,10 +20,7 @@
|
||||||
<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>
|
||||||
<string name="foreground_service_description">Receive events which require foreground service</string>
|
<string name="foreground_service_description">Receive events which require foreground service</string>
|
||||||
<string name="foreground_service_notification_title">Sentry</string>
|
<string name="foreground_service_notification_title">Guard</string>
|
||||||
<string name="dialog_confirm_panic_title">Activate panic\?</string>
|
|
||||||
<string name="dialog_confirm_panic_message">This will lock a device and optionally wipe its data.</string>
|
|
||||||
<string name="yes">Yes</string>
|
|
||||||
<string name="triggers_array_panic_kit">PanicKit</string>
|
<string name="triggers_array_panic_kit">PanicKit</string>
|
||||||
<string name="triggers_array_tile">Tile</string>
|
<string name="triggers_array_tile">Tile</string>
|
||||||
<string name="triggers_array_shortcut">Shortcut</string>
|
<string name="triggers_array_shortcut">Shortcut</string>
|
||||||
|
@ -34,4 +29,5 @@
|
||||||
<string name="notification_listener_service_label">Viper</string>
|
<string name="notification_listener_service_label">Viper</string>
|
||||||
<string name="notification_listener_service_description">Scan notifications for the authentication code</string>
|
<string name="notification_listener_service_description">Scan notifications for the authentication code</string>
|
||||||
<string name="triggers">Triggers</string>
|
<string name="triggers">Triggers</string>
|
||||||
|
<string name="copied_popup">Copied</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<device-admin>
|
<device-admin>
|
||||||
<support-transfer-ownership />
|
|
||||||
<uses-policies>
|
<uses-policies>
|
||||||
<force-lock />
|
<force-lock />
|
||||||
<watch-login />
|
|
||||||
<wipe-data />
|
<wipe-data />
|
||||||
</uses-policies>
|
</uses-policies>
|
||||||
</device-admin>
|
</device-admin>
|
|
@ -5,8 +5,8 @@ buildscript {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.1.1'
|
classpath 'com.android.tools.build:gradle:7.2.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.0"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
remove all preferences migrations, you have to reconfigure Wasted !!
|
||||||
|
.CodeReceiver renamed to .TriggerReceiver !!
|
||||||
|
remove max failed password attempts, migrate to Sentry
|
||||||
|
add copy authentication code with a long click
|
||||||
|
add Chinese Simplified, German, Spanish, Turkish, Ukrainian translations
|
||||||
|
update Italian translation
|
||||||
|
under the hood improvements
|
||||||
|
|
||||||
|
Thanks to:
|
||||||
|
Alex Ortiz
|
||||||
|
Alexander Sergevich
|
||||||
|
Noah Fisker
|
||||||
|
SuperM
|
||||||
|
TolDYuThad
|
||||||
|
Wong Anny
|
||||||
|
Giovanni Donisi (@gdonisi + @giovannidonisi)
|
|
@ -1,11 +1,11 @@
|
||||||
Lock a device and wipe its data on danger.
|
Lock a device and wipe its data on emergency.
|
||||||
|
|
||||||
You can use PanicKit, tile, shortcut or send a message with authentication code. On trigger, using
|
You can use PanicKit, tile, shortcut or send a message with authentication code. On trigger, using
|
||||||
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:
|
||||||
* limit the maximum number of failed password attempts
|
|
||||||
* wipe a device when it was not unlocked for N days
|
* wipe a device when it was not unlocked for N days
|
||||||
|
* 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
|
||||||
wipe this profile data with one click without wiping the whole device.
|
wipe this profile data with one click without wiping the whole device.
|
||||||
|
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 100 KiB |
Before Width: | Height: | Size: 114 KiB |
|
@ -1 +1 @@
|
||||||
Lock a device and wipe its data on danger
|
Lock a device and wipe its data on emergency
|
||||||
|
|
|
@ -5,7 +5,6 @@ un codice di autenticazione. All'attivazione, utilizzando l'API di amministrazio
|
||||||
del dispositivo, blocca un dispositivo e facoltativamente esegue la cancellazione.
|
del dispositivo, blocca un dispositivo e facoltativamente esegue la cancellazione.
|
||||||
|
|
||||||
Puoi anche:
|
Puoi anche:
|
||||||
* limitare il numero massimo di tentativi di password falliti
|
|
||||||
* cancellare i dati quando un dispositivo non è stato sbloccato per N giorni
|
* cancellare i dati quando un dispositivo non è stato sbloccato per N giorni
|
||||||
|
|
||||||
L'app funziona anche nel Profilo di Lavoro. Usa Shelter per installarci dentro le app pericolose e Wasted.
|
L'app funziona anche nel Profilo di Lavoro. Usa Shelter per installarci dentro le app pericolose e Wasted.
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
заблокирует устройство и при необходимости запустит очистку данных.
|
заблокирует устройство и при необходимости запустит очистку данных.
|
||||||
|
|
||||||
Также вы можете:
|
Также вы можете:
|
||||||
* ограничить максимальное количество неудачных попыток ввода пароля
|
|
||||||
* стереть данные, если устройство не было разблокировано в течение определённого количества дней
|
* стереть данные, если устройство не было разблокировано в течение определённого количества дней
|
||||||
|
* стереть данные, используя пароль под принуждением (приложение: https://github.com/x13a/Duress)
|
||||||
|
|
||||||
Приложение работает и в рабочем профиле. Используйте Shelter для установки рискованных приложений и
|
Приложение работает и в рабочем профиле. Используйте Shelter для установки рискованных приложений и
|
||||||
Wasted в него. Тогда вы можете стереть данные этого профиля одним кликом, без удаления данных всего
|
Wasted в него. Тогда вы можете стереть данные этого профиля одним кликом, без удаления данных всего
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
#Fri Jun 24 03:06:49 MSK 2022
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionSha256Sum=f581709a9c35e9cb92e16f585d2c4bc99b2b1a5f85d2badbd3dc6bff59e1e6dd
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|