Drop force activating feature, close #114

Update README files
Add AppLockDialog to DhizukuActivity
Improve UI
Upgrade dependencies
This commit is contained in:
BinTianqi
2025-06-01 12:36:25 +08:00
parent 21ddb5a98d
commit fb40708f0d
22 changed files with 175 additions and 307 deletions

View File

@@ -2,7 +2,7 @@
# OwnDroid # OwnDroid
Use Android Device owner privilege to manage your device. Use Android's DevicePolicyManager API to manage your device.
## Download ## Download
@@ -14,60 +14,28 @@ Use Android Device owner privilege to manage your device.
## Features ## Features
- System - System: Disable camera, disable screenshot, master volume mute, disable USB signal, Lock task mode, Manage CA certificates, Wipe data...
- Options: disable camera, disable screenshot, master volume mute, disable USB signal... - Network: Add/modify/delete Wi-Fi, Network stats, Minimum Wi-Fi security level, Always-on VPN, Network logging...
- Lock task mode - Applications: Suspend/hide app, Block app uninstallation, Grant/revoke permissions, Clear app storage, Install/uninstall app...
- Manage CA certificates - User restriction: Disable SMS, disable outgoing call, disable bluetooth, disable NFC, disable USB file transfer, disable app installing, disable app uninstalling...
- _Wipe data_ - User manager: User information, Start/switch/stop/delete user, Create user...
- ... - Password and keyguard: Reset password, Require password complexity, Set screen timeout...
- Network
- Add/modify/delete Wi-Fi ## Working modes
- Network stats
- Minimum Wi-Fi security level - Device owner (recommended)
- Always-on VPN
- Network logging Activating methods:
- ... - Shizuku
- Dhizuku
- Root
- ADB shell command `dpm set-device-owner com.bintianqi.owndroid/.Receiver`
- [Dhizuku](https://github.com/iamr0s/Dhizuku)
- Work profile - Work profile
- Create work profile
- Suspend personal apps
- ...
- Applications
- Suspend/hide app
- Block app uninstallation
- Grant/revoke permissions
- Clear app storage
- Install/uninstall app
- ...
- User restriction
- Network: disable configuring mobile network, disable configuring Wi-Fi, disable SMS, disable outgoing calls...
- Connection: disable bluetooth, disable configuring location, disable USB file transfer, disable printing...
- Applications: disable installing/uninstalling app...
- Users: disable adding/removing/switching user...
- Media: disable configuring brightness, disable adjusting volume...
- Other: disable modifying accounts, disable configuring locale, disable factory reset, disable debug features...
- User manager
- User information
- Start/switch/stop/delete user
- Create user
- ...
- Password and keyguard
- _Reset password_
- Require password complexity
- Set screen timeout
- ...
## Activate
- Shizuku (recommended)
- Dhizuku
- Root
- Execute command in adb shell: `dpm set-device-owner com.bintianqi.owndroid/.Receiver`
## FAQ ## FAQ
### Activating ### Already some accounts on the device
#### Already some accounts on the device
```text ```text
java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the device java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the device
@@ -77,7 +45,7 @@ Solutions:
- Freeze apps who hold those accounts. - Freeze apps who hold those accounts.
- Delete these accounts. - Delete these accounts.
#### Already several users on the device ### Already several users on the device
```text ```text
java.lang.IllegalStateException: Not allowed to set the device owner because there are already several users on the device java.lang.IllegalStateException: Not allowed to set the device owner because there are already several users on the device
@@ -89,7 +57,7 @@ Solutions:
> [!NOTE] > [!NOTE]
> Some systems have features such as app cloning and children space, which are usually users. > Some systems have features such as app cloning and children space, which are usually users.
#### MIUI ### MIUI
```text ```text
java.lang.SecurityException: Neither user 2000 nor current process has android.permission.MANAGE_DEVICE_ADMINS. java.lang.SecurityException: Neither user 2000 nor current process has android.permission.MANAGE_DEVICE_ADMINS.
@@ -99,7 +67,7 @@ Solutions:
- Enable `USB debugging (Security setting)` in developer options. - Enable `USB debugging (Security setting)` in developer options.
- Execute activating command in root shell. - Execute activating command in root shell.
#### ColorOS ### ColorOS
```text ```text
java.lang.IllegalStateException: Unexpected @ProvisioningPreCondition java.lang.IllegalStateException: Unexpected @ProvisioningPreCondition

View File

@@ -27,10 +27,6 @@ AndroidのDevice owner特権を使用してデバイスを管理します。
- 常時オンVPN - 常時オンVPN
- ネットワークログ - ネットワークログ
- ... - ...
- ワークプロファイル
- ワークプロファイルの作成
- 個人アプリの一時停止
- ...
- アプリケーション - アプリケーション
- アプリの一時停止/非表示 - アプリの一時停止/非表示
- アンインストールのブロック - アンインストールのブロック
@@ -63,9 +59,7 @@ AndroidのDevice owner特権を使用してデバイスを管理します。
## FAQ ## FAQ
### アクティベート ### デバイスに既にアカウントが存在する場合
#### デバイスに既にアカウントが存在する場合
```text ```text
java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the device java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the device
@@ -75,7 +69,7 @@ java.lang.IllegalStateException: Not allowed to set the device owner because the
- これらのアカウントを保持しているアプリを凍結します。 - これらのアカウントを保持しているアプリを凍結します。
- これらのアカウントを削除します。 - これらのアカウントを削除します。
#### デバイスに既に複数のユーザーが存在する場合 ### デバイスに既に複数のユーザーが存在する場合
```text ```text
java.lang.IllegalStateException: Not allowed to set the device owner because there are already several users on the device java.lang.IllegalStateException: Not allowed to set the device owner because there are already several users on the device
@@ -87,7 +81,7 @@ java.lang.IllegalStateException: Not allowed to set the device owner because the
> [!NOTE] > [!NOTE]
> 一部のシステムにはアプリのクローンや子供用スペースなどの機能があり、通常はユーザーとして扱われます。 > 一部のシステムにはアプリのクローンや子供用スペースなどの機能があり、通常はユーザーとして扱われます。
#### MIUI ### MIUI
```text ```text
java.lang.SecurityException: Neither user 2000 nor current process has android.permission.MANAGE_DEVICE_ADMINS. java.lang.SecurityException: Neither user 2000 nor current process has android.permission.MANAGE_DEVICE_ADMINS.
@@ -97,7 +91,7 @@ java.lang.SecurityException: Neither user 2000 nor current process has android.p
- 開発者オプションで `USBデバッグセキュリティ設定` を有効にします。 - 開発者オプションで `USBデバッグセキュリティ設定` を有効にします。
- ルートシェルでアクティベートコマンドを実行します。 - ルートシェルでアクティベートコマンドを実行します。
#### ColorOS ### ColorOS
```text ```text
java.lang.IllegalStateException: Unexpected @ProvisioningPreCondition java.lang.IllegalStateException: Unexpected @ProvisioningPreCondition

View File

@@ -2,7 +2,7 @@
# OwnDroid # OwnDroid
使用安卓Device owner特权管理你的设备。 使用安卓的设备策略管理器API管理你的设备。
## 下载 ## 下载
@@ -14,60 +14,28 @@
## 功能 ## 功能
- 系统 - 系统禁用摄像头、禁止截屏、全局静音、禁用USB信号、锁定任务模式、管理CA证书、清除数据...
- 选项禁用摄像头、禁止截屏、全局静音、禁用USB信号... - 网络:添加/修改/删除 Wi-Fi、网络统计、最小Wi-Fi安全等级、VPN保持打开、网络日志...
- 锁定任务模式 - 应用:挂起/隐藏应用、阻止应用卸载、授予/撤销权限、清除应用存储、安装/卸载应用...
- 管理CA证书 - 用户限制禁止发送短信、禁止拨出电话、禁用蓝牙、禁用NFC、禁用USB文件传输、禁止安装应用、禁止卸载应用...
- _清除数据_ - 用户:用户信息、启动/切换/停止/删除用户、创建用户...
- ... - 密码与锁屏:重置密码、要求密码复杂度、设置屏幕超时...
- 网络
- 添加/修改/删除 Wi-Fi ## 工作模式
- 网络统计
- 最小Wi-Fi安全等级 - Device owner推荐
- VPN保持打开
- 网络日志 激活方式:
- ... - Shizuku
- Dhizuku
- Root
- ADB shell命令 `dpm set-device-owner com.bintianqi.owndroid/.Receiver`
- [Dhizuku](https://github.com/iamr0s/Dhizuku)
- 工作资料 - 工作资料
- 创建工作资料
- 挂起个人应用
- ...
- 应用管理
- 挂起/隐藏应用
- 阻止应用卸载
- 授予/撤销权限
- 清除应用存储
- 安装/卸载应用
- ...
- 用户限制
- 网络禁止配置移动网络、禁止配置Wi-Fi、禁用短信、禁止拨出电话...
- 连接禁用蓝牙、禁止配置定位、禁用USB文件传输、禁用打印...
- 应用:禁止安装/卸载应用...
- 用户:禁止添加/删除/切换用户...
- 媒体:禁止调整亮度、禁止调整音量...
- 其他:禁止修改账号、禁止修改语言、禁止恢复出厂设置、禁用调试功能...
- 用户管理
- 用户信息
- 启动/切换/停止/删除用户
- 创建用户
- ...
- 密码与锁屏
- _重置密码_
- 要求密码复杂度
- 设置屏幕超时
- ...
## 激活
- Shizuku (推荐)
- Dhizuku
- Root
- 在ADB命令行中执行命令: `dpm set-device-owner com.bintianqi.owndroid/.Receiver`
## FAQ ## FAQ
### 激活 ### 设备上有账号
#### 设备上有账号
```text ```text
java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the device java.lang.IllegalStateException: Not allowed to set the device owner because there are already some accounts on the device
@@ -77,7 +45,7 @@ java.lang.IllegalStateException: Not allowed to set the device owner because the
- 冻结持有这些账号的app。 - 冻结持有这些账号的app。
- 删除这些账号。 - 删除这些账号。
#### 设备上有多个用户 ### 设备上有多个用户
```text ```text
java.lang.IllegalStateException: Not allowed to set the device owner because there are already several users on the device java.lang.IllegalStateException: Not allowed to set the device owner because there are already several users on the device
@@ -89,7 +57,7 @@ java.lang.IllegalStateException: Not allowed to set the device owner because the
> [!NOTE] > [!NOTE]
> 一些系统有应用克隆、儿童空间等功能,它们通常是用户。 > 一些系统有应用克隆、儿童空间等功能,它们通常是用户。
#### MIUI ### MIUI
```text ```text
java.lang.SecurityException: Neither user 2000 nor current process has android.permission.MANAGE_DEVICE_ADMINS. java.lang.SecurityException: Neither user 2000 nor current process has android.permission.MANAGE_DEVICE_ADMINS.
@@ -99,7 +67,7 @@ java.lang.SecurityException: Neither user 2000 nor current process has android.p
- 在开发者设置中打开`USB调试安全设置` - 在开发者设置中打开`USB调试安全设置`
- 在root命令行中执行激活命令 - 在root命令行中执行激活命令
#### ColorOS ### ColorOS
```text ```text
java.lang.IllegalStateException: Unexpected @ProvisioningPreCondition java.lang.IllegalStateException: Unexpected @ProvisioningPreCondition
@@ -147,9 +115,6 @@ context.sendBroadcast(intent)
``` ```
在Windows系统中应使用`./gradlew.bat`) 在Windows系统中应使用`./gradlew.bat`)
> [!TIP]
> 在中国大陆下载Gradle速度慢打开`gradle/wrapper/gradle-wrapper.properties`文件,注释官方下载地址,取消注释一个镜像地址。
## 许可证 ## 许可证
[License.md](LICENSE.md) [License.md](LICENSE.md)

View File

@@ -96,7 +96,6 @@ dependencies {
implementation(libs.androidx.fragment) implementation(libs.androidx.fragment)
implementation(libs.hiddenApiBypass) implementation(libs.hiddenApiBypass)
implementation(libs.libsu) implementation(libs.libsu)
implementation(libs.libsu.service)
implementation(libs.serialization) implementation(libs.serialization)
implementation(kotlin("reflect")) implementation(kotlin("reflect"))
} }

View File

@@ -8,6 +8,8 @@ import android.os.Bundle
import android.util.Log import android.util.Log
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
@@ -16,11 +18,14 @@ import androidx.compose.material3.TextButton
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
import com.google.accompanist.drawablepainter.rememberDrawablePainter import com.google.accompanist.drawablepainter.rememberDrawablePainter
import com.rosan.dhizuku.aidl.IDhizukuClient import com.rosan.dhizuku.aidl.IDhizukuClient
import com.rosan.dhizuku.aidl.IDhizukuRequestPermissionListener import com.rosan.dhizuku.aidl.IDhizukuRequestPermissionListener
@@ -97,43 +102,52 @@ class DhizukuActivity : ComponentActivity() {
if (grantPermission) PackageManager.PERMISSION_GRANTED else PackageManager.PERMISSION_DENIED if (grantPermission) PackageManager.PERMISSION_GRANTED else PackageManager.PERMISSION_DENIED
) )
} }
val vm by viewModels<MyViewModel>()
enableEdgeToEdge()
setContent { setContent {
AlertDialog( var appLockDialog by remember { mutableStateOf(false) }
icon = { val theme by vm.theme.collectAsStateWithLifecycle()
Image(rememberDrawablePainter(icon), null, Modifier.size(35.dp)) OwnDroidTheme(theme) {
}, if (!appLockDialog) AlertDialog(
title = { icon = {
Text(stringResource(R.string.request_permission)) Image(rememberDrawablePainter(icon), null, Modifier.size(35.dp))
}, },
text = { title = {
Text("$label\n($packageName)") Text(stringResource(R.string.request_permission))
}, },
confirmButton = { text = {
var time by remember { mutableIntStateOf(3) } Text("$label\n($packageName)")
LaunchedEffect(Unit) { },
(1..3).forEach { confirmButton = {
delay(1000) var time by remember { mutableIntStateOf(3) }
time -= 1 LaunchedEffect(Unit) {
(1..3).forEach {
delay(1000)
time -= 1
}
} }
} TextButton({
TextButton({ if (SharedPrefs(this).lockPasswordHash.isNullOrEmpty()) {
close(true) close(true)
}, enabled = time == 0) { } else {
val append = if (time > 0) " (${time}s)" else "" appLockDialog = true
Text(stringResource(R.string.allow) + append) }
} }, enabled = time == 0) {
}, val append = if (time > 0) " (${time}s)" else ""
dismissButton = { Text(stringResource(R.string.allow) + append)
TextButton({ }
close(false) },
}) { dismissButton = {
Text(stringResource(R.string.reject)) TextButton({
} close(false)
}, }) {
onDismissRequest = { Text(stringResource(R.string.reject))
finish() }
} },
) onDismissRequest = { close(false) }
)
else AppLockDialog({ close(true) }) { close(false) }
}
} }
} }
} }

View File

@@ -12,9 +12,10 @@ import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
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.imePadding import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
@@ -48,7 +49,6 @@ import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleEventObserver
@@ -249,7 +249,6 @@ import java.util.Locale
class MainActivity : FragmentActivity() { class MainActivity : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge() enableEdgeToEdge()
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val context = applicationContext val context = applicationContext
if (VERSION.SDK_INT >= 28) HiddenApiBypass.setHiddenApiExemptions("") if (VERSION.SDK_INT >= 28) HiddenApiBypass.setHiddenApiExemptions("")
@@ -309,7 +308,6 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.background(colorScheme.background) .background(colorScheme.background)
.imePadding()
.pointerInput(Unit) { detectTapGestures(onTap = { focusMgr.clearFocus() }) }, .pointerInput(Unit) { detectTapGestures(onTap = { focusMgr.clearFocus() }) },
enterTransition = Animations.navHostEnterTransition, enterTransition = Animations.navHostEnterTransition,
exitTransition = Animations.navHostExitTransition, exitTransition = Animations.navHostExitTransition,
@@ -514,7 +512,8 @@ private fun HomeScreen(onNavigate: (Any) -> Unit) {
}, },
scrollBehavior = sb scrollBehavior = sb
) )
} },
contentWindowInsets = WindowInsets.ime
) { ) {
Column(Modifier.fillMaxSize().padding(it).verticalScroll(rememberScrollState())) { Column(Modifier.fillMaxSize().padding(it).verticalScroll(rememberScrollState())) {
if(privilege.device || privilege.profile) { if(privilege.device || privilege.profile) {

View File

@@ -10,16 +10,18 @@ import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
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.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@@ -75,6 +77,7 @@ class PackageChooserActivity: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val vm by viewModels<MyViewModel>() val vm by viewModels<MyViewModel>()
enableEdgeToEdge()
setContent { setContent {
val theme by vm.theme.collectAsStateWithLifecycle() val theme by vm.theme.collectAsStateWithLifecycle()
OwnDroidTheme(theme) { OwnDroidTheme(theme) {
@@ -177,7 +180,8 @@ fun AppChooserScreen(params: ApplicationsList, onChoosePackage: (String?) -> Uni
}, },
colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceContainer) colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceContainer)
) )
} },
contentWindowInsets = WindowInsets.ime
) { paddingValues -> ) { paddingValues ->
LazyColumn(Modifier.fillMaxSize().padding(paddingValues)) { LazyColumn(Modifier.fillMaxSize().padding(paddingValues)) {
if (progress < 1F) stickyHeader { if (progress < 1F) stickyHeader {

View File

@@ -12,8 +12,10 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
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.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
@@ -116,7 +118,8 @@ fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
} }
} }
) )
} },
contentWindowInsets = WindowInsets.ime
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier modifier = Modifier

View File

@@ -23,8 +23,10 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
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.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyItemScope import androidx.compose.foundation.lazy.LazyItemScope
@@ -172,7 +174,8 @@ fun ApplicationsFeaturesScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Un
}, },
scrollBehavior = sb scrollBehavior = sb
) )
} },
contentWindowInsets = WindowInsets.ime
) { paddingValues -> ) { paddingValues ->
Column( Column(
Modifier Modifier

View File

@@ -520,6 +520,7 @@ fun handlePrivilegeChange(context: Context) {
val privilege = myPrivilege.value val privilege = myPrivilege.value
val activated = privilege.device || privilege.profile val activated = privilege.device || privilege.profile
val sp = SharedPrefs(context) val sp = SharedPrefs(context)
sp.dhizukuServer = false
if(activated) { if(activated) {
createShortcuts(context) createShortcuts(context)
if(!privilege.dhizuku) { if(!privilege.dhizuku) {

View File

@@ -51,8 +51,10 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
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.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.pager.rememberPagerState
@@ -239,7 +241,8 @@ fun WifiScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onNavigateTo
navigationIcon = { NavIcon(onNavigateUp) }, navigationIcon = { NavIcon(onNavigateUp) },
colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceContainer) colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceContainer)
) )
} },
contentWindowInsets = WindowInsets.ime
) { paddingValues -> ) { paddingValues ->
var wifiMacDialog by remember { mutableStateOf(false) } var wifiMacDialog by remember { mutableStateOf(false) }
Column( Column(

View File

@@ -1,19 +1,10 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.dpm
import android.annotation.SuppressLint
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.Bundle
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.os.Message
import android.os.Messenger
import android.os.PersistableBundle import android.os.PersistableBundle
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.annotation.Keep import androidx.annotation.Keep
@@ -29,13 +20,14 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
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.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.itemsIndexed 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
@@ -44,6 +36,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.outlined.Edit import androidx.compose.material.icons.outlined.Edit
@@ -55,6 +48,7 @@ import androidx.compose.material3.Checkbox
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
@@ -86,7 +80,6 @@ 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.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.DHIZUKU_CLIENTS_FILE
@@ -114,14 +107,10 @@ 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
import com.topjohnwu.superuser.ipc.RootService
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.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import java.lang.invoke.MethodHandles
import java.lang.reflect.Proxy
@Serializable data class WorkModes(val canNavigateUp: Boolean) @Serializable data class WorkModes(val canNavigateUp: Boolean)
@@ -134,7 +123,7 @@ fun WorkModesScreen(
val context = LocalContext.current val context = LocalContext.current
val coroutine = rememberCoroutineScope() val coroutine = rememberCoroutineScope()
val privilege by myPrivilege.collectAsStateWithLifecycle() val privilege by myPrivilege.collectAsStateWithLifecycle()
/** 0: none, 1: device owner, 2: circular progress indicator, 3: result, 4: deactivate, 5: command, 6: force activating warning */ /** 0: none, 1: device owner, 2: circular progress indicator, 3: result, 4: deactivate, 5: command */
var dialog by remember { mutableIntStateOf(0) } var dialog by remember { mutableIntStateOf(0) }
Scaffold( Scaffold(
topBar = { topBar = {
@@ -162,21 +151,24 @@ fun WorkModesScreen(
{ {
expanded = false expanded = false
dialog = 4 dialog = 4
} },
leadingIcon = { Icon(Icons.Default.Close, null) }
) )
if (VERSION.SDK_INT >= 26) DropdownMenuItem( if (VERSION.SDK_INT >= 26) DropdownMenuItem(
{ Text(stringResource(R.string.delegated_admins)) }, { Text(stringResource(R.string.delegated_admins)) },
{ {
expanded = false expanded = false
onNavigate(DelegatedAdmins) onNavigate(DelegatedAdmins)
} },
leadingIcon = { Icon(painterResource(R.drawable.admin_panel_settings_fill0), null) }
) )
if (!privilege.dhizuku && VERSION.SDK_INT >= 28) DropdownMenuItem( if (!privilege.dhizuku && VERSION.SDK_INT >= 28) DropdownMenuItem(
{ Text(stringResource(R.string.transfer_ownership)) }, { Text(stringResource(R.string.transfer_ownership)) },
{ {
expanded = false expanded = false
onNavigate(TransferOwnership) onNavigate(TransferOwnership)
} },
leadingIcon = { Icon(painterResource(R.drawable.swap_horiz_fill0), null) }
) )
} }
} }
@@ -185,7 +177,8 @@ fun WorkModesScreen(
} }
} }
) )
} },
contentWindowInsets = WindowInsets.ime
) { paddingValues -> ) { paddingValues ->
var navigateUpOnSucceed by remember { mutableStateOf(true) } var navigateUpOnSucceed by remember { mutableStateOf(true) }
var operationSucceed by remember { mutableStateOf(false) } var operationSucceed by remember { mutableStateOf(false) }
@@ -198,6 +191,7 @@ fun WorkModesScreen(
updatePrivilege(context) updatePrivilege(context)
handlePrivilegeChange(context) handlePrivilegeChange(context)
} else { } else {
dialog = 0
context.showOperationResultToast(false) context.showOperationResultToast(false)
} }
} }
@@ -315,12 +309,6 @@ fun WorkModesScreen(
} }
Spacer(Modifier.padding(horizontal = 2.dp)) Spacer(Modifier.padding(horizontal = 2.dp))
Button({ dialog = 5 }) { Text(stringResource(R.string.adb_command)) } Button({ dialog = 5 }) { Text(stringResource(R.string.adb_command)) }
Spacer(Modifier.padding(horizontal = 2.dp))
if (VERSION.SDK_INT >= 33) Button({
dialog = 6
}) {
Text(stringResource(R.string.root_force_activate))
}
} }
}, },
confirmButton = { confirmButton = {
@@ -386,23 +374,6 @@ fun WorkModesScreen(
}, },
onDismissRequest = { dialog = 0 } onDismissRequest = { dialog = 0 }
) )
if (dialog == 6) AlertDialog(
title = { Text(stringResource(R.string.warning)) },
text = { Text(stringResource(R.string.info_force_activate)) },
confirmButton = {
TextButton({
dialog = 2
navigateUpOnSucceed = false
forceActivateUsingRoot(context, ::handleResult)
}) {
Text(stringResource(R.string.continue_str))
}
},
dismissButton = {
TextButton({ dialog = 0 }) { Text(stringResource(R.string.cancel)) }
},
onDismissRequest = { dialog = 0 }
)
} }
} }
@@ -469,75 +440,6 @@ fun activateUsingDhizuku(context: Context, callback: (Boolean, Boolean, String?)
} }
} }
fun forceActivateUsingRoot(context: Context, callback: (Boolean, Boolean, String?) -> Unit) {
val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val handler = Handler(Looper.getMainLooper()) { msg ->
RootService.unbind(this)
val data = msg.data
val output = if (data.getBoolean("succeed")) context.getString(R.string.please_reboot) else null
callback(!data.getBoolean("error"), data.getBoolean("succeed"), output)
return@Handler true
}
val msg = Message()
msg.replyTo = Messenger(handler)
Messenger(service).send(msg)
}
override fun onServiceDisconnected(name: ComponentName?) {}
}
val intent = Intent(context, ForceActivateService::class.java)
RootService.bind(intent, connection)
}
@RequiresApi(26)
class ForceActivateService(): RootService() {
override fun onBind(intent: Intent): IBinder = messenger.binder
val handler = Handler(Looper.getMainLooper()) { msg ->
val replyMessage = Message()
try {
replyMessage.data = activateDeviceOwnerAsRoot(getReceiver()).apply { putBoolean("error", false) }
} catch (e: Exception) {
e.printStackTrace()
replyMessage.data = bundleOf("error" to true, "succeed" to false)
}
msg.replyTo.send(replyMessage)
return@Handler false
}
val messenger = Messenger(handler)
}
@SuppressLint("PrivateApi")
@RequiresApi(26)
fun activateDeviceOwnerAsRoot(cn: ComponentName): Bundle {
val dcl = DexClassLoader(
"/system/framework/services.jar", "/data/local/tmp", null, ClassLoader.getSystemClassLoader()
)
val ppp = dcl.loadClass("com.android.server.devicepolicy.PolicyPathProvider")
val pppProxy = Proxy.newProxyInstance(ppp.classLoader, arrayOf(ppp)) { obj, method, args ->
method.isAccessible = true
val mh = MethodHandles.lookup().`in`(ppp).unreflectSpecial(method, ppp).bindTo(obj)
return@newProxyInstance if (args == null) {
mh.invokeWithArguments()
} else {
mh.invokeWithArguments(*args)
}
}
val od = dcl.loadClass("com.android.server.devicepolicy.OwnersData")
val odIns = od.getConstructor(ppp).apply { isAccessible = true }.newInstance(pppProxy)
val oi = dcl.loadClass("com.android.server.devicepolicy.OwnersData\$OwnerInfo")
val oiIns = oi.constructors[0].apply { isAccessible = true }.newInstance(cn, null, null, true)
od.getField("mDeviceOwner").apply { isAccessible = true }.set(odIns, oiIns)
od.getField("mDeviceOwnerUserId").apply { isAccessible = true }.set(odIns, 0)
val setDoResult = od.getMethod("writeDeviceOwner").apply { isAccessible = true }.invoke(odIns) as Boolean
return if (setDoResult) {
val proc = Runtime.getRuntime().exec("dpm set-active-admin ${cn.flattenToShortString()}")
proc.waitFor()
bundleOf("succeed" to true)
} else {
bundleOf("succeed" to false)
}
}
fun activateDhizukuMode(context: Context, callback: (Boolean, Boolean, String?) -> Unit) { fun activateDhizukuMode(context: Context, callback: (Boolean, Boolean, String?) -> Unit) {
fun onSucceed() { fun onSucceed() {
SharedPrefs(context).dhizuku = true SharedPrefs(context).dhizuku = true
@@ -589,7 +491,7 @@ fun DhizukuServerSettingsScreen(onNavigateUp: () -> Unit) {
MyLazyScaffold(R.string.dhizuku_server, onNavigateUp) { MyLazyScaffold(R.string.dhizuku_server, onNavigateUp) {
item { item {
SwitchItem(R.string.enable, getState = { sp.dhizukuServer }, onCheckedChange = ::changeEnableState) SwitchItem(R.string.enable, getState = { sp.dhizukuServer }, onCheckedChange = ::changeEnableState)
Spacer(Modifier.padding(vertical = 8.dp)) HorizontalDivider(Modifier.padding(vertical = 8.dp))
} }
if (enabled) itemsIndexed(clients) { index, client -> if (enabled) itemsIndexed(clients) { index, client ->
val name = pm.getNameForUid(client.uid) val name = pm.getNameForUid(client.uid)
@@ -599,16 +501,13 @@ fun DhizukuServerSettingsScreen(onNavigateUp: () -> Unit) {
} else { } else {
val info = pm.getApplicationInfo(name, 0) val info = pm.getApplicationInfo(name, 0)
Row( Row(
Modifier Modifier.fillMaxWidth().padding(HorizontalPadding, 8.dp),
.fillMaxWidth().padding(8.dp)
.background(colorScheme.surfaceVariant, RoundedCornerShape(8.dp))
.padding(8.dp),
Arrangement.SpaceBetween, Alignment.CenterVertically Arrangement.SpaceBetween, Alignment.CenterVertically
) { ) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Image( Image(
rememberDrawablePainter(info.loadIcon(pm)), null, rememberDrawablePainter(info.loadIcon(pm)), null,
Modifier.padding(end = 12.dp).size(50.dp) Modifier.padding(end = 16.dp).size(50.dp)
) )
Text(info.loadLabel(pm).toString(), style = typography.titleLarge) Text(info.loadLabel(pm).toString(), style = typography.titleLarge)
} }

View File

@@ -47,8 +47,10 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
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.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
@@ -1104,7 +1106,8 @@ fun LockTaskModeScreen(onNavigateUp: () -> Unit) {
navigationIcon = { NavIcon(onNavigateUp) }, navigationIcon = { NavIcon(onNavigateUp) },
colors = TopAppBarDefaults.topAppBarColors(colorScheme.surfaceContainer) colors = TopAppBarDefaults.topAppBarColors(colorScheme.surfaceContainer)
) )
} },
contentWindowInsets = WindowInsets.ime
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier modifier = Modifier
@@ -1405,7 +1408,8 @@ fun CaCertScreen(onNavigateUp: () -> Unit) {
}) { }) {
Icon(Icons.Default.Add, stringResource(R.string.install)) Icon(Icons.Default.Add, stringResource(R.string.install))
} }
} },
contentWindowInsets = WindowInsets.ime
) { paddingValues -> ) { paddingValues ->
LazyColumn( LazyColumn(
Modifier Modifier

View File

@@ -12,8 +12,11 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
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.ime
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@@ -101,7 +104,8 @@ fun UserRestrictionScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
}, },
scrollBehavior = sb scrollBehavior = sb
) )
} },
contentWindowInsets = WindowInsets.ime
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier modifier = Modifier
@@ -299,7 +303,8 @@ fun UserRestrictionEditorScreen(onNavigateUp: () -> Unit) {
title = { Text(stringResource(R.string.edit)) }, title = { Text(stringResource(R.string.edit)) },
navigationIcon = { NavIcon(onNavigateUp) } navigationIcon = { NavIcon(onNavigateUp) }
) )
} },
contentWindowInsets = WindowInsets.ime
) { paddingValues -> ) { paddingValues ->
LazyColumn(Modifier.fillMaxSize().padding(paddingValues)) { LazyColumn(Modifier.fillMaxSize().padding(paddingValues)) {
items(list, { it }) { items(list, { it }) {

View File

@@ -10,8 +10,10 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
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.ime
import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@@ -294,7 +296,8 @@ fun MyScaffold(
navigationIcon = { NavIcon(onNavIconClicked) }, navigationIcon = { NavIcon(onNavIconClicked) },
scrollBehavior = sb scrollBehavior = sb
) )
} },
contentWindowInsets = WindowInsets.ime
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier modifier = Modifier
@@ -325,7 +328,8 @@ fun MyLazyScaffold(
navigationIcon = { NavIcon(onNavIconClicked) }, navigationIcon = { NavIcon(onNavIconClicked) },
scrollBehavior = sb scrollBehavior = sb
) )
} },
contentWindowInsets = WindowInsets.ime
) { paddingValues -> ) { paddingValues ->
LazyColumn(Modifier.fillMaxSize().padding(paddingValues), content = content) LazyColumn(Modifier.fillMaxSize().padding(paddingValues), content = content)
} }
@@ -346,7 +350,8 @@ fun MySmallTitleScaffold(
navigationIcon = { NavIcon(onNavIconClicked) }, navigationIcon = { NavIcon(onNavIconClicked) },
colors = TopAppBarDefaults.topAppBarColors(colorScheme.surfaceContainer) colors = TopAppBarDefaults.topAppBarColors(colorScheme.surfaceContainer)
) )
} },
contentWindowInsets = WindowInsets.ime
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier modifier = Modifier

View File

@@ -3,7 +3,11 @@ package com.bintianqi.owndroid.ui.theme
import android.app.Activity import android.app.Activity
import android.os.Build.VERSION import android.os.Build.VERSION
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.* import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@@ -106,7 +110,7 @@ fun OwnDroidTheme(
} }
val view = LocalView.current val view = LocalView.current
SideEffect { SideEffect {
val window = (view.context as Activity).window val window = (context as Activity).window
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme
} }
MaterialTheme( MaterialTheme(

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M280,800 L80,600l200,-200 56,57 -103,103h287v80L233,640l103,103 -56,57ZM680,560 L624,503 727,400L440,400v-80h287L624,217l56,-57 200,200 -200,200Z"
android:fillColor="#000000"/>
</vector>

View File

@@ -693,13 +693,10 @@
<string name="info_password_history_length">设置后用户将无法输入与历史记录中任何密码相同的新密码。当前密码将保留直到用户设置新密码为止因此更改不会立即生效。值为0表示不做限制。</string> <string name="info_password_history_length">设置后用户将无法输入与历史记录中任何密码相同的新密码。当前密码将保留直到用户设置新密码为止因此更改不会立即生效。值为0表示不做限制。</string>
<string name="info_required_strong_auth_timeout">如果用户在这段时间内没有使用强认证密码、PIN或图案解锁设备则要求使用强认证解锁设备。值为0表示OwnDroid不参与控制超时。一般来说最少1小时最多72小时。</string> <string name="info_required_strong_auth_timeout">如果用户在这段时间内没有使用强认证密码、PIN或图案解锁设备则要求使用强认证解锁设备。值为0表示OwnDroid不参与控制超时。一般来说最少1小时最多72小时。</string>
<string name="info_deactivate">OwnDroid将会丢失特权</string> <string name="info_deactivate">OwnDroid将会丢失特权</string>
<string name="info_force_activate">强行激活可能无法在你的设备上使用,它甚至有可能会损坏你的设备,你应该仅在其他方法无法使用时尝试此方法。</string>
<string name="choose_work_mode">选择一个工作模式</string> <string name="choose_work_mode">选择一个工作模式</string>
<string name="recommended">推荐</string> <string name="recommended">推荐</string>
<string name="activate_method">激活方法</string> <string name="activate_method">激活方法</string>
<string name="adb_command">ADB命令</string> <string name="adb_command">ADB命令</string>
<string name="root_force_activate">Root (强行激活)</string>
<string name="owndroid_warning">此应用使用Device owner或Profile owner特权。这些特权十分危险请谨慎使用。如果操作不当可能会造成严重损失。开发者将不会对此负责。</string> <string name="owndroid_warning">此应用使用Device owner或Profile owner特权。这些特权十分危险请谨慎使用。如果操作不当可能会造成严重损失。开发者将不会对此负责。</string>
<string name="please_reboot">请重启你的设备</string>
</resources> </resources>

View File

@@ -727,13 +727,10 @@
<string name="info_password_history_length">After setting this, the user will not be able to enter a new password that is the same as any password in the history. Note that the current password will remain until the user has set a new one, so the change does not take place immediately.\nA value of 0 means there is no restriction.</string> <string name="info_password_history_length">After setting this, the user will not be able to enter a new password that is the same as any password in the history. Note that the current password will remain until the user has set a new one, so the change does not take place immediately.\nA value of 0 means there is no restriction.</string>
<string name="info_required_strong_auth_timeout">Determine for how long the user will be able to use secondary, non strong auth for authentication, since last strong method authentication (password, pin or pattern) was used. After the returned timeout the user is required to use strong authentication method.\nA value of 0 means the admin is not participating in controlling the timeout. The minimum and maximum timeouts are platform-defined and are typically 1 hour and 72 hours, respectively.</string> <string name="info_required_strong_auth_timeout">Determine for how long the user will be able to use secondary, non strong auth for authentication, since last strong method authentication (password, pin or pattern) was used. After the returned timeout the user is required to use strong authentication method.\nA value of 0 means the admin is not participating in controlling the timeout. The minimum and maximum timeouts are platform-defined and are typically 1 hour and 72 hours, respectively.</string>
<string name="info_deactivate">OwnDroid will lost its privilege</string> <string name="info_deactivate">OwnDroid will lost its privilege</string>
<string name="info_force_activate">Force activation may not work and it may damage your device. This method should only be used when you can\'t use other methods.</string>
<string name="choose_work_mode">Choose a work mode</string> <string name="choose_work_mode">Choose a work mode</string>
<string name="recommended">Recommended</string> <string name="recommended">Recommended</string>
<string name="activate_method">Activate method</string> <string name="activate_method">Activate method</string>
<string name="adb_command">ADB command</string> <string name="adb_command">ADB command</string>
<string name="root_force_activate">Root (force activate)</string>
<string name="owndroid_warning">This app uses Device owner or Profile owner privileges. These privileges are extremely dangerous, please use them with caution. If used improperly, they may result in severe losses. The developers will not be responsible for this.</string> <string name="owndroid_warning">This app uses Device owner or Profile owner privileges. These privileges are extremely dangerous, please use them with caution. If used improperly, they may result in severe losses. The developers will not be responsible for this.</string>
<string name="please_reboot">Please reboot your device</string>
</resources> </resources>

View File

@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="Theme.OwnDroid" parent="android:Theme.Material.Light.NoActionBar"> <style name="Theme.OwnDroid" parent="android:Theme.Material.Light.NoActionBar">
<item name="android:navigationBarColor">#FFFFFF</item>
<item name="android:statusBarColor">#FFFFFF</item>
</style> </style>
<style name="Theme.Transparent" parent="Theme.OwnDroid"> <style name="Theme.Transparent" parent="Theme.OwnDroid">
<item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowBackground">@android:color/transparent</item>

View File

@@ -1,5 +1,5 @@
[versions] [versions]
agp = "8.10.0" agp = "8.10.1"
kotlin = "2.1.20" kotlin = "2.1.20"
navigation-compose = "2.9.0" navigation-compose = "2.9.0"
@@ -32,7 +32,6 @@ 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" } 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" }
serialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serialization" } serialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serialization" }

View File

@@ -1,8 +1,6 @@
#Fri Jan 12 20:22:20 CST 2024 #Fri Jan 12 20:22:20 CST 2024
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip distributionUrl=https\://downloads.gradle.org/distributions/gradle-8.14.1-bin.zip
#distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-8.14-bin.zip
#distributionUrl=https://mirrors.aliyun.com/gradle/distributions/v8.14.0/gradle-8.14-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists