Skip to content

Commit

Permalink
add samsung pin support (tab s8)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucky committed Jun 28, 2022
1 parent 326e3c7 commit 38dfa2d
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 25 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ Duress password trigger.
height="30%">

Tiny app to listen for a duress password on the lockscreen.
When found, it can send a broadcast message to the selected receiver or wipe the device.
When found, it can send a broadcast message or wipe the device.

## Wasted

You have to set:

* Action: `me.lucky.wasted.action.TRIGGER`
* Receiver: `me.lucky.wasted/.TriggerReceiver`
* Authentication code: a code from Wasted
* Password length: your actual password len plus at least two!
* action: `me.lucky.wasted.action.TRIGGER`
* receiver: `me.lucky.wasted/.TriggerReceiver`
* authentication code: the code from Wasted
* password length: your actual password len plus at least two!

Do not forget to activate `Broadcast` trigger in Wasted.

Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ android {
applicationId "me.lucky.duress"
minSdk 23
targetSdk 32
versionCode 3
versionName "1.0.2"
versionCode 4
versionName "1.0.3"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
72 changes: 65 additions & 7 deletions app/src/main/java/me/lucky/duress/AccessibilityService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,59 @@ package me.lucky.duress

import android.accessibilityservice.AccessibilityService
import android.app.KeyguardManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.view.accessibility.AccessibilityEvent
import java.lang.ref.WeakReference

class AccessibilityService : AccessibilityService() {
companion object {
private const val MIN_PASSWORD_LEN = 6
private const val KEY = "code"
private const val BUTTON_DELETE_TEXT = "DELETE"
private const val BUTTON_OK_TEXT = "OK"
}

private lateinit var prefs: Preferences
private val admin by lazy { DeviceAdminManager(this) }
private val lockReceiver = LockReceiver(WeakReference(this))
private var keyguardManager: KeyguardManager? = null
private var enteredPwLen = 0

override fun onCreate() {
super.onCreate()
init()
}

override fun onDestroy() {
super.onDestroy()
deinit()
}

private fun init() {
prefs = Preferences(this)
keyguardManager = getSystemService(KeyguardManager::class.java)
registerReceiver(lockReceiver, IntentFilter().apply {
addAction(Intent.ACTION_USER_PRESENT)
addAction(Intent.ACTION_SCREEN_OFF)
})
}

private fun deinit() {
unregisterReceiver(lockReceiver)
}

override fun onAccessibilityEvent(event: AccessibilityEvent?) {
if (event?.isEnabled != true ||
!event.isPassword ||
keyguardManager?.isDeviceLocked != true ||
if (keyguardManager?.isDeviceLocked != true ||
event?.isEnabled != true ||
!prefs.isEnabled) return
val passwordLen = prefs.passwordLen
if (passwordLen < MIN_PASSWORD_LEN ||
event.text.size != 1 ||
event.text[0].length < passwordLen) return
if (!when (prefs.keyguardType) {
KeyguardType.A.value -> checkKeyguardTypeA(event)
KeyguardType.B.value -> checkKeyguardTypeB(event)
else -> return
}) return
if (prefs.mode == Mode.WIPE.value) {
wipeData()
return
Expand All @@ -45,6 +66,33 @@ class AccessibilityService : AccessibilityService() {

override fun onInterrupt() {}

private fun checkKeyguardTypeA(event: AccessibilityEvent): Boolean {
if (event.eventType != AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED ||
!event.isPassword) return false
val passwordLen = prefs.passwordLen
if (passwordLen < MIN_PASSWORD_LEN ||
event.text.size != 1 ||
event.text[0].length < passwordLen) return false
return true
}

private fun checkKeyguardTypeB(event: AccessibilityEvent): Boolean {
if (event.eventType != AccessibilityEvent.TYPE_VIEW_CLICKED &&
event.eventType != AccessibilityEvent.TYPE_VIEW_LONG_CLICKED) return false
val passwordLen = prefs.passwordLen
if (passwordLen < MIN_PASSWORD_LEN || event.text.size != 1) return false
when (event.contentDescription.toString()) {
BUTTON_DELETE_TEXT -> {
if (event.eventType == AccessibilityEvent.TYPE_VIEW_LONG_CLICKED) enteredPwLen = 0
else if (enteredPwLen > 0) enteredPwLen -= 1
}
BUTTON_OK_TEXT -> enteredPwLen = 0
else -> enteredPwLen += 1
}
if (enteredPwLen < passwordLen) return false
return true
}

private fun sendBroadcast(action: String) {
sendBroadcast(Intent(action).apply {
val cls = prefs.receiver.split('/')
Expand All @@ -66,4 +114,14 @@ class AccessibilityService : AccessibilityService() {
private fun wipeData() {
try { admin.wipeData() } catch (exc: SecurityException) {}
}

private class LockReceiver(
private val service: WeakReference<me.lucky.duress.AccessibilityService>,
) : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action != Intent.ACTION_USER_PRESENT &&
intent?.action != Intent.ACTION_SCREEN_OFF) return
service.get()?.enteredPwLen = 0
}
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/me/lucky/duress/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ class MainActivity : AppCompatActivity() {
receiver.editText?.setText(prefs.receiver)
authenticationCode.editText?.setText(prefs.authenticationCode)
passwordLen.editText?.setText(prefs.passwordLen.toString())
keyguardType.check(when (prefs.keyguardType) {
KeyguardType.A.value -> R.id.keyguardTypeA
KeyguardType.B.value -> R.id.keyguardTypeB
else -> R.id.keyguardTypeA
})
toggle.isChecked = prefs.isEnabled
}
selectInterface()
Expand Down Expand Up @@ -81,6 +86,13 @@ class MainActivity : AppCompatActivity() {
prefs.passwordLen = it?.toString()?.toInt() ?: return@doAfterTextChanged
} catch (exc: NumberFormatException) {}
}
keyguardType.setOnCheckedChangeListener { _, checkedId ->
prefs.keyguardType = when (checkedId) {
R.id.keyguardTypeA -> KeyguardType.A.value
R.id.keyguardTypeB -> KeyguardType.B.value
else -> return@setOnCheckedChangeListener
}
}
toggle.setOnCheckedChangeListener { _, isChecked ->
if (isChecked && !hasPermissions()) {
toggle.isChecked = false
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/me/lucky/duress/Preferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class Preferences(ctx: Context) {
private const val RECEIVER = "receiver"
private const val AUTHENTICATION_CODE = "authentication_code"
private const val PASSWORD_LEN = "password_len"
private const val KEYGUARD_TYPE = "keyguard_type"
private const val SHOW_PROMINENT_DISCLOSURE = "show_prominent_disclosure"

private const val FILE_NAME = "sec_shared_prefs"
Expand Down Expand Up @@ -53,6 +54,10 @@ class Preferences(ctx: Context) {
get() = prefs.getInt(PASSWORD_LEN, 0)
set(value) = prefs.edit { putInt(PASSWORD_LEN, value) }

var keyguardType: Int
get() = prefs.getInt(KEYGUARD_TYPE, KeyguardType.A.value)
set(value) = prefs.edit { putInt(KEYGUARD_TYPE, value) }

var isShowProminentDisclosure: Boolean
get() = prefs.getBoolean(SHOW_PROMINENT_DISCLOSURE, true)
set(value) = prefs.edit { putBoolean(SHOW_PROMINENT_DISCLOSURE, value) }
Expand All @@ -62,3 +67,8 @@ enum class Mode(val value: Int) {
BROADCAST(0),
WIPE(1),
}

enum class KeyguardType(val value: Int) {
A(0),
B(1),
}
40 changes: 40 additions & 0 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,46 @@

</com.google.android.material.textfield.TextInputLayout>

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginVertical="10dp"
android:background="?android:attr/listDivider" />

<RadioGroup
android:id="@+id/keyguardType"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:textSize="16sp"
android:layout_marginEnd="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/keyguard_type" />

<RadioButton
android:id="@+id/keyguardTypeA"
android:textSize="16sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/keyguard_type_a" />

<RadioButton
android:id="@+id/keyguardTypeB"
android:textSize="16sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/keyguard_type_b" />

</RadioGroup>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/keyguard_type_description" />

</LinearLayout>
</ScrollView>

Expand Down
14 changes: 9 additions & 5 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@
<string name="app_name">Duress</string>
<string name="service_unavailable_popup">Service unavailable</string>
<string name="prominent_disclosure_title">Prominent Disclosure</string>
<string name="prominent_disclosure_message">The app uses accessibility service to listen for a duress password on the lockscreen. When found, it can send a broadcast message to the selected receiver or wipe the device.</string>
<string name="prominent_disclosure_message">The app uses accessibility service to listen for a duress password on the lockscreen. When found, it can send a broadcast message or wipe the device.</string>
<string name="accept">Accept</string>
<string name="exit">Exit</string>
<string name="action">Action*</string>
<string name="receiver">Receiver</string>
<string name="authentication_code">Authentication code</string>
<string name="password_len">Password length*</string>
<string name="action">action*</string>
<string name="receiver">receiver</string>
<string name="authentication_code">authentication code</string>
<string name="password_len">password length*</string>
<string name="password_len_helper_text">Has to be at least your password length plus two.</string>
<string name="tab_broadcast">BROADCAST</string>
<string name="tab_wipe">WIPE</string>
<string name="keyguard_type">Keyguard:</string>
<string name="keyguard_type_a">A</string>
<string name="keyguard_type_b">B</string>
<string name="keyguard_type_description">Change only if the default value is not working.</string>
</resources>
2 changes: 1 addition & 1 deletion app/src/main/res/xml/accessibility_service_config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/prominent_disclosure_message"
android:packageNames="com.android.systemui"
android:accessibilityEventTypes="typeViewTextChanged"
android:accessibilityEventTypes="typeViewTextChanged|typeViewClicked|typeViewLongClicked"
android:accessibilityFlags="flagRetrieveInteractiveWindows"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="100"
Expand Down
1 change: 1 addition & 0 deletions fastlane/metadata/android/en-US/changelogs/4.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add samsung pin support (tab s8)
10 changes: 5 additions & 5 deletions fastlane/metadata/android/en-US/full_description.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
Tiny app to listen for a duress password on the lockscreen.
When found, it can send a broadcast message to the selected receiver or wipe the device.
When found, it can send a broadcast message or wipe the device.

Wasted:

* Action: "me.lucky.wasted.action.TRIGGER"
* Receiver: "me.lucky.wasted/.TriggerReceiver"
* Authentication code: a code from Wasted
* Password length: your actual password len plus at least two!
* action: "me.lucky.wasted.action.TRIGGER"
* receiver: "me.lucky.wasted/.TriggerReceiver"
* authentication code: the code from Wasted
* password length: your actual password len plus at least two!

Do not forget to activate "Broadcast" trigger in Wasted.

Expand Down
Binary file modified fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 38dfa2d

Please sign in to comment.