stop lock task mode with notification

close #36
This commit is contained in:
BinTianqi
2024-07-17 18:17:57 +08:00
parent 8f8ed1ec57
commit a81a437bc3
7 changed files with 85 additions and 12 deletions

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_KEYGUARD"/> <uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_KEYGUARD"/>
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIPE_DATA"/> <uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIPE_DATA"/>
@@ -90,6 +91,10 @@
android:description="@string/app_name" android:description="@string/app_name"
android:permission="android.permission.BIND_DEVICE_ADMIN"> android:permission="android.permission.BIND_DEVICE_ADMIN">
</receiver> </receiver>
<receiver
android:name=".StopLockTaskModeReceiver"
android:description="@string/app_name">
</receiver>
<provider <provider
android:name="rikka.shizuku.ShizukuProvider" android:name="rikka.shizuku.ShizukuProvider"
android:authorities="${applicationId}.shizuku" android:authorities="${applicationId}.shizuku"

View File

@@ -1,5 +1,7 @@
package com.bintianqi.owndroid package com.bintianqi.owndroid
import android.annotation.SuppressLint
import android.app.NotificationManager
import android.app.admin.DeviceAdminReceiver import android.app.admin.DeviceAdminReceiver
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
@@ -10,6 +12,7 @@ import android.content.pm.PackageInstaller.*
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.compose.ui.platform.LocalContext
import com.bintianqi.owndroid.dpm.isDeviceOwner import com.bintianqi.owndroid.dpm.isDeviceOwner
import com.bintianqi.owndroid.dpm.isProfileOwner import com.bintianqi.owndroid.dpm.isProfileOwner
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -61,3 +64,16 @@ class PackageInstallerReceiver:BroadcastReceiver(){
} }
} }
} }
class StopLockTaskModeReceiver: BroadcastReceiver() {
@SuppressLint("NewApi")
override fun onReceive(context: Context, intent: Intent) {
val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val receiver = ComponentName(context,Receiver::class.java)
val packages = dpm.getLockTaskPackages(receiver)
dpm.setLockTaskPackages(receiver, arrayOf())
dpm.setLockTaskPackages(receiver, packages)
val nm = context.getSystemService(ComponentActivity.NOTIFICATION_SERVICE) as NotificationManager
nm.cancel(1)
}
}

View File

@@ -1,8 +1,11 @@
package com.bintianqi.owndroid package com.bintianqi.owndroid
import android.Manifest
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.content.* import android.content.*
import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.Build.VERSION
import android.widget.Toast import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
@@ -69,6 +72,7 @@ fun writeClipBoard(context: Context, string: String):Boolean{
return true return true
} }
lateinit var requestPermission: ActivityResultLauncher<String>
fun registerActivityResult(context: ComponentActivity){ fun registerActivityResult(context: ComponentActivity){
getFile = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult -> getFile = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
@@ -87,4 +91,20 @@ fun registerActivityResult(context: ComponentActivity){
backToHomeStateFlow.value = true backToHomeStateFlow.value = true
} }
} }
requestPermission = context.registerForActivityResult(ActivityResultContracts.RequestPermission()) { permissionGranted.value = it }
}
val permissionGranted = MutableStateFlow<Boolean?>(null)
suspend fun prepareForNotification(context: Context, action: ()->Unit) {
if(VERSION.SDK_INT >= 33) {
if(context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) {
action()
} else {
requestPermission.launch(Manifest.permission.POST_NOTIFICATIONS)
permissionGranted.collect { if(it == true) action() }
}
} else {
action()
}
} }

View File

@@ -3,6 +3,9 @@ package com.bintianqi.owndroid.dpm
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.ActivityOptions import android.app.ActivityOptions
import android.app.AlertDialog import android.app.AlertDialog
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.app.admin.DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY import android.app.admin.DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY
import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback
@@ -78,6 +81,7 @@ import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -88,6 +92,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.app.NotificationCompat
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
@@ -95,8 +100,10 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.Receiver import com.bintianqi.owndroid.Receiver
import com.bintianqi.owndroid.StopLockTaskModeReceiver
import com.bintianqi.owndroid.fileUriFlow import com.bintianqi.owndroid.fileUriFlow
import com.bintianqi.owndroid.getFile import com.bintianqi.owndroid.getFile
import com.bintianqi.owndroid.prepareForNotification
import com.bintianqi.owndroid.toText import com.bintianqi.owndroid.toText
import com.bintianqi.owndroid.toggle import com.bintianqi.owndroid.toggle
import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.Animations
@@ -107,6 +114,7 @@ import com.bintianqi.owndroid.ui.SubPageItem
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.TopBar import com.bintianqi.owndroid.ui.TopBar
import com.bintianqi.owndroid.uriToStream import com.bintianqi.owndroid.uriToStream
import kotlinx.coroutines.launch
import java.util.Date import java.util.Date
import java.util.TimeZone import java.util.TimeZone
import java.util.concurrent.Executors import java.util.concurrent.Executors
@@ -650,6 +658,7 @@ private fun LockTaskMode() {
val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val receiver = ComponentName(context,Receiver::class.java) val receiver = ComponentName(context,Receiver::class.java)
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
val coroutine = rememberCoroutineScope()
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
val lockTaskFeatures = remember { mutableStateListOf<Int>() } val lockTaskFeatures = remember { mutableStateListOf<Int>() }
var custom by remember { mutableStateOf(false) } var custom by remember { mutableStateOf(false) }
@@ -763,18 +772,13 @@ private fun LockTaskMode() {
) )
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Button( Button(
onClick = { onClick = { lockTaskPackages.add(inputLockTaskPkg) },
lockTaskPackages.add(inputLockTaskPkg)
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
},
modifier = Modifier.fillMaxWidth(0.49F) modifier = Modifier.fillMaxWidth(0.49F)
) { ) {
Text(stringResource(R.string.add)) Text(stringResource(R.string.add))
} }
Button( Button(
onClick = { onClick = { lockTaskPackages.remove(inputLockTaskPkg) },
Toast.makeText(context, if(lockTaskPackages.remove(inputLockTaskPkg)) R.string.success else R.string.not_exist, Toast.LENGTH_SHORT).show()
},
modifier = Modifier.fillMaxWidth(0.96F) modifier = Modifier.fillMaxWidth(0.96F)
) { ) {
Text(stringResource(R.string.remove)) Text(stringResource(R.string.remove))
@@ -812,8 +816,13 @@ private fun LockTaskMode() {
val packageManager = context.packageManager val packageManager = context.packageManager
val launchIntent = packageManager.getLaunchIntentForPackage(startLockTaskApp) val launchIntent = packageManager.getLaunchIntentForPackage(startLockTaskApp)
if (launchIntent != null) { if (launchIntent != null) {
coroutine.launch {
prepareForNotification(context) {
sendStopLockTaskNotification(context)
context.startActivity(launchIntent, options.toBundle()) context.startActivity(launchIntent, options.toBundle())
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
}
}
} else { } else {
Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show()
} }
@@ -1303,3 +1312,23 @@ fun InstallSystemUpdate() {
Spacer(Modifier.padding(vertical = 30.dp)) Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@SuppressLint("NewApi")
private fun sendStopLockTaskNotification(context: Context) {
val nm = context.getSystemService(ComponentActivity.NOTIFICATION_SERVICE) as NotificationManager
if (VERSION.SDK_INT >= 26) {
val channel = NotificationChannel("LockTaskMode", context.getString(R.string.lock_task_mode), NotificationManager.IMPORTANCE_HIGH).apply {
description = "Notification channel for stop lock task mode"
setShowBadge(false)
}
nm.createNotificationChannel(channel)
}
val intent = Intent(context, StopLockTaskModeReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
val builder = NotificationCompat.Builder(context, "LockTaskMode")
.setContentTitle(context.getText(R.string.lock_task_mode))
.setSmallIcon(R.drawable.lock_fill0)
.addAction(NotificationCompat.Action.Builder(R.drawable.lock_fill0, context.getText(R.string.stop), pendingIntent).build())
.setPriority(NotificationCompat.PRIORITY_HIGH)
nm.notify(1, builder.build())
}

View File

@@ -50,6 +50,7 @@
<string name="io_exception">G/Ç Hatası</string> <string name="io_exception">G/Ç Hatası</string>
<string name="current_status_is">Mevcut Durum: </string> <string name="current_status_is">Mevcut Durum: </string>
<string name="start">Başlat</string> <string name="start">Başlat</string>
<string name="stop">Stop</string> <!--TODO-->
<string name="unknown_error">Bilinmeyen Hata</string> <string name="unknown_error">Bilinmeyen Hata</string>
<string name="allow_all">Tümünü İzin Ver</string> <string name="allow_all">Tümünü İzin Ver</string>
<string name="use_policy">Politika Kullan</string> <string name="use_policy">Politika Kullan</string>

View File

@@ -47,6 +47,7 @@
<string name="io_exception">IO异常</string> <string name="io_exception">IO异常</string>
<string name="current_status_is">当前状态:</string> <string name="current_status_is">当前状态:</string>
<string name="start">开始</string> <string name="start">开始</string>
<string name="stop">停止</string>
<string name="unknown_error">未知错误</string> <string name="unknown_error">未知错误</string>
<string name="allow_all">允许全部</string> <string name="allow_all">允许全部</string>
<string name="use_policy">使用策略</string> <string name="use_policy">使用策略</string>

View File

@@ -50,6 +50,7 @@
<string name="io_exception">IO Exception</string> <string name="io_exception">IO Exception</string>
<string name="current_status_is">Current status: </string> <string name="current_status_is">Current status: </string>
<string name="start">Start</string> <string name="start">Start</string>
<string name="stop">Stop</string>
<string name="unknown_error">Unknown error</string> <string name="unknown_error">Unknown error</string>
<string name="allow_all">Allow all</string> <string name="allow_all">Allow all</string>
<string name="use_policy">Use policy</string> <string name="use_policy">Use policy</string>