diff --git a/README.md b/README.md index 9305f01..2f20738 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ message with a secret code. On trigger, using locks a device and optionally runs wipe. Also you can: -* fire when a device was not unlocked for N time +* fire when a device was not unlocked for X time * fire when a USB data connection is made while a device is locked * fire when a duress password is entered (companion app: [Duress](https://github.com/x13a/Duress)) @@ -32,6 +32,12 @@ the whole device. Only encrypted device may guarantee that the data will not be recoverable. +## Broadcast + +* action: `me.lucky.wasted.action.TRIGGER` +* receiver: `me.lucky.wasted/.TriggerReceiver` +* also you have to send a secret code from Wasted with the key: `code` + ## Permissions * DEVICE_ADMIN - lock and optionally wipe a device diff --git a/app/build.gradle b/app/build.gradle index 55b9272..77d542c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "me.lucky.wasted" minSdk 23 targetSdk 32 - versionCode 30 - versionName "1.5.1" + versionCode 31 + versionName "1.5.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -42,11 +42,13 @@ dependencies { implementation 'androidx.core:core-ktx:1.8.0' implementation 'androidx.appcompat:appcompat:1.4.2' implementation 'com.google.android.material:material:1.6.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' implementation 'androidx.security:security-crypto:1.0.0' implementation 'androidx.preference:preference-ktx:1.2.0' + implementation 'androidx.drawerlayout:drawerlayout:1.1.1' implementation 'info.guardianproject.panic:panic:1.0' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 00bcc17..1531773 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" package="me.lucky.wasted"> - + diff --git a/app/src/main/java/me/lucky/wasted/MainActivity.kt b/app/src/main/java/me/lucky/wasted/MainActivity.kt index 8bef16c..d4cfe98 100644 --- a/app/src/main/java/me/lucky/wasted/MainActivity.kt +++ b/app/src/main/java/me/lucky/wasted/MainActivity.kt @@ -62,6 +62,7 @@ open class MainActivity : AppCompatActivity() { private fun getFragment(id: Int) = when (id) { R.id.nav_main -> MainFragment() + R.id.nav_trigger_tile -> TileFragment() R.id.nav_trigger_lock -> LockFragment() R.id.top_settings -> SettingsFragment() else -> MainFragment() diff --git a/app/src/main/java/me/lucky/wasted/Preferences.kt b/app/src/main/java/me/lucky/wasted/Preferences.kt index cf9d7a9..b8284e6 100644 --- a/app/src/main/java/me/lucky/wasted/Preferences.kt +++ b/app/src/main/java/me/lucky/wasted/Preferences.kt @@ -12,6 +12,7 @@ import androidx.security.crypto.MasterKeys class Preferences(ctx: Context, encrypted: Boolean = true) { companion object { private const val DEFAULT_TRIGGER_LOCK_COUNT = 7 * 24 * 60 + private const val DEFAULT_TRIGGER_TILE_DELAY = 2000L private const val ENABLED = "enabled" private const val SECRET = "secret" @@ -20,6 +21,7 @@ class Preferences(ctx: Context, encrypted: Boolean = true) { private const val TRIGGERS = "triggers" private const val TRIGGER_LOCK_COUNT = "trigger_lock_count" + private const val TRIGGER_TILE_DELAY = "trigger_tile_delay" private const val FILE_NAME = "sec_shared_prefs" @@ -79,6 +81,10 @@ class Preferences(ctx: Context, encrypted: Boolean = true) { ) set(value) = prefs.edit { putInt(TRIGGER_LOCK_COUNT, value) } + var triggerTileDelay: Long + get() = prefs.getLong(TRIGGER_TILE_DELAY, DEFAULT_TRIGGER_TILE_DELAY) + set(value) = prefs.edit { putLong(TRIGGER_TILE_DELAY, value) } + fun registerListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) = prefs.registerOnSharedPreferenceChangeListener(listener) @@ -93,6 +99,7 @@ class Preferences(ctx: Context, encrypted: Boolean = true) { when (v) { is Boolean -> putBoolean(k, v) is Int -> putInt(k, v) + is Long -> putLong(k, v) is String -> putString(k, v) } } diff --git a/app/src/main/java/me/lucky/wasted/fragment/LockFragment.kt b/app/src/main/java/me/lucky/wasted/fragment/LockFragment.kt index 7c5ed39..a10c35f 100644 --- a/app/src/main/java/me/lucky/wasted/fragment/LockFragment.kt +++ b/app/src/main/java/me/lucky/wasted/fragment/LockFragment.kt @@ -57,13 +57,14 @@ class LockFragment : Fragment() { ctx = requireContext() prefs = Preferences(ctx) prefsdb = Preferences(ctx, encrypted = false) - val count = prefs.triggerLockCount - val time = when { - count % (24 * 60) == 0 -> "${count / 24 / 60}$MODIFIER_DAYS" - count % 60 == 0 -> "${count / 60}$MODIFIER_HOURS" - else -> "$count$MODIFIER_MINUTES" + binding.apply { + val count = prefs.triggerLockCount + time.editText?.setText(when { + count % (24 * 60) == 0 -> "${count / 24 / 60}$MODIFIER_DAYS" + count % 60 == 0 -> "${count / 60}$MODIFIER_HOURS" + else -> "$count$MODIFIER_MINUTES" + }) } - binding.time.editText?.setText(time) } private fun setup() = binding.apply { diff --git a/app/src/main/java/me/lucky/wasted/fragment/TileFragment.kt b/app/src/main/java/me/lucky/wasted/fragment/TileFragment.kt new file mode 100644 index 0000000..bc1eb76 --- /dev/null +++ b/app/src/main/java/me/lucky/wasted/fragment/TileFragment.kt @@ -0,0 +1,62 @@ +package me.lucky.wasted.fragment + +import android.content.Context +import android.content.SharedPreferences +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment + +import me.lucky.wasted.Preferences +import me.lucky.wasted.databinding.FragmentTileBinding + +class TileFragment : Fragment() { + private lateinit var binding: FragmentTileBinding + private lateinit var ctx: Context + private lateinit var prefs: Preferences + private lateinit var prefsdb: Preferences + + private val prefsListener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> + prefs.copyTo(prefsdb, key) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + binding = FragmentTileBinding.inflate(inflater, container, false) + init() + setup() + return binding.root + } + + override fun onStart() { + super.onStart() + prefs.registerListener(prefsListener) + } + + override fun onStop() { + super.onStop() + prefs.unregisterListener(prefsListener) + } + + private fun init() { + ctx = requireContext() + prefs = Preferences(ctx) + prefsdb = Preferences(ctx, encrypted = false) + binding.apply { + delay.value = prefs.triggerTileDelay.toFloat() / 1000 + } + } + + private fun setup() = binding.apply { + delay.setLabelFormatter { + String.format("%.1f", it) + } + delay.addOnChangeListener { _, value, _ -> + prefs.triggerTileDelay = (value * 1000).toLong() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/lucky/wasted/trigger/tile/TileService.kt b/app/src/main/java/me/lucky/wasted/trigger/tile/TileService.kt index 75bcea5..9ca8080 100644 --- a/app/src/main/java/me/lucky/wasted/trigger/tile/TileService.kt +++ b/app/src/main/java/me/lucky/wasted/trigger/tile/TileService.kt @@ -13,10 +13,6 @@ import me.lucky.wasted.Trigger @RequiresApi(Build.VERSION_CODES.N) class TileService : TileService() { - companion object { - private const val SAFE_DELAY = 2000L - } - private lateinit var prefs: Preferences private lateinit var admin: DeviceAdminManager private var counter = 0 @@ -61,7 +57,7 @@ class TileService : TileService() { admin.lockNow() admin.wipeData() } catch (exc: SecurityException) {} - }, SAFE_DELAY) + }, prefs.triggerTileDelay) } else -> { timer?.cancel() diff --git a/app/src/main/res/layout/fragment_tile.xml b/app/src/main/res/layout/fragment_tile.xml new file mode 100644 index 0000000..a1654b2 --- /dev/null +++ b/app/src/main/res/layout/fragment_tile.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/nav.xml b/app/src/main/res/menu/nav.xml index 7c0aa2f..7b60658 100644 --- a/app/src/main/res/menu/nav.xml +++ b/app/src/main/res/menu/nav.xml @@ -11,6 +11,10 @@ android:id="@+id/nav_group_options" android:checkableBehavior="all"> + + diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 01f81b7..75094b2 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,18 +1,17 @@ Wasted - Cancella i dati + Cancella dati Cancella eSIM Conferma app di panico - Sei sicuro di voler consentire a %1$s di attivare azioni di panico distruttive\? + Sei sicuro di voler consentire a %1$s di attivare azioni di panico distruttive\\? un\'app sconosciuta Consenti Modalità aereo Panico - Cancella i dati quando il dispositivo non viene sbloccato per N tempo. tempo 7d / 48h / 120m - [d]giorni [h]ore [m]minuti + Quanto tempo aspettare. Modificatori: [d]giorni [h]ore [m]minuti Predefinito Guardia PanicKit @@ -20,5 +19,16 @@ Scorciatoia Broadcast Notifica + Blocca + USB Copiato + Principale + Impostazioni + Abilita il panic responder. PanicKit è una raccolta di strumenti per la creazione di \"pulsanti di panico\" che possono attivare una risposta a livello di sistema quando l\'utente si trova in una situazione di ansia o di pericolo. Consente alle app trigger e alle app responder di connettersi tra loro in modo sicuro e semplice. L\'utente si collega all\'app trigger quando si trova in una situazione di panico. Le app di risposta ricevono il segnale di attivazione ed eseguono individualmente le operazioni per le quali sono state configurate. + Abilita il servizio toggle. Si tratta di un pulsante nel pannello delle impostazioni rapide quando scorri il dito dalla parte superiore dello schermo. Questo pulsante simula la modalità aereo. Ha un ritardo di due secondi se lo si tocca accidentalmente. + Abilita la scorciatoia dell\'icona. È un pulsante che viene visualizzato quando si tocca a lungo l\'icona di Wasted. + Abilita il ricevitore broadcast. È utile per comunicare con altre applicazioni Android. Ad esempio, è possibile avviare Wasted da Tasker. + Abilita l\'ascoltatore di notifiche del dispositivo. Esaminerà tutte le notifiche a cui ha accesso alla ricerca del codice segreto. Quando lo trova, si attiva. È necessario concedere a Wasted le autorizzazioni necessarie nelle Impostazioni > Notifiche > Notifiche app e dispositivi. + Abilita i Job Scheduler di blocco. Pianificherà un Job ogni volta che si blocca un dispositivo e lo annullerà ogni volta che si sblocca un dispositivo. Se non si sblocca un dispositivo per un periodo di tempo X, il Job verrà avviato. + Abilita il ricevitore di stato USB. Quando si effettua una connessione dati USB mentre un dispositivo è bloccato, il ricevitore si attiva. Non deve attivarsi sul caricatore, ma solo su dispositivi e accessori. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ce8321b..799cab6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -12,6 +12,7 @@ time 7d / 48h / 120m How much time to wait. Modifiers: [d]ays [h]ours [m]inutes + Safe delay before it will fire. Gives you some time to cancel fire if you will tap a tile accidentally. Default Guard PanicKit @@ -25,7 +26,7 @@ Main Settings Enable panic responder. PanicKit is a collection of tools for creating “panic buttons” that can trigger a system-wide response when the user is in an anxious or dangerous situation. It enables trigger apps and responder apps to safely and easily connect to each other. The user engages with the trigger app when in a panic situation. The responder apps receive that trigger signal, and individually execute the steps that they were configured to do. - Enable tile service. It is a button in quick settings panel when you swipe from the top of the screen. This button will mimic to the airplane mode. It has 2s delay if you will tap it accidentally. + Enable tile service. It is a button in quick settings panel when you swipe from the top of the screen. This button will mimic to the airplane mode. Enable icon shortcut. It is a button you will see when you make a long tap on the Wasted icon. Enable broadcast receiver. It is useful to communicate with another Android apps. For example you can fire Wasted from Tasker using this. Enable device notification listener. It will scan all notifications it has access to for the secret code. When found it will fire. You have to give Wasted necessary permissions in Settings > Notifications > Device and app notifications. diff --git a/fastlane/metadata/android/en-US/changelogs/31.txt b/fastlane/metadata/android/en-US/changelogs/31.txt new file mode 100644 index 0000000..4fd44b1 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/31.txt @@ -0,0 +1,2 @@ +tile trigger safe delay option +update Italian translation, thanks to Giovanni Donisi (@gdonisi + @giovannidonisi) diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt index 6d76710..e79d8de 100644 --- a/fastlane/metadata/android/en-US/full_description.txt +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -4,7 +4,7 @@ You can use PanicKit, tile, shortcut or send a message with a secret code. On tr Device Administration API, it locks a device and optionally runs wipe. Also you can: -* fire when a device was not unlocked for N time +* fire when a device was not unlocked for X time * fire when a USB data connection is made while a device is locked * fire when a duress password is entered (companion app: [Duress](https://github.com/x13a/Duress)) @@ -13,6 +13,11 @@ wipe this profile data with one click without wiping the whole device. Only encrypted device may guarantee that the data will not be recoverable. +Broadcast: +* action: me.lucky.wasted.action.TRIGGER +* receiver: me.lucky.wasted/.TriggerReceiver +* also you have to send a secret code from Wasted with the key: code + Permissions: * DEVICE_ADMIN - lock and optionally wipe a device * FOREGROUND_SERVICE - receive lock and USB state events