Improve Lock task mode

Make this feature available in Dhizuku mode
Use foreground service to display the notification
This commit is contained in:
BinTianqi
2025-12-19 00:57:16 +08:00
parent 39d142493a
commit dad57a8846
10 changed files with 95 additions and 54 deletions

View File

@@ -12,6 +12,8 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.USE_BIOMETRIC"/> <uses-permission android:name="android.permission.USE_BIOMETRIC"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
<uses-sdk tools:overrideLibrary="rikka.shizuku.provider,rikka.shizuku.api,rikka.shizuku.shared,rikka.shizuku.aidl,com.rosan.dhizuku.server_api,com.rosan.dhizuku.api"/> <uses-sdk tools:overrideLibrary="rikka.shizuku.provider,rikka.shizuku.api,rikka.shizuku.shared,rikka.shizuku.aidl,com.rosan.dhizuku.server_api,com.rosan.dhizuku.api"/>
<uses-feature android:name="android.software.device_admin"/> <uses-feature android:name="android.software.device_admin"/>
<application <application
@@ -81,7 +83,7 @@
android:name=".Receiver" android:name=".Receiver"
android:description="@string/app_name" android:description="@string/app_name"
android:permission="android.permission.BIND_DEVICE_ADMIN" android:permission="android.permission.BIND_DEVICE_ADMIN"
android:exported="true"> android:exported="false">
<meta-data <meta-data
android:name="android.app.device_admin" android:name="android.app.device_admin"
android:resource="@xml/device_admin"/> android:resource="@xml/device_admin"/>
@@ -99,6 +101,12 @@
android:name=".ApiReceiver" android:name=".ApiReceiver"
android:exported="true"> android:exported="true">
</receiver> </receiver>
<service
android:name=".LockTaskService"
android:exported="false"
android:foregroundServiceType="specialUse" />
<provider <provider
android:name="rikka.shizuku.ShizukuProvider" android:name="rikka.shizuku.ShizukuProvider"
android:authorities="${applicationId}.shizuku" android:authorities="${applicationId}.shizuku"

View File

@@ -86,7 +86,7 @@ fun AppLockDialog(onSucceed: () -> Unit, onDismiss: () -> Unit) = Dialog(onDismi
IconButton(onClick = { showPassword = !showPassword }) { IconButton(onClick = { showPassword = !showPassword }) {
Icon( Icon(
painter = painterResource( painter = painterResource(
id = if (showPassword) R.drawable.visibility_off_fill0 else R.drawable.visibility_fill0 id = if (showPassword) R.drawable.visibility_fill0 else R.drawable.visibility_off_fill0
), ),
contentDescription = if (showPassword) "Hide password" else "Show password" contentDescription = if (showPassword) "Hide password" else "Show password"
) )

View File

@@ -0,0 +1,82 @@
package com.bintianqi.owndroid
import android.app.ActivityManager
import android.app.PendingIntent
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ServiceInfo
import android.os.Build
import android.os.IBinder
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@RequiresApi(28)
class LockTaskService: Service() {
val coroutineScope = CoroutineScope(Dispatchers.IO)
override fun onBind(intent: Intent?): IBinder? = null
val stopReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
coroutineScope.cancel()
stopLockTask()
stop()
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
val filter = IntentFilter(STOP_ACTION)
ContextCompat.registerReceiver(
this, stopReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED
)
val pendingIntent = PendingIntent.getBroadcast(
this, 0, Intent(STOP_ACTION).setPackage(this.packageName), PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(this, MyNotificationChannel.LockTaskMode.id)
.setContentTitle(getText(R.string.lock_task_mode))
.setSmallIcon(R.drawable.lock_fill0)
.addAction(NotificationCompat.Action.Builder(null, getString(R.string.stop), pendingIntent).build())
.build()
ServiceCompat.startForeground(
this, NotificationType.LockTaskMode.id, notification,
if (Build.VERSION.SDK_INT < 34) 0 else ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST
)
coroutineScope.launch {
val am = getSystemService(ActivityManager::class.java)
delay(3000)
while (am.lockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
delay(1000)
}
stop()
}
return START_NOT_STICKY
}
fun stop() {
unregisterReceiver(stopReceiver)
stopSelf()
}
fun stopLockTask() {
val features = Privilege.DPM.getLockTaskFeatures(Privilege.DAR)
val packages = Privilege.DPM.getLockTaskPackages(Privilege.DAR)
Privilege.DPM.setLockTaskPackages(Privilege.DAR, arrayOf())
Privilege.DPM.setLockTaskPackages(Privilege.DAR, packages)
Privilege.DPM.setLockTaskFeatures(Privilege.DAR, features)
}
companion object {
const val STOP_ACTION = "com.bintianqi.owndroid.action.STOP_LOCK_TASK_MODE"
}
}

View File

@@ -2,6 +2,7 @@ package com.bintianqi.owndroid
import android.accounts.Account import android.accounts.Account
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.ActivityManager
import android.app.ActivityOptions import android.app.ActivityOptions
import android.app.Application import android.app.Application
import android.app.KeyguardManager import android.app.KeyguardManager
@@ -886,6 +887,7 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
if (intent != null) { if (intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
application.startActivity(intent, options.toBundle()) application.startActivity(intent, options.toBundle())
application.startForegroundService(Intent(application, LockTaskService::class.java))
return true return true
} else { } else {
return false return false

View File

@@ -1,31 +1,17 @@
package com.bintianqi.owndroid package com.bintianqi.owndroid
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.admin.DeviceAdminReceiver import android.app.admin.DeviceAdminReceiver
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Binder import android.os.Binder
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.UserHandle import android.os.UserHandle
import android.os.UserManager import android.os.UserManager
import androidx.core.app.NotificationCompat
import com.bintianqi.owndroid.dpm.handlePrivilegeChange import com.bintianqi.owndroid.dpm.handlePrivilegeChange
import com.bintianqi.owndroid.dpm.retrieveNetworkLogs import com.bintianqi.owndroid.dpm.retrieveNetworkLogs
import com.bintianqi.owndroid.dpm.retrieveSecurityLogs import com.bintianqi.owndroid.dpm.retrieveSecurityLogs
class Receiver : DeviceAdminReceiver() { class Receiver : DeviceAdminReceiver() {
override fun onReceive(context: Context, intent: Intent) {
super.onReceive(context, intent)
if(VERSION.SDK_INT >= 26 && intent.action == "com.bintianqi.owndroid.action.STOP_LOCK_TASK_MODE") {
val receiver = ComponentName(context, this::class.java)
val packages = Privilege.DPM.getLockTaskPackages(receiver)
Privilege.DPM.setLockTaskPackages(receiver, arrayOf())
Privilege.DPM.setLockTaskPackages(receiver, packages)
}
}
override fun onEnabled(context: Context, intent: Intent) { override fun onEnabled(context: Context, intent: Intent) {
super.onEnabled(context, intent) super.onEnabled(context, intent)
Privilege.updateStatus() Privilege.updateStatus()
@@ -56,25 +42,6 @@ class Receiver : DeviceAdminReceiver() {
} }
} }
override fun onLockTaskModeEntering(context: Context, intent: Intent, pkg: String) {
super.onLockTaskModeEntering(context, intent, pkg)
val stopIntent = Intent(context, this::class.java)
.setAction("com.bintianqi.owndroid.action.STOP_LOCK_TASK_MODE")
val pendingIntent = PendingIntent.getBroadcast(context, 0, stopIntent, PendingIntent.FLAG_IMMUTABLE)
val notification = NotificationCompat.Builder(context, MyNotificationChannel.LockTaskMode.id)
.setContentTitle(context.getText(R.string.lock_task_mode))
.setSmallIcon(R.drawable.lock_fill0)
.addAction(NotificationCompat.Action.Builder(null, context.getString(R.string.stop), pendingIntent).build())
.build()
val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
nm.notify(NotificationType.LockTaskMode.id, notification)
}
override fun onLockTaskModeExiting(context: Context, intent: Intent) {
super.onLockTaskModeExiting(context, intent)
NotificationUtils.cancel(context, NotificationType.LockTaskMode)
}
override fun onPasswordChanged(context: Context, intent: Intent, userHandle: UserHandle) { override fun onPasswordChanged(context: Context, intent: Intent, userHandle: UserHandle) {
super.onPasswordChanged(context, intent, userHandle) super.onPasswordChanged(context, intent, userHandle)
sendUserRelatedNotification(context, userHandle, NotificationType.PasswordChanged) sendUserRelatedNotification(context, userHandle, NotificationType.PasswordChanged)

View File

@@ -1224,17 +1224,6 @@ private fun StartLockTaskMode(
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
Spacer(Modifier.height(5.dp)) Spacer(Modifier.height(5.dp))
if (privilege.dhizuku) Column(
Modifier
.fillMaxWidth().padding(vertical = 8.dp)
.background(colorScheme.errorContainer, RoundedCornerShape(10.dp))
.padding(8.dp)
) {
Text(
stringResource(R.string.start_lock_task_mode_not_supported),
color = colorScheme.onErrorContainer
)
}
PackageNameTextField(packageName, onChoosePackage) { packageName = it } PackageNameTextField(packageName, onChoosePackage) { packageName = it }
Row( Row(
Modifier Modifier
@@ -1264,7 +1253,6 @@ private fun StartLockTaskMode(
if (!result) context.showOperationResultToast(false) if (!result) context.showOperationResultToast(false)
}, },
enabled = packageName.isNotBlank() && (!specifyActivity || activity.isNotBlank()) enabled = packageName.isNotBlank() && (!specifyActivity || activity.isNotBlank())
&& !privilege.dhizuku
) { ) {
Text(stringResource(R.string.start)) Text(stringResource(R.string.start))
} }

View File

@@ -278,7 +278,6 @@
<string name="network_logging">Сетевой журнал</string> <string name="network_logging">Сетевой журнал</string>
<string name="delete_logs">Удалить журналы</string> <string name="delete_logs">Удалить журналы</string>
<string name="export_logs">Экспортировать журналы</string> <string name="export_logs">Экспортировать журналы</string>
<string name="wifi_auth_keypair">Пара ключей Wi-Fi</string>
<string name="preferential_network_service">Предпочтительная сетевая служба</string> <string name="preferential_network_service">Предпочтительная сетевая служба</string>
<string name="add_config">Add config</string> <!--TODO--> <string name="add_config">Add config</string> <!--TODO-->
<string name="network_id">Идентификатор сети</string> <string name="network_id">Идентификатор сети</string>

View File

@@ -307,7 +307,6 @@
<string name="network_logging">Ağ Kayıtları</string> <string name="network_logging">Ağ Kayıtları</string>
<string name="delete_logs">Kayıtları Sil</string> <string name="delete_logs">Kayıtları Sil</string>
<string name="export_logs">Kayıtları Dışa Aktar</string> <string name="export_logs">Kayıtları Dışa Aktar</string>
<string name="wifi_auth_keypair">Wi-Fi Kimlik Doğrulama Anahtar Çifti</string>
<string name="preferential_network_service">Tercihli Ağ Servisi</string> <string name="preferential_network_service">Tercihli Ağ Servisi</string>
<string name="add_config">Yapılandırma Ekle</string> <string name="add_config">Yapılandırma Ekle</string>
<string name="network_id">Ağ Kimliği</string> <string name="network_id">Ağ Kimliği</string>

View File

@@ -173,7 +173,6 @@
<string name="nearby_notification_streaming">附近通知传输</string> <string name="nearby_notification_streaming">附近通知传输</string>
<string name="enable_if_secure_enough">在足够安全时启用</string> <string name="enable_if_secure_enough">在足够安全时启用</string>
<string name="lock_task_mode">锁定任务模式</string> <string name="lock_task_mode">锁定任务模式</string>
<string name="start_lock_task_mode_not_supported">Dhizuku模式下不支持启动锁定任务模式</string>
<string name="app_not_allowed">应用未被允许</string> <string name="app_not_allowed">应用未被允许</string>
<string name="disable_all">禁用全部</string> <string name="disable_all">禁用全部</string>
<string name="ltf_sys_info">允许状态栏信息</string> <string name="ltf_sys_info">允许状态栏信息</string>
@@ -294,7 +293,6 @@
<string name="network_logs_collected">网络日志已收集</string> <string name="network_logs_collected">网络日志已收集</string>
<string name="delete_logs">删除日志</string> <string name="delete_logs">删除日志</string>
<string name="export_logs">导出日志</string> <string name="export_logs">导出日志</string>
<string name="wifi_auth_keypair">Wi-Fi密钥对</string>
<string name="preferential_network_service">首选网络服务</string> <string name="preferential_network_service">首选网络服务</string>
<string name="add_config">添加配置</string> <string name="add_config">添加配置</string>
<string name="network_id">网络ID</string> <string name="network_id">网络ID</string>

View File

@@ -102,7 +102,7 @@
<string name="org_name">Organization name</string> <string name="org_name">Organization name</string>
<string name="disable_account_management">Disable account management</string> <string name="disable_account_management">Disable account management</string>
<string name="account_type">Account type</string> <string name="account_type">Account type</string>
<string name="transfer_ownership">Transfer Ownership</string> <string name="transfer_ownership">Transfer ownership</string>
<string name="lock_screen_info">Lock screen info</string> <string name="lock_screen_info">Lock screen info</string>
<string name="support_messages">Support Messages</string> <string name="support_messages">Support Messages</string>
<string name="short_support_msg">Short message</string> <string name="short_support_msg">Short message</string>
@@ -201,7 +201,6 @@
<string name="nearby_notification_streaming">Nearby notification streaming policy</string> <string name="nearby_notification_streaming">Nearby notification streaming policy</string>
<string name="enable_if_secure_enough">Same managed account only</string> <string name="enable_if_secure_enough">Same managed account only</string>
<string name="lock_task_mode">Lock task mode</string> <string name="lock_task_mode">Lock task mode</string>
<string name="start_lock_task_mode_not_supported">Starting lock task mode is not supported under Dhizuku mode</string>
<string name="app_not_allowed">App is not allowed</string> <string name="app_not_allowed">App is not allowed</string>
<string name="disable_all">Disable all</string> <string name="disable_all">Disable all</string>
<!--ltf: lock task feature--> <!--ltf: lock task feature-->
@@ -328,7 +327,6 @@
<string name="network_logs_collected">Network logs collected</string> <string name="network_logs_collected">Network logs collected</string>
<string name="delete_logs">Delete logs</string> <string name="delete_logs">Delete logs</string>
<string name="export_logs">Export logs</string> <string name="export_logs">Export logs</string>
<string name="wifi_auth_keypair">Wi-Fi keypair</string>
<string name="preferential_network_service">Preferential network service</string> <string name="preferential_network_service">Preferential network service</string>
<string name="add_config">Add config</string> <string name="add_config">Add config</string>
<string name="network_id">Network ID</string> <string name="network_id">Network ID</string>