Skip to content

Commit

Permalink
Optimize start/stop lock task mode flow
Browse files Browse the repository at this point in the history
Optimize Package selector
  • Loading branch information
BinTianqi committed Dec 21, 2024
1 parent 873896e commit 84c1dff
Show file tree
Hide file tree
Showing 16 changed files with 216 additions and 285 deletions.
4 changes: 0 additions & 4 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
10 changes: 4 additions & 6 deletions app/src/main/java/com/bintianqi/owndroid/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) }
Expand All @@ -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) }
Expand All @@ -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") {
Expand Down Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 29 additions & 0 deletions app/src/main/java/com/bintianqi/owndroid/NotificationUtils.kt
Original file line number Diff line number Diff line change
@@ -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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
)
Expand Down Expand Up @@ -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)
}
}
}
Expand All @@ -201,21 +196,21 @@ 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,
modifier = Modifier
.fillMaxWidth()
.clickable{
focusMgr.clearFocus()
selectedPackage.value = pkg.pkgName
vm.selectedPackage.value = pkg.pkgName
navCtrl.navigateUp()
}
.padding(horizontal = 8.dp, vertical = 10.dp)
Expand Down
50 changes: 34 additions & 16 deletions app/src/main/java/com/bintianqi/owndroid/Receiver.kt
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
}
}
20 changes: 0 additions & 20 deletions app/src/main/java/com/bintianqi/owndroid/Utils.kt
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
Loading

0 comments on commit 84c1dff

Please sign in to comment.