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

@@ -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))
}