mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 11:05:59 +00:00
Integrate Dhizuku server
This commit is contained in:
@@ -92,6 +92,7 @@ dependencies {
|
|||||||
implementation(libs.shizuku.provider)
|
implementation(libs.shizuku.provider)
|
||||||
implementation(libs.shizuku.api)
|
implementation(libs.shizuku.api)
|
||||||
implementation(libs.dhizuku.api)
|
implementation(libs.dhizuku.api)
|
||||||
|
implementation(libs.dhizuku.server.api)
|
||||||
implementation(libs.androidx.fragment)
|
implementation(libs.androidx.fragment)
|
||||||
implementation(libs.hiddenApiBypass)
|
implementation(libs.hiddenApiBypass)
|
||||||
implementation(libs.libsu)
|
implementation(libs.libsu)
|
||||||
|
|||||||
4
app/proguard-rules.pro
vendored
4
app/proguard-rules.pro
vendored
@@ -20,3 +20,7 @@
|
|||||||
# If you keep the line number information, uncomment this to
|
# If you keep the line number information, uncomment this to
|
||||||
# hide the original source file name.
|
# hide the original source file name.
|
||||||
# -renamesourcefileattribute SourceFile
|
# -renamesourcefileattribute SourceFile
|
||||||
|
|
||||||
|
-dontwarn android.app.ActivityThread
|
||||||
|
-dontwarn android.app.ContextImpl
|
||||||
|
-dontwarn android.app.LoadedApk
|
||||||
|
|||||||
@@ -68,6 +68,17 @@
|
|||||||
android:permission="com.bintianqi.owndroid.MyPermission"
|
android:permission="com.bintianqi.owndroid.MyPermission"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@android:style/Theme.NoDisplay" />
|
android:theme="@android:style/Theme.NoDisplay" />
|
||||||
|
<activity
|
||||||
|
android:name=".DhizukuActivity"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:exported="true"
|
||||||
|
android:launchMode="singleInstance"
|
||||||
|
android:theme="@style/Theme.Transparent">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.bintianqi.owndroid.action.REQUEST_DHIZUKU_PERMISSION" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".Receiver"
|
android:name=".Receiver"
|
||||||
android:description="@string/app_name"
|
android:description="@string/app_name"
|
||||||
@@ -97,5 +108,12 @@
|
|||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||||
|
<provider
|
||||||
|
android:name=".MyDhizukuProvider"
|
||||||
|
android:authorities="com.bintianqi.owndroid.dhizuku_server.provider"
|
||||||
|
android:directBootAware="true"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true">
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
147
app/src/main/java/com/bintianqi/owndroid/DhizukuServer.kt
Normal file
147
app/src/main/java/com/bintianqi/owndroid/DhizukuServer.kt
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package com.bintianqi.owndroid
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
||||||
|
import com.rosan.dhizuku.aidl.IDhizukuClient
|
||||||
|
import com.rosan.dhizuku.aidl.IDhizukuRequestPermissionListener
|
||||||
|
import com.rosan.dhizuku.server_api.DhizukuProvider
|
||||||
|
import com.rosan.dhizuku.server_api.DhizukuService
|
||||||
|
import com.rosan.dhizuku.shared.DhizukuVariables
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
private const val TAG = "DhizukuServer"
|
||||||
|
|
||||||
|
const val DHIZUKU_CLIENTS_FILE = "dhizuku_clients.json"
|
||||||
|
|
||||||
|
class MyDhizukuProvider(): DhizukuProvider() {
|
||||||
|
override fun onCreateService(client: IDhizukuClient): DhizukuService? {
|
||||||
|
Log.d(TAG, "Creating MyDhizukuService")
|
||||||
|
return if (SharedPrefs(context!!).dhizukuServer) MyDhizukuService(context!!, MyAdminComponent, client) else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyDhizukuService(context: Context, admin: ComponentName, client: IDhizukuClient) :
|
||||||
|
DhizukuService(context, admin, client) {
|
||||||
|
override fun checkCallingPermission(func: String?, callingUid: Int, callingPid: Int): Boolean {
|
||||||
|
if (!SharedPrefs(mContext).dhizukuServer) return false
|
||||||
|
val pm = mContext.packageManager
|
||||||
|
val packageInfo = pm.getPackageInfo(
|
||||||
|
pm.getNameForUid(callingUid) ?: return false,
|
||||||
|
if (Build.VERSION.SDK_INT >= 28) PackageManager.GET_SIGNING_CERTIFICATES else PackageManager.GET_SIGNATURES
|
||||||
|
)
|
||||||
|
val file = mContext.filesDir.resolve(DHIZUKU_CLIENTS_FILE)
|
||||||
|
val clients = Json.decodeFromString<List<DhizukuClientInfo>>(file.readText())
|
||||||
|
val signature = getPackageSignature(packageInfo)
|
||||||
|
val hasPermission = DhizukuClientInfo(callingUid, signature, true) in clients
|
||||||
|
Log.d(TAG, "UID $callingUid, PID $callingPid, has permission: $hasPermission")
|
||||||
|
return hasPermission
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getVersionName() = "1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
class DhizukuActivity : ComponentActivity() {
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
if (!SharedPrefs(this).dhizukuServer) {
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val bundle = intent.extras ?: return
|
||||||
|
val uid = bundle.getInt(DhizukuVariables.PARAM_CLIENT_UID, -1)
|
||||||
|
if (uid == -1) return
|
||||||
|
val binder = bundle.getBinder(DhizukuVariables.PARAM_CLIENT_REQUEST_PERMISSION_BINDER) ?: return
|
||||||
|
val listener = IDhizukuRequestPermissionListener.Stub.asInterface(binder)
|
||||||
|
val packageName = packageManager.getPackagesForUid(uid)?.first() ?: return
|
||||||
|
val packageInfo = packageManager.getPackageInfo(
|
||||||
|
packageName,
|
||||||
|
if (Build.VERSION.SDK_INT >= 28) PackageManager.GET_SIGNING_CERTIFICATES else PackageManager.GET_SIGNATURES
|
||||||
|
)
|
||||||
|
val appInfo = packageManager.getApplicationInfo(packageName, 0)
|
||||||
|
val icon = appInfo.loadIcon(packageManager)
|
||||||
|
val label = appInfo.loadLabel(packageManager).toString()
|
||||||
|
fun close(grantPermission: Boolean) {
|
||||||
|
val file = filesDir.resolve(DHIZUKU_CLIENTS_FILE)
|
||||||
|
val clients = Json.decodeFromString<MutableList<DhizukuClientInfo>>(file.readText())
|
||||||
|
val index = clients.indexOfFirst { it.uid == uid }
|
||||||
|
val clientInfo = DhizukuClientInfo(uid, getPackageSignature(packageInfo), grantPermission)
|
||||||
|
if (index == -1) clients += clientInfo
|
||||||
|
else clients[index] = clientInfo
|
||||||
|
file.writeText(Json.encodeToString(clients))
|
||||||
|
finish()
|
||||||
|
listener.onRequestPermission(
|
||||||
|
if (grantPermission) PackageManager.PERMISSION_GRANTED else PackageManager.PERMISSION_DENIED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
setContent {
|
||||||
|
AlertDialog(
|
||||||
|
icon = {
|
||||||
|
Image(rememberDrawablePainter(icon), null, Modifier.size(35.dp))
|
||||||
|
},
|
||||||
|
title = {
|
||||||
|
Text(stringResource(R.string.request_permission))
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text("$label\n($packageName)")
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
var time by remember { mutableIntStateOf(3) }
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
(1..3).forEach {
|
||||||
|
delay(1000)
|
||||||
|
time -= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextButton({
|
||||||
|
close(true)
|
||||||
|
}, enabled = time == 0) {
|
||||||
|
val append = if (time > 0) " (${time}s)" else ""
|
||||||
|
Text(stringResource(R.string.allow) + append)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton({
|
||||||
|
close(false)
|
||||||
|
}) {
|
||||||
|
Text(stringResource(R.string.reject))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDismissRequest = {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class DhizukuClientInfo(
|
||||||
|
val uid: Int,
|
||||||
|
val signature: String?,
|
||||||
|
val allow: Boolean
|
||||||
|
)
|
||||||
@@ -107,6 +107,8 @@ import com.bintianqi.owndroid.dpm.DeleteWorkProfile
|
|||||||
import com.bintianqi.owndroid.dpm.DeleteWorkProfileScreen
|
import com.bintianqi.owndroid.dpm.DeleteWorkProfileScreen
|
||||||
import com.bintianqi.owndroid.dpm.DeviceInfo
|
import com.bintianqi.owndroid.dpm.DeviceInfo
|
||||||
import com.bintianqi.owndroid.dpm.DeviceInfoScreen
|
import com.bintianqi.owndroid.dpm.DeviceInfoScreen
|
||||||
|
import com.bintianqi.owndroid.dpm.DhizukuServerSettings
|
||||||
|
import com.bintianqi.owndroid.dpm.DhizukuServerSettingsScreen
|
||||||
import com.bintianqi.owndroid.dpm.DisableAccountManagement
|
import com.bintianqi.owndroid.dpm.DisableAccountManagement
|
||||||
import com.bintianqi.owndroid.dpm.DisableAccountManagementScreen
|
import com.bintianqi.owndroid.dpm.DisableAccountManagementScreen
|
||||||
import com.bintianqi.owndroid.dpm.DisableMeteredData
|
import com.bintianqi.owndroid.dpm.DisableMeteredData
|
||||||
@@ -324,6 +326,7 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
|
|||||||
}
|
}
|
||||||
}, ::navigate)
|
}, ::navigate)
|
||||||
}
|
}
|
||||||
|
composable<DhizukuServerSettings> { DhizukuServerSettingsScreen(::navigateUp) }
|
||||||
|
|
||||||
composable<DelegatedAdmins> { DelegatedAdminsScreen(::navigateUp, ::navigate) }
|
composable<DelegatedAdmins> { DelegatedAdminsScreen(::navigateUp, ::navigate) }
|
||||||
composable<AddDelegatedAdmin>{ AddDelegatedAdminScreen(it.toRoute(), ::navigateUp) }
|
composable<AddDelegatedAdmin>{ AddDelegatedAdminScreen(it.toRoute(), ::navigateUp) }
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class Receiver : DeviceAdminReceiver() {
|
|||||||
super.onSecurityLogsAvailable(context, intent)
|
super.onSecurityLogsAvailable(context, intent)
|
||||||
if(VERSION.SDK_INT >= 24) {
|
if(VERSION.SDK_INT >= 24) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
val events = getManager(context).retrieveSecurityLogs(ComponentName(context, this@Receiver::class.java)) ?: return@launch
|
val events = getManager(context).retrieveSecurityLogs(MyAdminComponent) ?: return@launch
|
||||||
val file = context.filesDir.resolve("SecurityLogs.json")
|
val file = context.filesDir.resolve("SecurityLogs.json")
|
||||||
val fileExists = file.exists()
|
val fileExists = file.exists()
|
||||||
file.outputStream().use {
|
file.outputStream().use {
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ class SharedPrefs(context: Context) {
|
|||||||
var biometricsUnlock by BooleanSharedPref("lock.biometrics")
|
var biometricsUnlock by BooleanSharedPref("lock.biometrics")
|
||||||
var lockWhenLeaving by BooleanSharedPref("lock.onleave")
|
var lockWhenLeaving by BooleanSharedPref("lock.onleave")
|
||||||
var applicationsListView by BooleanSharedPref("applications.list_view", true)
|
var applicationsListView by BooleanSharedPref("applications.list_view", true)
|
||||||
var shortcuts by BooleanSharedPref("shortcuts", false)
|
var shortcuts by BooleanSharedPref("shortcuts")
|
||||||
|
var dhizukuServer by BooleanSharedPref("dhizuku_server")
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BooleanSharedPref(val key: String, val defValue: Boolean = false): ReadWriteProperty<SharedPrefs, Boolean> {
|
private class BooleanSharedPref(val key: String, val defValue: Boolean = false): ReadWriteProperty<SharedPrefs, Boolean> {
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package com.bintianqi.owndroid
|
|||||||
|
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageInfo
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@@ -131,3 +133,13 @@ fun String.hash(): String {
|
|||||||
val md = MessageDigest.getInstance("SHA-256")
|
val md = MessageDigest.getInstance("SHA-256")
|
||||||
return md.digest(this.encodeToByteArray()).toHexString()
|
return md.digest(this.encodeToByteArray()).toHexString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val MyAdminComponent = ComponentName.unflattenFromString("com.bintianqi.owndroid/.Receiver")!!
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
fun getPackageSignature(info: PackageInfo): String? {
|
||||||
|
val signatures = if (Build.VERSION.SDK_INT >= 28) info.signingInfo?.apkContentsSigners else info.signatures
|
||||||
|
return signatures?.firstOrNull()?.toByteArray()
|
||||||
|
?.let { MessageDigest.getInstance("SHA-256").digest(it) }?.toHexString()
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ import androidx.annotation.RequiresApi
|
|||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
import com.bintianqi.owndroid.MyAdminComponent
|
||||||
import com.bintianqi.owndroid.R
|
import com.bintianqi.owndroid.R
|
||||||
import com.bintianqi.owndroid.Receiver
|
import com.bintianqi.owndroid.Receiver
|
||||||
import com.bintianqi.owndroid.SharedPrefs
|
import com.bintianqi.owndroid.SharedPrefs
|
||||||
import com.bintianqi.owndroid.ShortcutsReceiverActivity
|
import com.bintianqi.owndroid.ShortcutsReceiverActivity
|
||||||
import com.bintianqi.owndroid.backToHomeStateFlow
|
|
||||||
import com.bintianqi.owndroid.createShortcuts
|
import com.bintianqi.owndroid.createShortcuts
|
||||||
import com.bintianqi.owndroid.myPrivilege
|
import com.bintianqi.owndroid.myPrivilege
|
||||||
import com.rosan.dhizuku.api.Dhizuku
|
import com.rosan.dhizuku.api.Dhizuku
|
||||||
@@ -130,7 +130,7 @@ fun Context.getReceiver(): ComponentName {
|
|||||||
return if(SharedPrefs(this).dhizuku) {
|
return if(SharedPrefs(this).dhizuku) {
|
||||||
Dhizuku.getOwnerComponent()
|
Dhizuku.getOwnerComponent()
|
||||||
} else {
|
} else {
|
||||||
ComponentName(this, Receiver::class.java)
|
MyAdminComponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
|||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
@@ -31,7 +32,10 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||||
@@ -57,6 +61,7 @@ import androidx.compose.material3.MaterialTheme.colorScheme
|
|||||||
import androidx.compose.material3.MaterialTheme.typography
|
import androidx.compose.material3.MaterialTheme.typography
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
@@ -84,23 +89,28 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.bintianqi.owndroid.ChoosePackageContract
|
import com.bintianqi.owndroid.ChoosePackageContract
|
||||||
|
import com.bintianqi.owndroid.DHIZUKU_CLIENTS_FILE
|
||||||
|
import com.bintianqi.owndroid.DhizukuClientInfo
|
||||||
import com.bintianqi.owndroid.HorizontalPadding
|
import com.bintianqi.owndroid.HorizontalPadding
|
||||||
import com.bintianqi.owndroid.IUserService
|
import com.bintianqi.owndroid.IUserService
|
||||||
|
import com.bintianqi.owndroid.MyAdminComponent
|
||||||
import com.bintianqi.owndroid.R
|
import com.bintianqi.owndroid.R
|
||||||
import com.bintianqi.owndroid.Receiver
|
|
||||||
import com.bintianqi.owndroid.Settings
|
import com.bintianqi.owndroid.Settings
|
||||||
import com.bintianqi.owndroid.SharedPrefs
|
import com.bintianqi.owndroid.SharedPrefs
|
||||||
import com.bintianqi.owndroid.myPrivilege
|
import com.bintianqi.owndroid.myPrivilege
|
||||||
import com.bintianqi.owndroid.showOperationResultToast
|
import com.bintianqi.owndroid.showOperationResultToast
|
||||||
import com.bintianqi.owndroid.ui.CircularProgressDialog
|
import com.bintianqi.owndroid.ui.CircularProgressDialog
|
||||||
import com.bintianqi.owndroid.ui.InfoItem
|
import com.bintianqi.owndroid.ui.InfoItem
|
||||||
|
import com.bintianqi.owndroid.ui.MyLazyScaffold
|
||||||
import com.bintianqi.owndroid.ui.MyScaffold
|
import com.bintianqi.owndroid.ui.MyScaffold
|
||||||
import com.bintianqi.owndroid.ui.MySmallTitleScaffold
|
import com.bintianqi.owndroid.ui.MySmallTitleScaffold
|
||||||
import com.bintianqi.owndroid.ui.NavIcon
|
import com.bintianqi.owndroid.ui.NavIcon
|
||||||
import com.bintianqi.owndroid.ui.Notes
|
import com.bintianqi.owndroid.ui.Notes
|
||||||
|
import com.bintianqi.owndroid.ui.SwitchItem
|
||||||
import com.bintianqi.owndroid.updatePrivilege
|
import com.bintianqi.owndroid.updatePrivilege
|
||||||
import com.bintianqi.owndroid.useShizuku
|
import com.bintianqi.owndroid.useShizuku
|
||||||
import com.bintianqi.owndroid.yesOrNo
|
import com.bintianqi.owndroid.yesOrNo
|
||||||
|
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
||||||
import com.rosan.dhizuku.api.Dhizuku
|
import com.rosan.dhizuku.api.Dhizuku
|
||||||
import com.rosan.dhizuku.api.DhizukuRequestPermissionListener
|
import com.rosan.dhizuku.api.DhizukuRequestPermissionListener
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
@@ -108,6 +118,8 @@ import com.topjohnwu.superuser.ipc.RootService
|
|||||||
import dalvik.system.DexClassLoader
|
import dalvik.system.DexClassLoader
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import java.lang.invoke.MethodHandles
|
import java.lang.invoke.MethodHandles
|
||||||
import java.lang.reflect.Proxy
|
import java.lang.reflect.Proxy
|
||||||
|
|
||||||
@@ -258,6 +270,14 @@ fun WorkModesScreen(
|
|||||||
tint = if(privilege.device) colorScheme.primary else colorScheme.onBackground
|
tint = if(privilege.device) colorScheme.primary else colorScheme.onBackground
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if ((privilege.device || privilege.profile) && !privilege.dhizuku) Row(
|
||||||
|
Modifier.padding(top = 20.dp).fillMaxWidth().clickable { onNavigate(DhizukuServerSettings) },
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(painterResource(R.drawable.dhizuku_icon), null, Modifier.padding(8.dp).size(28.dp))
|
||||||
|
Text(stringResource(R.string.dhizuku_server), style = typography.titleLarge)
|
||||||
|
}
|
||||||
|
|
||||||
Column(Modifier.padding(HorizontalPadding, 20.dp)) {
|
Column(Modifier.padding(HorizontalPadding, 20.dp)) {
|
||||||
Row(Modifier.padding(bottom = 4.dp), verticalAlignment = Alignment.CenterVertically) {
|
Row(Modifier.padding(bottom = 4.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||||
Icon(Icons.Outlined.Warning, null, Modifier.padding(end = 4.dp), colorScheme.error)
|
Icon(Icons.Outlined.Warning, null, Modifier.padding(end = 4.dp), colorScheme.error)
|
||||||
@@ -338,7 +358,7 @@ fun WorkModesScreen(
|
|||||||
if(privilege.device) {
|
if(privilege.device) {
|
||||||
dpm.clearDeviceOwnerApp(context.packageName)
|
dpm.clearDeviceOwnerApp(context.packageName)
|
||||||
} else if(VERSION.SDK_INT >= 24) {
|
} else if(VERSION.SDK_INT >= 24) {
|
||||||
dpm.clearProfileOwner(ComponentName(context, Receiver::class.java))
|
dpm.clearProfileOwner(MyAdminComponent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dialog = 0
|
dialog = 0
|
||||||
@@ -424,10 +444,7 @@ fun activateUsingDhizuku(context: Context, callback: (Boolean, Boolean, String?)
|
|||||||
if(dpm == null) {
|
if(dpm == null) {
|
||||||
context.showOperationResultToast(false)
|
context.showOperationResultToast(false)
|
||||||
} else {
|
} else {
|
||||||
dpm.transferOwnership(
|
dpm.transferOwnership(Dhizuku.getOwnerComponent(), MyAdminComponent, PersistableBundle())
|
||||||
Dhizuku.getOwnerComponent(),
|
|
||||||
ComponentName(context, Receiver::class.java), PersistableBundle()
|
|
||||||
)
|
|
||||||
callback(true, true, null)
|
callback(true, true, null)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -542,6 +559,65 @@ fun activateDhizukuMode(context: Context, callback: (Boolean, Boolean, String?)
|
|||||||
|
|
||||||
const val ACTIVATE_DEVICE_OWNER_COMMAND = "dpm set-device-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver"
|
const val ACTIVATE_DEVICE_OWNER_COMMAND = "dpm set-device-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver"
|
||||||
|
|
||||||
|
@Serializable object DhizukuServerSettings
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DhizukuServerSettingsScreen(onNavigateUp: () -> Unit) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val pm = context.packageManager
|
||||||
|
val sp = SharedPrefs(context)
|
||||||
|
val file = context.filesDir.resolve(DHIZUKU_CLIENTS_FILE)
|
||||||
|
var enabled by remember { mutableStateOf(sp.dhizukuServer) }
|
||||||
|
val clients = remember { mutableStateListOf<DhizukuClientInfo>() }
|
||||||
|
fun changeEnableState(status: Boolean) {
|
||||||
|
enabled = status
|
||||||
|
sp.dhizukuServer = status
|
||||||
|
}
|
||||||
|
fun writeList() {
|
||||||
|
file.writeText(Json.encodeToString(clients))
|
||||||
|
}
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
if (!file.exists()) file.writeText("[]")
|
||||||
|
}
|
||||||
|
LaunchedEffect(enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
clients.clear()
|
||||||
|
clients.addAll(Json.decodeFromString<List<DhizukuClientInfo>>(file.readText()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MyLazyScaffold(R.string.dhizuku_server, onNavigateUp) {
|
||||||
|
item {
|
||||||
|
SwitchItem(R.string.enable, getState = { sp.dhizukuServer }, onCheckedChange = ::changeEnableState)
|
||||||
|
Spacer(Modifier.padding(vertical = 8.dp))
|
||||||
|
}
|
||||||
|
if (enabled) itemsIndexed(clients) { index, client ->
|
||||||
|
val name = pm.getNameForUid(client.uid)
|
||||||
|
if (name == null) {
|
||||||
|
clients.dropWhile { it.uid == client.uid }
|
||||||
|
writeList()
|
||||||
|
} else {
|
||||||
|
val info = pm.getApplicationInfo(name, 0)
|
||||||
|
Row(
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth().padding(8.dp)
|
||||||
|
.background(colorScheme.surfaceVariant, RoundedCornerShape(8.dp))
|
||||||
|
.padding(8.dp),
|
||||||
|
Arrangement.SpaceBetween, Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Image(
|
||||||
|
rememberDrawablePainter(info.loadIcon(pm)), null,
|
||||||
|
Modifier.padding(end = 12.dp).size(50.dp)
|
||||||
|
)
|
||||||
|
Text(info.loadLabel(pm).toString(), style = typography.titleLarge)
|
||||||
|
}
|
||||||
|
Switch(client.allow, { clients[index] = client.copy(allow = it) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Serializable object LockScreenInfo
|
@Serializable object LockScreenInfo
|
||||||
|
|
||||||
@RequiresApi(24)
|
@RequiresApi(24)
|
||||||
|
|||||||
13
app/src/main/res/drawable/dhizuku_icon.xml
Normal file
13
app/src/main/res/drawable/dhizuku_icon.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:width="512dp"
|
||||||
|
android:height="512dp"
|
||||||
|
android:viewportWidth="512"
|
||||||
|
android:viewportHeight="512"
|
||||||
|
tools:ignore="VectorRaster,VectorPath">
|
||||||
|
<path
|
||||||
|
android:pathData="M169.19,346.11C161.37,346.07 159.99,344.74 159.91,337.43C159.86,332.6 159.82,327.76 159.92,322.93C160.03,317.38 162.37,315.03 167.89,314.94C173.56,314.84 179.23,314.79 184.88,314.97C188.39,315.09 189.99,314.12 189.97,310.22C189.85,279.06 189.81,247.9 190.01,216.74C190.04,212.88 187.79,212.53 185.32,211.61C151.63,199.06 142.08,155.85 167.82,131.55C182.14,118.04 199.25,114.18 217.77,120.57C235.72,126.77 246.5,139.95 249.78,158.77C253.66,181.07 240.75,203.1 218.95,211.11C214.46,212.76 212.81,214.83 213.07,219.6C213.5,227.25 213.27,234.93 213.15,242.59C213.09,245.99 214.34,247.35 217.84,247.3C227.83,247.14 237.83,247.33 247.83,247.15C249.44,247.12 251.44,246.36 252.56,245.24C281.47,216.41 310.27,187.48 339.15,158.63C341.21,156.56 341.48,154.77 341.33,151.75C340.74,139.79 340.5,127.75 341.16,115.8C341.59,107.98 350.04,101.51 358.52,101.3C367.18,101.08 375.85,101.06 384.51,101.29C395.41,101.59 403.05,109.67 403.1,120.62C403.14,128.95 403.17,137.28 403.09,145.61C403,156.59 395.44,164.22 384.54,164.07C373.25,163.92 361.97,163.38 350.68,163.14C349.71,163.11 348.51,163.87 347.76,164.61C320.45,191.46 293.18,218.36 265.91,245.26C266.2,245.79 266.49,246.33 266.79,246.86C268.13,246.99 269.47,247.25 270.81,247.25C295.14,247.27 319.47,247.19 343.8,247.33C347.67,247.36 348.96,246.32 348.93,242.29C348.84,229.41 356.49,222.1 369.5,222.09C377.34,222.09 385.17,222.06 393,222.1C403.99,222.16 411.89,230.06 411.93,241.01C411.96,249.18 411.95,257.34 411.93,265.51C411.9,275.98 405.11,284.01 394.76,284.57C385.3,285.08 375.75,284.96 366.3,284.3C355.87,283.58 348.97,275.41 348.83,264.85C348.81,262.88 348.83,260.91 348.83,258.52C320.72,258.52 293.03,258.52 264.72,258.52C265.54,259.71 266.01,260.69 266.73,261.41C293.62,287.99 320.53,314.56 347.49,341.07C348.41,341.98 349.98,342.75 351.23,342.73C363.5,342.5 375.77,341.69 388.03,341.87C395.97,342 402.86,349.81 403.04,357.93C403.26,367.76 403.25,377.6 403.05,387.42C402.87,396.32 395.21,403.9 386.31,404.05C376.65,404.22 366.98,404.23 357.32,404.05C348.72,403.89 340.82,396.19 340.86,387.71C340.92,375.93 341.54,364.15 341.73,352.36C341.75,351.13 340.8,349.6 339.85,348.65C310.24,319.13 280.6,289.63 250.84,260.26C249.52,258.95 247.08,258.24 245.14,258.2C236.31,257.98 227.47,258.36 218.65,258C214.08,257.81 213.1,259.44 213.12,263.71C213.26,303.53 213.27,343.36 213.04,383.18C213.02,386.72 211.8,390.87 209.69,393.63C206.78,397.44 202.06,398.12 197.39,396.23C192.8,394.37 189.92,390.96 190,385.99C190.07,382.15 188.72,381.1 185.08,381.24C178.93,381.49 172.75,381.23 166.59,381.31C161.99,381.37 159.8,379.21 159.9,374.64C159.93,372.98 159.81,371.3 159.92,369.65C160.21,365.26 163.23,362.35 167.69,362.28C173.82,362.2 179.96,362.26 186.44,362.26C186.44,356.74 186.44,351.69 186.44,346.11C180.58,346.11 175.12,346.11 169.19,346.11M225.82,157.02C225.25,155.82 224.75,154.58 224.09,153.43C218.37,143.47 206.71,138.58 195.41,141.36C184.77,143.98 176.26,154.09 176.01,164.59C175.75,175.62 180.5,183.97 190.38,188.78C200.04,193.48 209.59,192.47 217.94,185.64C226.85,178.35 229.1,168.76 225.82,157.02M351.09,144.13C351.42,151.11 353.26,153.78 358.41,153.87C367.22,154.02 376.04,153.98 384.85,153.86C389.4,153.8 392.18,150.94 392.36,146.71C392.73,137.6 392.72,128.45 392.42,119.32C392.25,114.31 389.33,111.97 384.24,111.91C375.92,111.83 367.61,111.79 359.29,111.92C353.69,112.01 351.15,114.71 351.12,120.25C351.07,127.9 351.1,135.55 351.09,144.13M376.45,393.84C378.78,393.84 381.11,393.86 383.44,393.83C390.03,393.75 392.16,391.86 392.28,385.26C392.44,376.61 392.37,367.95 392.21,359.31C392.12,354.45 389.59,352.02 384.7,351.96C376.55,351.86 368.39,351.9 360.24,351.93C353.9,351.95 351.32,354.24 351.19,360.47C351.01,368.79 351.03,377.11 351.17,385.43C351.26,391.07 353.88,393.65 359.49,393.8C364.81,393.94 370.14,393.84 376.45,393.84M374.55,274.12C380.88,274.12 387.22,274.21 393.54,274.1C398.38,274.02 401.11,271.51 401.2,266.77C401.36,257.95 401.34,249.11 401.18,240.29C401.09,235.46 398.41,232.84 393.75,232.8C384.93,232.71 376.1,232.73 367.27,232.79C362.93,232.82 360.24,235.05 360.16,239.46C360,248.45 359.98,257.45 360.16,266.45C360.27,271.4 363.19,273.99 368.08,274.11C369.91,274.16 371.75,274.12 374.55,274.12z"
|
||||||
|
android:fillColor="#4DCBE4"
|
||||||
|
android:strokeColor="#00000000" />
|
||||||
|
</vector>
|
||||||
@@ -106,6 +106,11 @@
|
|||||||
<string name="transfer">转移</string>
|
<string name="transfer">转移</string>
|
||||||
<string name="transfer_ownership_warning">%1$s 特权将被转移至 %2$s</string>
|
<string name="transfer_ownership_warning">%1$s 特权将被转移至 %2$s</string>
|
||||||
|
|
||||||
|
<string name="dhizuku_server">Dhizuku服务器</string>
|
||||||
|
<string name="request_permission">请求权限</string>
|
||||||
|
<string name="allow">允许</string>
|
||||||
|
<string name="reject">拒绝</string>
|
||||||
|
|
||||||
<!--Receiver-->
|
<!--Receiver-->
|
||||||
<string name="create_work_profile_success">创建工作资料成功</string>
|
<string name="create_work_profile_success">创建工作资料成功</string>
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,11 @@
|
|||||||
<string name="transfer">Transfer</string>
|
<string name="transfer">Transfer</string>
|
||||||
<string name="transfer_ownership_warning">%1$s privilege will be transferred to %2$s</string>
|
<string name="transfer_ownership_warning">%1$s privilege will be transferred to %2$s</string>
|
||||||
|
|
||||||
|
<string name="dhizuku_server">Dhizuku server</string>
|
||||||
|
<string name="request_permission">Request permission</string>
|
||||||
|
<string name="allow">Allow</string>
|
||||||
|
<string name="reject">Reject</string>
|
||||||
|
|
||||||
<!--Receiver-->
|
<!--Receiver-->
|
||||||
<string name="create_work_profile_success">Create work profile success</string>
|
<string name="create_work_profile_success">Create work profile success</string>
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ agp = "8.10.0"
|
|||||||
kotlin = "2.1.20"
|
kotlin = "2.1.20"
|
||||||
|
|
||||||
navigation-compose = "2.9.0"
|
navigation-compose = "2.9.0"
|
||||||
composeBom = "2025.05.00"
|
composeBom = "2025.05.01"
|
||||||
accompanist-drawablepainter = "0.35.0-alpha"
|
accompanist-drawablepainter = "0.35.0-alpha"
|
||||||
accompanist-permissions = "0.37.0"
|
accompanist-permissions = "0.37.0"
|
||||||
shizuku = "13.1.5"
|
shizuku = "13.1.5"
|
||||||
fragment = "1.8.6"
|
fragment = "1.8.7"
|
||||||
dhizuku = "2.5.3"
|
dhizuku = "2.5.3"
|
||||||
|
dhizuku-server = "0.0.5"
|
||||||
hiddenApiBypass = "4.3"
|
hiddenApiBypass = "4.3"
|
||||||
libsu = "6.0.0"
|
libsu = "6.0.0"
|
||||||
serialization = "1.7.3"
|
serialization = "1.7.3"
|
||||||
@@ -28,6 +29,7 @@ accompanist-permissions = { group = "com.google.accompanist", name = "accompanis
|
|||||||
shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku" }
|
shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku" }
|
||||||
shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku" }
|
shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku" }
|
||||||
dhizuku-api = { module = "io.github.iamr0s:Dhizuku-API", version.ref = "dhizuku" }
|
dhizuku-api = { module = "io.github.iamr0s:Dhizuku-API", version.ref = "dhizuku" }
|
||||||
|
dhizuku-server-api = { group = "io.github.iamr0s", name = "Dhizuku-SERVER_API", version.ref = "dhizuku-server" }
|
||||||
hiddenApiBypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version.ref = "hiddenApiBypass" }
|
hiddenApiBypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version.ref = "hiddenApiBypass" }
|
||||||
libsu = { module = "com.github.topjohnwu.libsu:core", version.ref = "libsu" }
|
libsu = { module = "com.github.topjohnwu.libsu:core", version.ref = "libsu" }
|
||||||
libsu-service = { module = "com.github.topjohnwu.libsu:service", version.ref = "libsu" }
|
libsu-service = { module = "com.github.topjohnwu.libsu:service", version.ref = "libsu" }
|
||||||
|
|||||||
Reference in New Issue
Block a user