mirror of
https://github.com/jrpie/Launcher.git
synced 2025-02-22 22:11:27 +01:00
add accessibility service as second method for locking the screen (cf. #65)
This commit is contained in:
parent
9848785b3e
commit
f61f861950
12 changed files with 206 additions and 27 deletions
|
@ -53,7 +53,7 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<receiver android:name=".actions.LauncherDeviceAdmin"
|
||||
<receiver android:name=".actions.lock.LauncherDeviceAdmin"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:description="@string/device_admin_description"
|
||||
|
@ -66,7 +66,7 @@
|
|||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service android:name=".actions.LauncherAccessibilityService"
|
||||
<service android:name=".actions.lock.LauncherAccessibilityService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
|
||||
android:label="@string/accessibility_service_name">
|
||||
|
|
|
@ -12,9 +12,9 @@ import android.view.KeyEvent
|
|||
import android.widget.Toast
|
||||
import de.jrpie.android.launcher.Application
|
||||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.actions.LauncherAccessibilityService.Companion.ACTION_LOCK_SCREEN
|
||||
import de.jrpie.android.launcher.apps.AppFilter
|
||||
import de.jrpie.android.launcher.apps.AppInfo.Companion.INVALID_USER
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.ui.list.ListActivity
|
||||
import de.jrpie.android.launcher.ui.settings.SettingsActivity
|
||||
|
||||
|
@ -78,7 +78,7 @@ enum class LauncherAction(
|
|||
"launcher:lockScreen",
|
||||
R.string.list_other_lock_screen,
|
||||
R.drawable.baseline_lock_24px,
|
||||
LauncherDeviceAdmin::lockScreen
|
||||
{ c -> LauncherPreferences.actions().lockMethod().lockOrEnable(c) }
|
||||
),
|
||||
TORCH(
|
||||
"launcher:toggleTorch",
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
package de.jrpie.android.launcher.actions
|
||||
package de.jrpie.android.launcher.actions.lock
|
||||
|
||||
import android.accessibilityservice.AccessibilityService
|
||||
import android.accessibilityservice.AccessibilityServiceInfo
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.getSystemService
|
||||
import de.jrpie.android.launcher.BuildConfig
|
||||
import de.jrpie.android.launcher.R
|
||||
|
||||
class LauncherAccessibilityService : AccessibilityService() {
|
||||
override fun onInterrupt() { }
|
||||
override fun onInterrupt() {}
|
||||
|
||||
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
|
||||
// Intentionally left blank, we are not interested in any AccessibilityEvents.
|
||||
|
@ -23,11 +23,15 @@ class LauncherAccessibilityService : AccessibilityService() {
|
|||
companion object {
|
||||
const val ACTION_LOCK_SCREEN = "ACTION_LOCK_SCREEN"
|
||||
|
||||
private fun lockScreen(context: Context){
|
||||
fun lockScreen(context: Context) {
|
||||
try {
|
||||
context.startService(Intent(context, LauncherAccessibilityService::class.java).apply {
|
||||
action = ACTION_LOCK_SCREEN
|
||||
})
|
||||
context.startService(
|
||||
Intent(
|
||||
context,
|
||||
LauncherAccessibilityService::class.java
|
||||
).apply {
|
||||
action = ACTION_LOCK_SCREEN
|
||||
})
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
|
@ -36,19 +40,33 @@ class LauncherAccessibilityService : AccessibilityService() {
|
|||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun isEnabled(context: Context): Boolean {
|
||||
val accessibilityManager =
|
||||
context.getSystemService<AccessibilityManager>() ?: return false
|
||||
val enabledServices =
|
||||
accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK)
|
||||
return enabledServices.any {
|
||||
it.id.startsWith(BuildConfig.APPLICATION_ID)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun isServiceEnabled(): Boolean {
|
||||
val accessibilityManager = getSystemService<AccessibilityManager>() ?: return false
|
||||
val enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK)
|
||||
return enabledServices.any { it.id.contains(packageName) }
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
intent?.action?.let { action ->
|
||||
if (!isServiceEnabled()) {
|
||||
Toast.makeText(this, getString(R.string.toast_accessibility_service_not_enabled), Toast.LENGTH_LONG).show()
|
||||
startActivity(Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
|
||||
if (!isEnabled(this)) {
|
||||
Toast.makeText(
|
||||
this,
|
||||
getString(R.string.toast_accessibility_service_not_enabled),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
startActivity(
|
||||
Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS).addFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
)
|
||||
)
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
|
@ -59,7 +77,7 @@ class LauncherAccessibilityService : AccessibilityService() {
|
|||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
||||
private fun handleLockScreen(){
|
||||
private fun handleLockScreen() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||
Toast.makeText(
|
||||
this,
|
|
@ -1,4 +1,4 @@
|
|||
package de.jrpie.android.launcher.actions
|
||||
package de.jrpie.android.launcher.actions.lock
|
||||
|
||||
import android.app.admin.DeviceAdminReceiver
|
||||
import android.app.admin.DevicePolicyManager
|
||||
|
@ -18,11 +18,17 @@ class LauncherDeviceAdmin : DeviceAdminReceiver() {
|
|||
|
||||
val intent = Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN).apply {
|
||||
putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, getComponentName(context))
|
||||
putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
|
||||
context.getString(R.string.device_admin_explanation))
|
||||
putExtra(
|
||||
DevicePolicyManager.EXTRA_ADD_EXPLANATION,
|
||||
context.getString(R.string.device_admin_explanation)
|
||||
)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun isDeviceAdmin(context: Context): Boolean {
|
||||
val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
||||
return dpm.isAdminActive(getComponentName(context))
|
||||
}
|
||||
|
||||
private fun assertDeviceAdmin(context: Context): Boolean {
|
||||
|
@ -36,17 +42,15 @@ class LauncherDeviceAdmin : DeviceAdminReceiver() {
|
|||
requestDeviceAdmin(context)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun lockScreen(context: Context) {
|
||||
|
||||
assertDeviceAdmin(context) || return
|
||||
|
||||
val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
||||
dpm.lockNow()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package de.jrpie.android.launcher.actions.lock
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.view.LayoutInflater
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
|
||||
|
||||
@Suppress("unused")
|
||||
enum class LockMethod(
|
||||
private val lock: (Context) -> Unit,
|
||||
private val isEnabled: (Context) -> Boolean,
|
||||
private val enable: (Context) -> Unit
|
||||
) {
|
||||
DEVICE_ADMIN(
|
||||
LauncherDeviceAdmin::lockScreen,
|
||||
LauncherDeviceAdmin::isDeviceAdmin,
|
||||
LauncherDeviceAdmin::lockScreen
|
||||
),
|
||||
ACCESSIBILITY_SERVICE(
|
||||
LauncherAccessibilityService::lockScreen,
|
||||
LauncherAccessibilityService::isEnabled,
|
||||
LauncherAccessibilityService::lockScreen
|
||||
),
|
||||
;
|
||||
|
||||
fun lockOrEnable(context: Context) {
|
||||
if (!this.isEnabled(context)) {
|
||||
chooseMethod(context)
|
||||
return
|
||||
}
|
||||
this.lock(context)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun chooseMethod(context: Context) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||
// only device admin is available
|
||||
setMethod(context, DEVICE_ADMIN)
|
||||
return
|
||||
}
|
||||
val builder = AlertDialog.Builder(context, R.style.AlertDialogCustom)
|
||||
builder.setNegativeButton("cancel") { _, _ -> }
|
||||
builder.setCustomTitle(
|
||||
LayoutInflater.from(context).inflate(R.layout.dialog_select_lock_method, null)
|
||||
)
|
||||
|
||||
builder.setItems(
|
||||
arrayOf(
|
||||
context.getString(R.string.screen_lock_method_use_accessibility),
|
||||
context.getString(R.string.screen_lock_method_use_device_admin)
|
||||
)
|
||||
) { _, i ->
|
||||
val method = when (i) {
|
||||
0 -> ACCESSIBILITY_SERVICE
|
||||
1 -> DEVICE_ADMIN
|
||||
else -> return@setItems
|
||||
}
|
||||
setMethod(context, method)
|
||||
}
|
||||
builder.show()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
private fun setMethod(context: Context, m: LockMethod) {
|
||||
LauncherPreferences.actions().lockMethod(m)
|
||||
if (!m.isEnabled(context))
|
||||
m.enable(context)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import java.util.Set;
|
|||
|
||||
import de.jrpie.android.launcher.R;
|
||||
import de.jrpie.android.launcher.apps.AppInfo;
|
||||
import de.jrpie.android.launcher.actions.lock.LockMethod;
|
||||
import de.jrpie.android.launcher.preferences.theme.Background;
|
||||
import de.jrpie.android.launcher.preferences.theme.ColorTheme;
|
||||
import de.jrpie.android.launcher.preferences.theme.Font;
|
||||
|
@ -62,6 +63,9 @@ import eu.jonahbauer.android.preference.annotations.serializer.PreferenceSeriali
|
|||
@Preference(name = "edge_swipe", type = boolean.class, defaultValue = "true"),
|
||||
@Preference(name = "edge_swipe_edge_width", type = int.class, defaultValue = "15"),
|
||||
}),
|
||||
@PreferenceGroup(name = "actions", prefix = "settings_actions_", suffix = "_key", value = {
|
||||
@Preference(name = "lock_method", type = LockMethod.class, defaultValue = "DEVICE_ADMIN"),
|
||||
}),
|
||||
})
|
||||
public final class LauncherPreferences$Config {
|
||||
public static class AppInfoSetSerializer implements PreferenceSerializer<Set<AppInfo>, Set<String>> {
|
||||
|
|
|
@ -7,6 +7,7 @@ import androidx.preference.PreferenceFragmentCompat
|
|||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.actions.openAppsList
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
import de.jrpie.android.launcher.actions.lock.LockMethod
|
||||
import de.jrpie.android.launcher.setDefaultHomeScreen
|
||||
|
||||
|
||||
|
@ -74,6 +75,15 @@ class SettingsFragmentLauncher : PreferenceFragmentCompat() {
|
|||
openAppsList(requireContext(), favorite = false, hidden = true)
|
||||
true
|
||||
}
|
||||
|
||||
val lockMethod = findPreference<androidx.preference.Preference>(
|
||||
LauncherPreferences.actions().keys().lockMethod()
|
||||
)
|
||||
|
||||
lockMethod?.setOnPreferenceClickListener {
|
||||
LockMethod.chooseMethod(requireContext())
|
||||
true
|
||||
}
|
||||
updateVisibility()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package de.jrpie.android.launcher.ui.util
|
||||
|
||||
import android.content.Context
|
||||
import android.text.Html
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
|
||||
class HtmlTextView(context: Context, attr: AttributeSet?, int: Int) :
|
||||
AppCompatTextView(context, attr, int) {
|
||||
constructor(context: Context, attr: AttributeSet?) : this(context, attr, 0)
|
||||
constructor(context: Context) : this(context, null, 0)
|
||||
|
||||
init {
|
||||
text = Html.fromHtml(text.toString())
|
||||
movementMethod = LinkMovementMethod.getInstance()
|
||||
}
|
||||
}
|
14
app/src/main/res/layout/dialog_select_lock_method.xml
Normal file
14
app/src/main/res/layout/dialog_select_lock_method.xml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="10dp"
|
||||
android:layout_height="match_parent">
|
||||
<de.jrpie.android.launcher.ui.util.HtmlTextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/screen_lock_method_dialog_text"
|
||||
android:id="@+id/dialog_select_lock_method_text"
|
||||
android:textColor="@color/material_dynamic_primary0"
|
||||
/>
|
||||
</LinearLayout>
|
|
@ -102,6 +102,8 @@
|
|||
<string name="settings_functionality_search_auto_open_keyboard_key" translatable="false">functionality.search_auto_keyboard</string>
|
||||
|
||||
|
||||
<string name="settings_actions_lock_method_key">settings_action_lock_method</string>
|
||||
|
||||
|
||||
<!--
|
||||
-
|
||||
|
|
|
@ -247,6 +247,37 @@
|
|||
<string name="toast_accessibility_service_not_enabled">μLauncher\'s accessibility service is not enabled. Please enable it in settings</string>
|
||||
<string name="toast_lock_screen_not_supported">Error: Locking the screen using accessibility is not supported on this device. Please use device admin instead.</string>
|
||||
<string name="accessibility_service_name">µLauncher - lock screen</string>
|
||||
<string name="accessibility_service_description">Setting µLauncher as an accessibility service allows it to lock the screen. Note that excessive permissions are required, you should never grant such permissions lightly to any app. µLauncher will use the accessibility service only for locking the screen. You should check the source code to make sure. Note that locking the screen can also be accomplished by granting µLauncher device administrator permissions. Those are more fine grained. However that method doesn\'t work with fingerprint and facial recognition.</string>
|
||||
<string name="accessibility_service_description">
|
||||
Setting µLauncher as an accessibility service allows it to lock the screen.
|
||||
Note that excessive permissions are required. You should never grant such permissions lightly to any app.
|
||||
|
||||
µLauncher will use the accessibility service only for locking the screen. You can check the source code to make sure.
|
||||
|
||||
Note that locking the screen can also be accomplished by granting µLauncher device administrator permissions. However that method doesn\'t work with fingerprint and face unlock.
|
||||
</string>
|
||||
|
||||
|
||||
<string name="screen_lock_method_dialog_title">Choose Method for Locking</string>
|
||||
<string name="screen_lock_method_dialog_text"><![CDATA[
|
||||
<h1>Choose locking method</h1>
|
||||
There are two methods to lock the screen.
|
||||
Unfortunately both have downsides:<br/><br/>
|
||||
|
||||
<h3>Accessibility Service</h3>
|
||||
Requires excessive privileges.
|
||||
µLauncher will use those privileges only for locking the screen.
|
||||
<br/>
|
||||
(You really should not trust a random app you just downloaded with such a claim, but you can check the <a href=\"https://github.com/jrpie/Launcher\">source code</a>.)
|
||||
<br/>
|
||||
<br/>
|
||||
<h3>Device Admin</h3>
|
||||
Doesn\'t work with unlocking by fingerprint or face recognition.
|
||||
|
||||
<br/><br/><br/><br/>
|
||||
You can change your selection later in settings.
|
||||
]]>
|
||||
</string>
|
||||
<string name="screen_lock_method_use_accessibility">Use Accessibility Service</string>
|
||||
<string name="screen_lock_method_use_device_admin">Use Device Admin</string>
|
||||
<string name="settings_actions_lock_method">Choose method for locking the screen</string>
|
||||
</resources>
|
||||
|
|
|
@ -107,6 +107,10 @@
|
|||
android:title="@string/settings_enabled_gestures_edge_swipe_edge_width"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<Preference
|
||||
android:key="@string/settings_actions_lock_method_key"
|
||||
android:title="@string/settings_actions_lock_method" />
|
||||
|
||||
|
||||
|
||||
</PreferenceCategory>
|
||||
|
|
Loading…
Add table
Reference in a new issue