mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 19:15:58 +00:00
Optimize start/stop lock task mode flow
Optimize Package selector
This commit is contained in:
@@ -91,10 +91,6 @@
|
||||
android:description="@string/app_name"
|
||||
android:permission="android.permission.BIND_DEVICE_ADMIN">
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".StopLockTaskModeReceiver"
|
||||
android:description="@string/app_name">
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".ApiReceiver"
|
||||
android:exported="true">
|
||||
|
||||
@@ -37,7 +37,6 @@ import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
@@ -188,7 +187,6 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
val receiver = context.getReceiver()
|
||||
val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)
|
||||
val focusMgr = LocalFocusManager.current
|
||||
val dialogStatus = remember { mutableIntStateOf(0) }
|
||||
val backToHome by backToHomeStateFlow.collectAsState()
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
LaunchedEffect(backToHome) {
|
||||
@@ -227,7 +225,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
composable(route = "PermissionPolicy") { PermissionPolicy(navCtrl) }
|
||||
composable(route = "MTEPolicy") { MTEPolicy(navCtrl) }
|
||||
composable(route = "NearbyStreamingPolicy") { NearbyStreamingPolicy(navCtrl) }
|
||||
composable(route = "LockTaskMode") { LockTaskMode(navCtrl) }
|
||||
composable(route = "LockTaskMode") { LockTaskMode(navCtrl, vm) }
|
||||
composable(route = "CACert") { CACert(navCtrl) }
|
||||
composable(route = "SecurityLogging") { SecurityLogging(navCtrl) }
|
||||
composable(route = "DisableAccountManagement") { DisableAccountManagement(navCtrl) }
|
||||
@@ -241,7 +239,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
composable(route = "MinWifiSecurityLevel") { WifiSecurityLevel(navCtrl) }
|
||||
composable(route = "WifiSsidPolicy") { WifiSsidPolicy(navCtrl) }
|
||||
composable(route = "PrivateDNS") { PrivateDNS(navCtrl) }
|
||||
composable(route = "AlwaysOnVpn") { AlwaysOnVPNPackage(navCtrl) }
|
||||
composable(route = "AlwaysOnVpn") { AlwaysOnVPNPackage(navCtrl, vm) }
|
||||
composable(route = "RecommendedGlobalProxy") { RecommendedGlobalProxy(navCtrl) }
|
||||
composable(route = "NetworkLog") { NetworkLogging(navCtrl) }
|
||||
composable(route = "WifiAuthKeypair") { WifiAuthKeypair(navCtrl) }
|
||||
@@ -255,7 +253,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
composable(route = "IntentFilter") { IntentFilter(navCtrl) }
|
||||
composable(route = "DeleteWorkProfile") { DeleteWorkProfile(navCtrl) }
|
||||
|
||||
composable(route = "Applications") { ApplicationManage(navCtrl, dialogStatus) }
|
||||
composable(route = "Applications") { ApplicationManage(navCtrl, vm) }
|
||||
|
||||
composable(route = "UserRestriction") { UserRestriction(navCtrl) }
|
||||
composable(route = "UR-Internet") {
|
||||
@@ -302,7 +300,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
composable(route = "ApiSettings") { ApiSettings(navCtrl) }
|
||||
composable(route = "About") { About(navCtrl) }
|
||||
|
||||
composable(route = "PackageSelector") { PackageSelector(navCtrl) }
|
||||
composable(route = "PackageSelector") { PackageSelector(navCtrl, vm) }
|
||||
|
||||
composable(
|
||||
route = "Authenticate",
|
||||
|
||||
@@ -10,6 +10,8 @@ import kotlinx.coroutines.launch
|
||||
|
||||
class MyViewModel: ViewModel() {
|
||||
val theme = MutableStateFlow(ThemeSettings())
|
||||
val installedPackages = mutableListOf<PackageInfo>()
|
||||
val selectedPackage = MutableStateFlow("")
|
||||
val shizukuBinder = MutableStateFlow<IBinder?>(null)
|
||||
|
||||
var initialized = false
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.bintianqi.owndroid
|
||||
|
||||
import android.Manifest
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
|
||||
/**
|
||||
* ### Notification channels
|
||||
* - LockTaskMode
|
||||
*
|
||||
* ### Notification IDs
|
||||
* - 1: Stop lock task mode
|
||||
*/
|
||||
object NotificationUtils {
|
||||
fun checkPermission(context: Context): Boolean {
|
||||
return if(Build.VERSION.SDK_INT >= 33)
|
||||
context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
|
||||
else false
|
||||
}
|
||||
fun registerChannels(context: Context) {
|
||||
if(Build.VERSION.SDK_INT < 26) return
|
||||
val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
val channel = NotificationChannel("LockTaskMode", context.getString(R.string.lock_task_mode), NotificationManager.IMPORTANCE_HIGH)
|
||||
nm.createNotificationChannel(channel)
|
||||
}
|
||||
}
|
||||
@@ -54,24 +54,19 @@ import com.bintianqi.owndroid.ui.NavIcon
|
||||
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
private data class PkgInfo(
|
||||
data class PackageInfo(
|
||||
val pkgName: String,
|
||||
val label: String,
|
||||
val icon: Drawable,
|
||||
val system: Boolean
|
||||
)
|
||||
|
||||
private val pkgs = mutableListOf<PkgInfo>()
|
||||
|
||||
val selectedPackage = MutableStateFlow("")
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun PackageSelector(navCtrl: NavHostController) {
|
||||
fun PackageSelector(navCtrl: NavHostController, vm: MyViewModel) {
|
||||
val context = LocalContext.current
|
||||
val pm = context.packageManager
|
||||
val apps = pm.getInstalledApplications(0)
|
||||
@@ -88,9 +83,9 @@ fun PackageSelector(navCtrl: NavHostController) {
|
||||
show = false
|
||||
progress = 0
|
||||
hideProgress = false
|
||||
pkgs.clear()
|
||||
vm.installedPackages.clear()
|
||||
for(pkg in apps) {
|
||||
pkgs += PkgInfo(
|
||||
vm.installedPackages += PackageInfo(
|
||||
pkg.packageName, pkg.loadLabel(pm).toString(), pkg.loadIcon(pm),
|
||||
(pkg.flags and ApplicationInfo.FLAG_SYSTEM) != 0
|
||||
)
|
||||
@@ -181,14 +176,14 @@ fun PackageSelector(navCtrl: NavHostController) {
|
||||
}
|
||||
}
|
||||
if(show) {
|
||||
items(pkgs) {
|
||||
items(vm.installedPackages) {
|
||||
if(system == it.system) {
|
||||
if(search != "") {
|
||||
if(it.pkgName.contains(search, ignoreCase = true) || it.label.contains(search, ignoreCase = true)) {
|
||||
PackageItem(it, navCtrl)
|
||||
PackageItem(it, navCtrl, vm)
|
||||
}
|
||||
} else {
|
||||
PackageItem(it, navCtrl)
|
||||
PackageItem(it, navCtrl, vm)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,13 +196,13 @@ fun PackageSelector(navCtrl: NavHostController) {
|
||||
}
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
if(pkgs.size == 0) { getPkgList() }
|
||||
if(vm.installedPackages.isEmpty()) { getPkgList() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PackageItem(pkg: PkgInfo, navCtrl: NavHostController) {
|
||||
private fun PackageItem(pkg: PackageInfo, navCtrl: NavHostController, vm: MyViewModel) {
|
||||
val focusMgr = LocalFocusManager.current
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
@@ -215,7 +210,7 @@ private fun PackageItem(pkg: PkgInfo, navCtrl: NavHostController) {
|
||||
.fillMaxWidth()
|
||||
.clickable{
|
||||
focusMgr.clearFocus()
|
||||
selectedPackage.value = pkg.pkgName
|
||||
vm.selectedPackage.value = pkg.pkgName
|
||||
navCtrl.navigateUp()
|
||||
}
|
||||
.padding(horizontal = 8.dp, vertical = 10.dp)
|
||||
@@ -1,9 +1,10 @@
|
||||
package com.bintianqi.owndroid
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.admin.DeviceAdminReceiver
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInstaller.EXTRA_STATUS
|
||||
@@ -21,8 +22,7 @@ import android.os.Build.VERSION
|
||||
import android.os.PersistableBundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import com.bintianqi.owndroid.dpm.getDPM
|
||||
import com.bintianqi.owndroid.dpm.getReceiver
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.bintianqi.owndroid.dpm.handleNetworkLogs
|
||||
import com.bintianqi.owndroid.dpm.handleSecurityLogs
|
||||
import com.bintianqi.owndroid.dpm.isDeviceAdmin
|
||||
@@ -35,6 +35,17 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
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 dpm = getManager(context)
|
||||
val receiver = ComponentName(context, this::class.java)
|
||||
val packages = dpm.getLockTaskPackages(receiver)
|
||||
dpm.setLockTaskPackages(receiver, arrayOf())
|
||||
dpm.setLockTaskPackages(receiver, packages)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onEnabled(context: Context, intent: Intent) {
|
||||
super.onEnabled(context, intent)
|
||||
context.toggleInstallAppActivity()
|
||||
@@ -78,6 +89,26 @@ class Receiver : DeviceAdminReceiver() {
|
||||
sp.edit().putBoolean("dhizuku", false).apply()
|
||||
context.toggleInstallAppActivity()
|
||||
}
|
||||
|
||||
override fun onLockTaskModeEntering(context: Context, intent: Intent, pkg: String) {
|
||||
super.onLockTaskModeEntering(context, intent, pkg)
|
||||
NotificationUtils.registerChannels(context)
|
||||
val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
val intent = Intent(context, this::class.java).apply { action = "com.bintianqi.owndroid.action.STOP_LOCK_TASK_MODE" }
|
||||
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(null, context.getString(R.string.stop), pendingIntent).build())
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
nm.notify(1, builder.build())
|
||||
}
|
||||
|
||||
override fun onLockTaskModeExiting(context: Context, intent: Intent) {
|
||||
super.onLockTaskModeExiting(context, intent)
|
||||
val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
nm.cancel(1)
|
||||
}
|
||||
}
|
||||
|
||||
val installAppDone = MutableStateFlow(false)
|
||||
@@ -105,16 +136,3 @@ class PackageInstallerReceiver: BroadcastReceiver() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StopLockTaskModeReceiver: BroadcastReceiver() {
|
||||
@SuppressLint("NewApi")
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val packages = dpm.getLockTaskPackages(receiver)
|
||||
dpm.setLockTaskPackages(receiver, arrayOf())
|
||||
dpm.setLockTaskPackages(receiver, packages)
|
||||
val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
nm.cancel(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
package com.bintianqi.owndroid
|
||||
|
||||
import android.Manifest
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build.VERSION
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
@@ -65,7 +62,6 @@ fun writeClipBoard(context: Context, string: String):Boolean{
|
||||
return true
|
||||
}
|
||||
|
||||
lateinit var requestPermission: ActivityResultLauncher<String>
|
||||
lateinit var exportFile: ActivityResultLauncher<Intent>
|
||||
var exportFilePath: String? = null
|
||||
var isExportingSecurityOrNetworkLogs = false
|
||||
@@ -83,7 +79,6 @@ fun registerActivityResult(context: ComponentActivity){
|
||||
backToHomeStateFlow.value = true
|
||||
}
|
||||
}
|
||||
requestPermission = context.registerForActivityResult(ActivityResultContracts.RequestPermission()) { permissionGranted.value = it }
|
||||
exportFile = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
val intentData = result.data ?: return@registerForActivityResult
|
||||
val uriData = intentData.data ?: return@registerForActivityResult
|
||||
@@ -103,21 +98,6 @@ fun registerActivityResult(context: ComponentActivity){
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
fun formatFileSize(bytes: Long): String {
|
||||
val kb = 1024
|
||||
val mb = kb * 1024
|
||||
|
||||
@@ -50,7 +50,6 @@ import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableIntState
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
@@ -74,37 +73,37 @@ import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.bintianqi.owndroid.InstallAppActivity
|
||||
import com.bintianqi.owndroid.MyViewModel
|
||||
import com.bintianqi.owndroid.PackageInstallerReceiver
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.fileUriFlow
|
||||
import com.bintianqi.owndroid.getFile
|
||||
import com.bintianqi.owndroid.selectedPackage
|
||||
import com.bintianqi.owndroid.ui.Animations
|
||||
import com.bintianqi.owndroid.ui.FunctionItem
|
||||
import com.bintianqi.owndroid.ui.InfoCard
|
||||
import com.bintianqi.owndroid.ui.Information
|
||||
import com.bintianqi.owndroid.ui.ListItem
|
||||
import com.bintianqi.owndroid.ui.NavIcon
|
||||
import com.bintianqi.owndroid.ui.RadioButtonItem
|
||||
import com.bintianqi.owndroid.ui.FunctionItem
|
||||
import com.bintianqi.owndroid.ui.SwitchItem
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ApplicationManage(navCtrl:NavHostController, dialogStatus: MutableIntState) {
|
||||
fun ApplicationManage(navCtrl:NavHostController, vm: MyViewModel) {
|
||||
val focusMgr = LocalFocusManager.current
|
||||
val localNavCtrl = rememberNavController()
|
||||
var pkgName by rememberSaveable { mutableStateOf("") }
|
||||
val updatePackage by selectedPackage.collectAsState()
|
||||
val updatePackage by vm.selectedPackage.collectAsStateWithLifecycle()
|
||||
LaunchedEffect(updatePackage) {
|
||||
if(updatePackage != "") {
|
||||
pkgName = updatePackage
|
||||
selectedPackage.value = ""
|
||||
vm.selectedPackage.value = ""
|
||||
}
|
||||
}
|
||||
Scaffold(
|
||||
@@ -145,9 +144,7 @@ fun ApplicationManage(navCtrl:NavHostController, dialogStatus: MutableIntState)
|
||||
popEnterTransition = Animations.navHostPopEnterTransition,
|
||||
popExitTransition = Animations.navHostPopExitTransition
|
||||
) {
|
||||
composable(route = "Home") {
|
||||
Home(localNavCtrl, pkgName, dialogStatus)
|
||||
}
|
||||
composable(route = "Home") { Home(localNavCtrl, pkgName) }
|
||||
composable(route = "UserControlDisabled") { UserCtrlDisabledPkg(pkgName) }
|
||||
composable(route = "PermissionManage") { PermissionManage(pkgName) }
|
||||
composable(route = "CrossProfilePackage") { CrossProfilePkg(pkgName) }
|
||||
@@ -160,23 +157,11 @@ fun ApplicationManage(navCtrl:NavHostController, dialogStatus: MutableIntState)
|
||||
composable(route = "UninstallApp") { UninstallApp(pkgName) }
|
||||
}
|
||||
}
|
||||
when(dialogStatus.intValue) {
|
||||
0 -> {}
|
||||
1 -> EnableSystemAppDialog(dialogStatus, pkgName)
|
||||
2 -> ClearAppDataDialog(dialogStatus, pkgName)
|
||||
3 -> DefaultDialerAppDialog(dialogStatus, pkgName)
|
||||
}
|
||||
LaunchedEffect(dialogStatus.intValue) {
|
||||
focusMgr.clearFocus()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Home(
|
||||
navCtrl:NavHostController,
|
||||
pkgName: String,
|
||||
dialogStatus: MutableIntState
|
||||
) {
|
||||
private fun Home(navCtrl:NavHostController, pkgName: String) {
|
||||
var dialogStatus by remember { mutableIntStateOf(0) }
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
@@ -190,7 +175,6 @@ private fun Home(
|
||||
hide = dpm.isApplicationHidden(receiver, pkgName)
|
||||
var blockUninstall by remember { mutableStateOf(false) }
|
||||
blockUninstall = dpm.isUninstallBlocked(receiver,pkgName)
|
||||
var appControlDialog by remember { mutableStateOf(false) }
|
||||
var appControlAction by remember { mutableIntStateOf(0) }
|
||||
val focusMgr = LocalFocusManager.current
|
||||
val appControl: (Boolean) -> Unit = {
|
||||
@@ -226,20 +210,20 @@ private fun Home(
|
||||
title = R.string.suspend, desc = "", icon = R.drawable.block_fill0,
|
||||
state = suspend,
|
||||
onCheckedChange = { appControlAction = 1; appControl(it) },
|
||||
onClickBlank = { appControlAction = 1; appControlDialog = true }
|
||||
onClickBlank = { appControlAction = 1; dialogStatus = 4 }
|
||||
)
|
||||
}
|
||||
SwitchItem(
|
||||
title = R.string.hide, desc = stringResource(R.string.isapphidden_desc), icon = R.drawable.visibility_off_fill0,
|
||||
state = hide,
|
||||
onCheckedChange = { appControlAction = 2; appControl(it) },
|
||||
onClickBlank = { appControlAction = 2; appControlDialog = true }
|
||||
onClickBlank = { appControlAction = 2; dialogStatus = 4 }
|
||||
)
|
||||
SwitchItem(
|
||||
title = R.string.block_uninstall, desc = "", icon = R.drawable.delete_forever_fill0,
|
||||
state = blockUninstall,
|
||||
onCheckedChange = { appControlAction = 3; appControl(it) },
|
||||
onClickBlank = { appControlAction = 3; appControlDialog = true }
|
||||
onClickBlank = { appControlAction = 3; dialogStatus = 4 }
|
||||
)
|
||||
if((VERSION.SDK_INT >= 33 && profileOwner) || (VERSION.SDK_INT >= 30 && deviceOwner)) {
|
||||
FunctionItem(R.string.ucd, "", R.drawable.do_not_touch_fill0) { navCtrl.navigate("UserControlDisabled") }
|
||||
@@ -259,32 +243,124 @@ private fun Home(
|
||||
FunctionItem(R.string.permitted_accessibility_services, "", R.drawable.settings_accessibility_fill0) { navCtrl.navigate("Accessibility") }
|
||||
FunctionItem(R.string.permitted_ime, "", R.drawable.keyboard_fill0) { navCtrl.navigate("IME") }
|
||||
FunctionItem(R.string.enable_system_app, "", R.drawable.enable_fill0) {
|
||||
if(pkgName != "") dialogStatus.intValue = 1
|
||||
if(pkgName != "") dialogStatus = 1
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28 && deviceOwner) {
|
||||
FunctionItem(R.string.keep_uninstalled_packages, "", R.drawable.delete_fill0) { navCtrl.navigate("KeepUninstalled") }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28) {
|
||||
FunctionItem(R.string.clear_app_storage, "", R.drawable.mop_fill0) {
|
||||
if(pkgName != "") dialogStatus.intValue = 2
|
||||
if(pkgName != "") dialogStatus = 2
|
||||
}
|
||||
}
|
||||
FunctionItem(R.string.install_app, "", R.drawable.install_mobile_fill0) { navCtrl.navigate("InstallApp") }
|
||||
FunctionItem(R.string.uninstall_app, "", R.drawable.delete_fill0) { navCtrl.navigate("UninstallApp") }
|
||||
if(VERSION.SDK_INT >= 34 && (deviceOwner || dpm.isOrgProfile(receiver))) {
|
||||
FunctionItem(R.string.set_default_dialer, "", R.drawable.call_fill0) {
|
||||
if(pkgName != "") dialogStatus.intValue = 3
|
||||
if(pkgName != "") dialogStatus = 3
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 30.dp))
|
||||
LaunchedEffect(Unit) { fileUriFlow.value = Uri.parse("") }
|
||||
}
|
||||
if(appControlDialog) {
|
||||
if(dialogStatus == 1) AlertDialog(
|
||||
title = { Text(stringResource(R.string.enable_system_app)) },
|
||||
text = {
|
||||
Text(stringResource(R.string.enable_system_app_desc) + "\n" + pkgName)
|
||||
},
|
||||
onDismissRequest = { dialogStatus = 0 },
|
||||
dismissButton = {
|
||||
TextButton(onClick = { dialogStatus = 0 }) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
try {
|
||||
dpm.enableSystemApp(receiver, pkgName)
|
||||
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
|
||||
} catch(_: IllegalArgumentException) {
|
||||
Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
dialogStatus = 0
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.confirm))
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
if(dialogStatus == 2 && VERSION.SDK_INT >= 28) AlertDialog(
|
||||
title = { Text(text = stringResource(R.string.clear_app_storage)) },
|
||||
text = {
|
||||
Text(stringResource(R.string.app_storage_will_be_cleared) + "\n" + pkgName)
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
val executor = Executors.newCachedThreadPool()
|
||||
val onClear = DevicePolicyManager.OnClearApplicationUserDataListener { pkg: String, succeed: Boolean ->
|
||||
Looper.prepare()
|
||||
val toastText =
|
||||
if(pkg!="") { "$pkg\n" }else{ "" } +
|
||||
context.getString(R.string.clear_data) +
|
||||
context.getString(if(succeed) R.string.success else R.string.failed )
|
||||
Toast.makeText(context, toastText, Toast.LENGTH_SHORT).show()
|
||||
Looper.loop()
|
||||
}
|
||||
dpm.clearApplicationUserData(receiver, pkgName, executor, onClear)
|
||||
dialogStatus = 0
|
||||
},
|
||||
colors = ButtonDefaults.textButtonColors(contentColor = colorScheme.error)
|
||||
) {
|
||||
Text(text = stringResource(R.string.clear))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = { dialogStatus = 0 }
|
||||
) {
|
||||
Text(text = stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
onDismissRequest = { dialogStatus = 0 },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
if(dialogStatus == 3 && VERSION.SDK_INT >= 34) AlertDialog(
|
||||
title = { Text(stringResource(R.string.set_default_dialer)) },
|
||||
text = {
|
||||
Text(stringResource(R.string.app_will_be_default_dialer) + "\n" + pkgName)
|
||||
},
|
||||
onDismissRequest = { dialogStatus = 0 },
|
||||
dismissButton = {
|
||||
TextButton(onClick = { dialogStatus = 0 }) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
try{
|
||||
dpm.setDefaultDialerApplication(pkgName)
|
||||
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
|
||||
} catch(_: IllegalArgumentException) {
|
||||
Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
dialogStatus = 0
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.confirm))
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
if(dialogStatus == 4) {
|
||||
LaunchedEffect(Unit) {
|
||||
focusMgr.clearFocus()
|
||||
}
|
||||
AlertDialog(
|
||||
onDismissRequest = { appControlDialog = false },
|
||||
onDismissRequest = { dialogStatus = 0 },
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(
|
||||
@@ -316,7 +392,7 @@ private fun Home(
|
||||
TextButton(
|
||||
onClick = {
|
||||
appControl(true)
|
||||
appControlDialog = false
|
||||
dialogStatus = 0
|
||||
}
|
||||
) {
|
||||
Text(text = stringResource(R.string.enable))
|
||||
@@ -326,7 +402,7 @@ private fun Home(
|
||||
TextButton(
|
||||
onClick = {
|
||||
appControl(false)
|
||||
appControlDialog = false
|
||||
dialogStatus = 0
|
||||
}
|
||||
) {
|
||||
Text(text = stringResource(R.string.disable))
|
||||
@@ -334,6 +410,7 @@ private fun Home(
|
||||
}
|
||||
)
|
||||
}
|
||||
LaunchedEffect(dialogStatus) { focusMgr.clearFocus() }
|
||||
}
|
||||
|
||||
|
||||
@@ -697,9 +774,7 @@ private fun PermittedAccessibility(pkgName: String) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Information {
|
||||
Text(stringResource(R.string.system_accessibility_always_allowed))
|
||||
}
|
||||
InfoCard(R.string.system_accessibility_always_allowed)
|
||||
Spacer(Modifier.padding(vertical = 30.dp))
|
||||
}
|
||||
}
|
||||
@@ -755,9 +830,7 @@ private fun PermittedIME(pkgName: String) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Information {
|
||||
Text(stringResource(R.string.system_ime_always_allowed))
|
||||
}
|
||||
InfoCard(R.string.system_ime_always_allowed)
|
||||
Spacer(Modifier.padding(vertical = 30.dp))
|
||||
}
|
||||
}
|
||||
@@ -892,117 +965,3 @@ private fun InstallApp() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Composable
|
||||
private fun ClearAppDataDialog(status: MutableIntState, pkgName: String) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
AlertDialog(
|
||||
title = { Text(text = stringResource(R.string.clear_app_storage)) },
|
||||
text = {
|
||||
Text(stringResource(R.string.app_storage_will_be_cleared) + "\n" + pkgName)
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
val executor = Executors.newCachedThreadPool()
|
||||
val onClear = DevicePolicyManager.OnClearApplicationUserDataListener { pkg: String, succeed: Boolean ->
|
||||
Looper.prepare()
|
||||
val toastText =
|
||||
if(pkg!="") { "$pkg\n" }else{ "" } +
|
||||
context.getString(R.string.clear_data) +
|
||||
context.getString(if(succeed) R.string.success else R.string.failed )
|
||||
Toast.makeText(context, toastText, Toast.LENGTH_SHORT).show()
|
||||
Looper.loop()
|
||||
}
|
||||
dpm.clearApplicationUserData(receiver, pkgName, executor, onClear)
|
||||
status.intValue = 0
|
||||
},
|
||||
colors = ButtonDefaults.textButtonColors(contentColor = colorScheme.error)
|
||||
) {
|
||||
Text(text = stringResource(R.string.clear))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = { status.intValue = 0 }
|
||||
) {
|
||||
Text(text = stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
onDismissRequest = { status.intValue = 0 },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Composable
|
||||
private fun DefaultDialerAppDialog(status: MutableIntState, pkgName: String) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
AlertDialog(
|
||||
title = { Text(stringResource(R.string.set_default_dialer)) },
|
||||
text = {
|
||||
Text(stringResource(R.string.app_will_be_default_dialer) + "\n" + pkgName)
|
||||
},
|
||||
onDismissRequest = { status.intValue = 0 },
|
||||
dismissButton = {
|
||||
TextButton(onClick = { status.intValue = 0 }) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
try{
|
||||
dpm.setDefaultDialerApplication(pkgName)
|
||||
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
|
||||
}catch(_: IllegalArgumentException) {
|
||||
Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
status.intValue = 0
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.confirm))
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EnableSystemAppDialog(status: MutableIntState, pkgName: String) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
AlertDialog(
|
||||
title = { Text(stringResource(R.string.enable_system_app)) },
|
||||
text = {
|
||||
Text(stringResource(R.string.enable_system_app_desc) + "\n" + pkgName)
|
||||
},
|
||||
onDismissRequest = { status.intValue = 0 },
|
||||
dismissButton = {
|
||||
TextButton(onClick = { status.intValue = 0 }) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
try {
|
||||
dpm.enableSystemApp(receiver, pkgName)
|
||||
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
|
||||
} catch(_: IllegalArgumentException) {
|
||||
Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
status.intValue = 0
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.confirm))
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -92,12 +92,12 @@ import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.net.toUri
|
||||
import androidx.navigation.NavHostController
|
||||
import com.bintianqi.owndroid.MyViewModel
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.exportFile
|
||||
import com.bintianqi.owndroid.exportFilePath
|
||||
import com.bintianqi.owndroid.formatFileSize
|
||||
import com.bintianqi.owndroid.isExportingSecurityOrNetworkLogs
|
||||
import com.bintianqi.owndroid.selectedPackage
|
||||
import com.bintianqi.owndroid.ui.CheckBoxItem
|
||||
import com.bintianqi.owndroid.ui.FunctionItem
|
||||
import com.bintianqi.owndroid.ui.InfoCard
|
||||
@@ -400,7 +400,7 @@ fun PrivateDNS(navCtrl: NavHostController) {
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Composable
|
||||
fun AlwaysOnVPNPackage(navCtrl: NavHostController) {
|
||||
fun AlwaysOnVPNPackage(navCtrl: NavHostController, vm: MyViewModel) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
@@ -409,11 +409,11 @@ fun AlwaysOnVPNPackage(navCtrl: NavHostController) {
|
||||
val focusMgr = LocalFocusManager.current
|
||||
val refresh = { pkgName = dpm.getAlwaysOnVpnPackage(receiver) ?: "" }
|
||||
LaunchedEffect(Unit) { refresh() }
|
||||
val updatePackage by selectedPackage.collectAsState()
|
||||
val updatePackage by vm.selectedPackage.collectAsState()
|
||||
LaunchedEffect(updatePackage) {
|
||||
if(selectedPackage.value != "") {
|
||||
pkgName = selectedPackage.value
|
||||
selectedPackage.value = ""
|
||||
if(updatePackage != "") {
|
||||
pkgName = updatePackage
|
||||
vm.selectedPackage.value = ""
|
||||
}
|
||||
}
|
||||
val setAlwaysOnVpn: (String?, Boolean)->Boolean = { vpnPkg: String?, lockdownEnabled: Boolean ->
|
||||
|
||||
@@ -75,7 +75,6 @@ import com.bintianqi.owndroid.ui.CardItem
|
||||
import com.bintianqi.owndroid.ui.CheckBoxItem
|
||||
import com.bintianqi.owndroid.ui.FunctionItem
|
||||
import com.bintianqi.owndroid.ui.InfoCard
|
||||
import com.bintianqi.owndroid.ui.Information
|
||||
import com.bintianqi.owndroid.ui.MyScaffold
|
||||
import com.bintianqi.owndroid.ui.RadioButtonItem
|
||||
import com.bintianqi.owndroid.yesOrNo
|
||||
@@ -303,7 +302,7 @@ fun ResetPasswordToken(navCtrl: NavHostController) {
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
Information{ Text(stringResource(R.string.activate_token_not_required_when_no_password)) }
|
||||
InfoCard(R.string.activate_token_not_required_when_no_password)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,6 @@ package com.bintianqi.owndroid.dpm
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ActivityOptions
|
||||
import android.app.AlertDialog
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.admin.DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY
|
||||
import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback
|
||||
import android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK
|
||||
@@ -107,10 +104,11 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavHostController
|
||||
import com.bintianqi.owndroid.MyViewModel
|
||||
import com.bintianqi.owndroid.NotificationUtils
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.StopLockTaskModeReceiver
|
||||
import com.bintianqi.owndroid.exportFile
|
||||
import com.bintianqi.owndroid.exportFilePath
|
||||
import com.bintianqi.owndroid.fileUriFlow
|
||||
@@ -118,13 +116,10 @@ import com.bintianqi.owndroid.formatFileSize
|
||||
import com.bintianqi.owndroid.getFile
|
||||
import com.bintianqi.owndroid.humanReadableDate
|
||||
import com.bintianqi.owndroid.isExportingSecurityOrNetworkLogs
|
||||
import com.bintianqi.owndroid.prepareForNotification
|
||||
import com.bintianqi.owndroid.selectedPackage
|
||||
import com.bintianqi.owndroid.toggle
|
||||
import com.bintianqi.owndroid.ui.CheckBoxItem
|
||||
import com.bintianqi.owndroid.ui.FunctionItem
|
||||
import com.bintianqi.owndroid.ui.InfoCard
|
||||
import com.bintianqi.owndroid.ui.Information
|
||||
import com.bintianqi.owndroid.ui.ListItem
|
||||
import com.bintianqi.owndroid.ui.MyScaffold
|
||||
import com.bintianqi.owndroid.ui.RadioButtonItem
|
||||
@@ -522,9 +517,7 @@ fun ChangeTimeZone(navCtrl: NavHostController) {
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Information {
|
||||
Text(stringResource(R.string.disable_auto_time_zone_before_set))
|
||||
}
|
||||
InfoCard(R.string.disable_auto_time_zone_before_set)
|
||||
}
|
||||
if(dialog) AlertDialog(
|
||||
text = {
|
||||
@@ -700,12 +693,11 @@ fun NearbyStreamingPolicy(navCtrl: NavHostController) {
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Composable
|
||||
fun LockTaskMode(navCtrl: NavHostController) {
|
||||
fun LockTaskMode(navCtrl: NavHostController, vm: MyViewModel) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val focusMgr = LocalFocusManager.current
|
||||
val coroutine = rememberCoroutineScope()
|
||||
var appSelectorRequest by rememberSaveable { mutableIntStateOf(0) }
|
||||
MyScaffold(R.string.lock_task_mode, 8.dp, navCtrl, false) {
|
||||
val lockTaskFeatures = remember { mutableStateListOf<Int>() }
|
||||
@@ -784,11 +776,11 @@ fun LockTaskMode(navCtrl: NavHostController) {
|
||||
lockTaskFeatures.forEach { result += it }
|
||||
}
|
||||
try {
|
||||
dpm.setLockTaskFeatures(receiver,result)
|
||||
dpm.setLockTaskFeatures(receiver, result)
|
||||
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
AlertDialog.Builder(context)
|
||||
.setTitle("Error")
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(e.message)
|
||||
.setPositiveButton(R.string.confirm) { dialog, _ -> dialog.dismiss() }
|
||||
.show()
|
||||
@@ -863,11 +855,11 @@ fun LockTaskMode(navCtrl: NavHostController) {
|
||||
var startLockTaskApp by rememberSaveable { mutableStateOf("") }
|
||||
var startLockTaskActivity by rememberSaveable { mutableStateOf("") }
|
||||
var specifyActivity by rememberSaveable { mutableStateOf(false) }
|
||||
val updatePackage by selectedPackage.collectAsState()
|
||||
val updatePackage by vm.selectedPackage.collectAsStateWithLifecycle()
|
||||
LaunchedEffect(updatePackage) {
|
||||
if(updatePackage != "") {
|
||||
if(appSelectorRequest == 1) inputLockTaskPkg = updatePackage else startLockTaskApp = updatePackage
|
||||
selectedPackage.value = ""
|
||||
vm.selectedPackage.value = ""
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
@@ -906,7 +898,8 @@ fun LockTaskMode(navCtrl: NavHostController) {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
if(!dpm.getLockTaskPackages(receiver).contains(startLockTaskApp)) {
|
||||
if(!NotificationUtils.checkPermission(context)) return@Button
|
||||
if(!dpm.isLockTaskPermitted(startLockTaskApp)) {
|
||||
Toast.makeText(context, R.string.app_not_allowed, Toast.LENGTH_SHORT).show()
|
||||
return@Button
|
||||
}
|
||||
@@ -915,13 +908,7 @@ fun LockTaskMode(navCtrl: NavHostController) {
|
||||
val launchIntent = if(specifyActivity) Intent().setComponent(ComponentName(startLockTaskApp, startLockTaskActivity))
|
||||
else packageManager.getLaunchIntentForPackage(startLockTaskApp)
|
||||
if (launchIntent != null) {
|
||||
coroutine.launch {
|
||||
prepareForNotification(context) {
|
||||
sendStopLockTaskNotification(context)
|
||||
context.startActivity(launchIntent, options.toBundle())
|
||||
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
context.startActivity(launchIntent, options.toBundle())
|
||||
} else {
|
||||
Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
@@ -1497,23 +1484,3 @@ fun InstallSystemUpdate(navCtrl: NavHostController) {
|
||||
InfoCard(R.string.auto_reboot_after_install_succeed)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private fun sendStopLockTaskNotification(context: Context) {
|
||||
val nm = context.getSystemService(Context.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())
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
import androidx.navigation.NavHostController
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.writeClipBoard
|
||||
@@ -79,21 +78,6 @@ fun NavIcon(operation: () -> Unit) {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Information(content: @Composable ()->Unit) {
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 5.dp, top = 20.dp)) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.info_fill0),
|
||||
contentDescription = "info",
|
||||
tint = colorScheme.onBackground.copy(alpha = 0.8F)
|
||||
)
|
||||
Spacer(Modifier.padding(vertical = 1.dp))
|
||||
Column(modifier = Modifier.padding(start = 2.dp)) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RadioButtonItem(
|
||||
@StringRes text: Int,
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
<string name="alias">Alias</string>
|
||||
<string name="unknown_error">Unknown error</string>
|
||||
<string name="permission_denied">Permission denied</string>
|
||||
<string name="error">Error</string>
|
||||
|
||||
|
||||
<!--Разрешения-->
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
<string name="alias">Alias</string>
|
||||
<string name="unknown_error">Unknown error</string>
|
||||
<string name="permission_denied">Permission denied</string>
|
||||
<string name="error">Error</string>
|
||||
|
||||
<!--Permissions-->
|
||||
<string name="click_to_activate">Etkinleştirmek İçin Tıklayın</string>
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
<string name="alias">别名</string>
|
||||
<string name="unknown_error">未知错误</string>
|
||||
<string name="permission_denied">无权限</string>
|
||||
<string name="error">错误</string>
|
||||
|
||||
<!--Permissions-->
|
||||
<string name="click_to_activate">点击以激活</string>
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
<string name="unknown_error">Unknown error</string>
|
||||
<string name="permission_denied">Permission denied</string>
|
||||
<string name="api" translatable="false">API</string>
|
||||
<string name="error">Error</string>
|
||||
|
||||
<!--Permissions-->
|
||||
<string name="click_to_activate">Click to activate</string>
|
||||
|
||||
Reference in New Issue
Block a user