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.CHANGE_WIFI_STATE"/>
<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-feature android:name="android.software.device_admin"/>
<application
@@ -81,7 +83,7 @@
android:name=".Receiver"
android:description="@string/app_name"
android:permission="android.permission.BIND_DEVICE_ADMIN"
android:exported="true">
android:exported="false">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin"/>
@@ -99,6 +101,12 @@
android:name=".ApiReceiver"
android:exported="true">
</receiver>
<service
android:name=".LockTaskService"
android:exported="false"
android:foregroundServiceType="specialUse" />
<provider
android:name="rikka.shizuku.ShizukuProvider"
android:authorities="${applicationId}.shizuku"

View File

@@ -86,7 +86,7 @@ fun AppLockDialog(onSucceed: () -> Unit, onDismiss: () -> Unit) = Dialog(onDismi
IconButton(onClick = { showPassword = !showPassword }) {
Icon(
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"
)

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.annotation.SuppressLint
import android.app.ActivityManager
import android.app.ActivityOptions
import android.app.Application
import android.app.KeyguardManager
@@ -886,6 +887,7 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
if (intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
application.startActivity(intent, options.toBundle())
application.startForegroundService(Intent(application, LockTaskService::class.java))
return true
} else {
return false

View File

@@ -1,31 +1,17 @@
package com.bintianqi.owndroid
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.admin.DeviceAdminReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Binder
import android.os.Build.VERSION
import android.os.UserHandle
import android.os.UserManager
import androidx.core.app.NotificationCompat
import com.bintianqi.owndroid.dpm.handlePrivilegeChange
import com.bintianqi.owndroid.dpm.retrieveNetworkLogs
import com.bintianqi.owndroid.dpm.retrieveSecurityLogs
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) {
super.onEnabled(context, intent)
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) {
super.onPasswordChanged(context, intent, userHandle)
sendUserRelatedNotification(context, userHandle, NotificationType.PasswordChanged)

View File

@@ -1224,17 +1224,6 @@ private fun StartLockTaskMode(
.verticalScroll(rememberScrollState())
) {
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 }
Row(
Modifier
@@ -1264,7 +1253,6 @@ private fun StartLockTaskMode(
if (!result) context.showOperationResultToast(false)
},
enabled = packageName.isNotBlank() && (!specifyActivity || activity.isNotBlank())
&& !privilege.dhizuku
) {
Text(stringResource(R.string.start))
}

View File

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

View File

@@ -307,7 +307,6 @@
<string name="network_logging">Ağ Kayıtları</string>
<string name="delete_logs">Kayıtları Sil</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="add_config">Yapılandırma Ekle</string>
<string name="network_id">Ağ Kimliği</string>

View File

@@ -173,7 +173,6 @@
<string name="nearby_notification_streaming">附近通知传输</string>
<string name="enable_if_secure_enough">在足够安全时启用</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="disable_all">禁用全部</string>
<string name="ltf_sys_info">允许状态栏信息</string>
@@ -294,7 +293,6 @@
<string name="network_logs_collected">网络日志已收集</string>
<string name="delete_logs">删除日志</string>
<string name="export_logs">导出日志</string>
<string name="wifi_auth_keypair">Wi-Fi密钥对</string>
<string name="preferential_network_service">首选网络服务</string>
<string name="add_config">添加配置</string>
<string name="network_id">网络ID</string>

View File

@@ -102,7 +102,7 @@
<string name="org_name">Organization name</string>
<string name="disable_account_management">Disable account management</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="support_messages">Support Messages</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="enable_if_secure_enough">Same managed account only</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="disable_all">Disable all</string>
<!--ltf: lock task feature-->
@@ -328,7 +327,6 @@
<string name="network_logs_collected">Network logs collected</string>
<string name="delete_logs">Delete 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="add_config">Add config</string>
<string name="network_id">Network ID</string>