merge branch 'auth'

This commit is contained in:
BinTianqi
2024-05-17 13:28:12 +08:00
13 changed files with 344 additions and 44 deletions

View File

@@ -21,21 +21,24 @@ android {
applicationId = "com.bintianqi.owndroid" applicationId = "com.bintianqi.owndroid"
minSdk = 21 minSdk = 21
targetSdk = 34 targetSdk = 34
versionCode = 27 versionCode = 28
versionName = "5.2" versionName = "5.3"
multiDexEnabled = false multiDexEnabled = false
signingConfig = signingConfigs.getByName("testkey")
} }
buildTypes { buildTypes {
release { release {
project.gradle.startParameter.excludedTaskNames.add("lint") //project.gradle.startParameter.excludedTaskNames.add("lint")
isMinifyEnabled = true isMinifyEnabled = true
isShrinkResources = true isShrinkResources = true
proguardFiles( proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro" "proguard-rules.pro"
) )
signingConfig = signingConfigs.getByName("testkey")
}
debug {
signingConfig = signingConfigs.getByName("testkey")
} }
} }
compileOptions { compileOptions {
@@ -75,4 +78,5 @@ dependencies {
implementation(libs.androidx.navigation.compose) implementation(libs.androidx.navigation.compose)
implementation(libs.shizuku.provider) implementation(libs.shizuku.provider)
implementation(libs.shizuku.api) implementation(libs.shizuku.api)
implementation(libs.androidx.biometric)
} }

View File

@@ -45,7 +45,6 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<receiver <receiver
android:name=".Receiver" android:name=".Receiver"
android:description="@string/app_name" android:description="@string/app_name"

View File

@@ -0,0 +1,153 @@
package com.bintianqi.owndroid
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt
import androidx.biometric.BiometricPrompt.AuthenticationCallback
import androidx.biometric.BiometricPrompt.PromptInfo.Builder
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.stringResource
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class AuthFragment: Fragment() {
@SuppressLint("UnrememberedMutableState")
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val context = requireContext()
val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)!!
val canStartAuth = mutableStateOf(true)
val onAuthSucceed = {
val fragmentManager = this.parentFragmentManager
val transaction = fragmentManager.beginTransaction()
transaction.setCustomAnimations(R.anim.enter, R.anim.exit)
transaction.remove(this@AuthFragment).commit()
}
val promptInfo = Builder()
.setTitle(context.getText(R.string.authenticate))
.setSubtitle(context.getText(R.string.auth_with_bio))
.setConfirmationRequired(true)
var fallback = false
val callback = object: AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
onAuthSucceed()
}
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
when(errorCode){
BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL -> onAuthSucceed()
BiometricPrompt.ERROR_NEGATIVE_BUTTON -> fallback = true
else -> canStartAuth.value = true
}
Log.e("OwnDroid", errString.toString())
}
}
lifecycleScope.launch(Dispatchers.Main) {
while(true){
if(fallback){
val fallbackPromptInfo = Builder()
.setAllowedAuthenticators(BiometricManager.Authenticators.DEVICE_CREDENTIAL)
.setTitle(context.getText(R.string.authenticate))
.setSubtitle(context.getText(R.string.auth_with_password))
.setConfirmationRequired(true)
.build()
val executor = ContextCompat.getMainExecutor(requireContext())
val biometricPrompt = BiometricPrompt(requireActivity(), executor, callback)
biometricPrompt.authenticate(fallbackPromptInfo)
break
}
delay(50)
}
}
return ComposeView(requireContext()).apply {
setContent {
val materialYou = mutableStateOf(sharedPref.getBoolean("material_you",true))
val blackTheme = mutableStateOf(sharedPref.getBoolean("black_theme", false))
OwnDroidTheme(materialYou.value, blackTheme.value) {
Auth(this@AuthFragment, promptInfo, callback, canStartAuth)
}
}
}
}
}
@Composable
fun Auth(activity: Fragment, promptInfo: Builder, callback: AuthenticationCallback, canStartAuth: MutableState<Boolean>) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)
){
Text(
text = stringResource(R.string.authenticate),
style = MaterialTheme.typography.headlineLarge,
color = MaterialTheme.colorScheme.onBackground
)
LaunchedEffect(Unit){
delay(300)
startAuth(activity, promptInfo, callback)
canStartAuth.value = false
}
Button(
onClick = {
startAuth(activity, promptInfo, callback)
canStartAuth.value = false
},
enabled = canStartAuth.value
){
Text(text = stringResource(R.string.start))
}
}
}
private fun startAuth(activity: Fragment, promptInfo: Builder, callback: AuthenticationCallback){
val context = activity.requireContext()
val bioManager = BiometricManager.from(context)
val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)
if(sharedPref.getBoolean("bio_auth", false)){
when(BiometricManager.BIOMETRIC_SUCCESS){
bioManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) ->
promptInfo
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
.setNegativeButtonText(context.getText(R.string.use_password))
bioManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) ->
promptInfo
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_WEAK)
.setNegativeButtonText(context.getText(R.string.use_password))
else -> promptInfo
.setAllowedAuthenticators(BiometricManager.Authenticators.DEVICE_CREDENTIAL)
.setSubtitle(context.getText(R.string.auth_with_password))
}
}else{
promptInfo
.setAllowedAuthenticators(BiometricManager.Authenticators.DEVICE_CREDENTIAL)
.setSubtitle(context.getText(R.string.auth_with_password))
}
val executor = ContextCompat.getMainExecutor(context)
val biometricPrompt = BiometricPrompt(activity, executor, callback)
biometricPrompt.authenticate(promptInfo.build())
}

View File

@@ -6,9 +6,11 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@@ -27,12 +29,15 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager 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.core.view.WindowCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
@@ -45,21 +50,65 @@ import java.util.Locale
var backToHome = false var backToHome = false
@ExperimentalMaterial3Api @ExperimentalMaterial3Api
class MainActivity : ComponentActivity() { class MainActivity : FragmentActivity() {
private var auth = false
@SuppressLint("UnrememberedMutableState") @SuppressLint("UnrememberedMutableState")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
registerActivityResult(this)
enableEdgeToEdge() enableEdgeToEdge()
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
registerActivityResult(this) setContentView(R.layout.base)
val locale = applicationContext.resources.configuration.locale
zhCN = locale==Locale.SIMPLIFIED_CHINESE||locale==Locale.CHINESE||locale==Locale.CHINA
val sharedPref = applicationContext.getSharedPreferences("data", Context.MODE_PRIVATE) val sharedPref = applicationContext.getSharedPreferences("data", Context.MODE_PRIVATE)
setContent { val fragmentManager = supportFragmentManager
val materialYou = mutableStateOf(sharedPref.getBoolean("material_you",true)) val transaction = fragmentManager.beginTransaction()
val blackTheme = mutableStateOf(sharedPref.getBoolean("black_theme", false)) transaction.add(R.id.base, HomeFragment(), "home")
OwnDroidTheme(materialYou.value, blackTheme.value){ if(sharedPref.getBoolean("auth", false)){
Home(materialYou, blackTheme) transaction.add(R.id.base, AuthFragment(), "auth")
}
transaction.commit()
val locale = applicationContext.resources?.configuration?.locale
zhCN = locale==Locale.SIMPLIFIED_CHINESE||locale==Locale.CHINESE||locale==Locale.CHINA
}
override fun onResume() {
super.onResume()
if(auth){
val sharedPref = applicationContext.getSharedPreferences("data", Context.MODE_PRIVATE)
if(
sharedPref.getBoolean("auth", false) &&
sharedPref.getBoolean("lock_in_background", false)
){
val fragmentManager = supportFragmentManager
val fragment = fragmentManager.findFragmentByTag("auth")
if(fragment == null){
val transaction = fragmentManager.beginTransaction()
transaction.setCustomAnimations(R.anim.enter, R.anim.exit)
transaction.add(R.id.base, AuthFragment(), "auth").commit()
}
}
auth = false
}
}
override fun onRestart() {
super.onRestart()
auth = true
}
}
class HomeFragment: Fragment() {
@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnrememberedMutableState")
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val sharedPref = context?.getSharedPreferences("data", Context.MODE_PRIVATE)!!
return ComposeView(requireContext()).apply {
setContent {
val materialYou = mutableStateOf(sharedPref.getBoolean("material_you",true))
val blackTheme = mutableStateOf(sharedPref.getBoolean("black_theme", false))
OwnDroidTheme(materialYou.value, blackTheme.value){
Home(materialYou, blackTheme)
}
} }
} }
} }
@@ -96,18 +145,18 @@ fun Home(materialYou:MutableState<Boolean>, blackTheme:MutableState<Boolean>){
popEnterTransition = Animations.navHostPopEnterTransition, popEnterTransition = Animations.navHostPopEnterTransition,
popExitTransition = Animations.navHostPopExitTransition popExitTransition = Animations.navHostPopExitTransition
){ ){
composable(route = "HomePage", content = { HomePage(navCtrl, pkgName)}) composable(route = "HomePage"){ HomePage(navCtrl, pkgName) }
composable(route = "SystemManage", content = { SystemManage(navCtrl) }) composable(route = "SystemManage"){ SystemManage(navCtrl) }
composable(route = "ManagedProfile", content = {ManagedProfile(navCtrl)}) composable(route = "ManagedProfile"){ ManagedProfile(navCtrl) }
composable(route = "Permissions", content = { DpmPermissions(navCtrl)}) composable(route = "Permissions"){ DpmPermissions(navCtrl) }
composable(route = "ApplicationManage", content = { ApplicationManage(navCtrl, pkgName, dialogStatus)}) composable(route = "ApplicationManage"){ ApplicationManage(navCtrl, pkgName, dialogStatus)}
composable(route = "UserRestriction", content = { UserRestriction(navCtrl)}) composable(route = "UserRestriction"){ UserRestriction(navCtrl) }
composable(route = "UserManage", content = { UserManage(navCtrl)}) composable(route = "UserManage"){ UserManage(navCtrl) }
composable(route = "Password", content = { Password(navCtrl)}) composable(route = "Password"){ Password(navCtrl) }
composable(route = "AppSetting", content = { AppSetting(navCtrl, materialYou, blackTheme)}) composable(route = "AppSetting"){ AppSetting(navCtrl, materialYou, blackTheme) }
composable(route = "Network", content = {Network(navCtrl)}) composable(route = "Network"){ Network(navCtrl) }
composable(route = "PackageSelector"){PackageSelector(navCtrl, pkgName)} composable(route = "PackageSelector"){ PackageSelector(navCtrl, pkgName) }
composable(route = "PermissionPicker"){PermissionPicker(navCtrl)} composable(route = "PermissionPicker"){ PermissionPicker(navCtrl) }
} }
LaunchedEffect(Unit){ LaunchedEffect(Unit){
val profileInited = sharedPref.getBoolean("ManagedProfileActivated",false) val profileInited = sharedPref.getBoolean("ManagedProfileActivated",false)

View File

@@ -5,18 +5,13 @@ import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build.VERSION import android.os.Build.VERSION
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
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
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -26,10 +21,7 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.*
import com.bintianqi.owndroid.ui.SubPageItem
import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.TopBar
@Composable @Composable
fun AppSetting(navCtrl:NavHostController, materialYou: MutableState<Boolean>, blackTheme: MutableState<Boolean>){ fun AppSetting(navCtrl:NavHostController, materialYou: MutableState<Boolean>, blackTheme: MutableState<Boolean>){
@@ -56,9 +48,10 @@ fun AppSetting(navCtrl:NavHostController, materialYou: MutableState<Boolean>, bl
popExitTransition = Animations.navHostPopExitTransition, popExitTransition = Animations.navHostPopExitTransition,
modifier = Modifier.padding(top = it.calculateTopPadding()) modifier = Modifier.padding(top = it.calculateTopPadding())
){ ){
composable(route = "Home"){Home(localNavCtrl)} composable(route = "Home"){ Home(localNavCtrl) }
composable(route = "Settings"){Settings(materialYou, blackTheme)} composable(route = "Theme"){ ThemeSettings(materialYou, blackTheme) }
composable(route = "About"){About()} composable(route = "Auth"){ AuthSettings() }
composable(route = "About"){ About() }
} }
} }
} }
@@ -66,13 +59,14 @@ fun AppSetting(navCtrl:NavHostController, materialYou: MutableState<Boolean>, bl
@Composable @Composable
private fun Home(navCtrl: NavHostController){ private fun Home(navCtrl: NavHostController){
Column(modifier = Modifier.fillMaxSize()){ Column(modifier = Modifier.fillMaxSize()){
SubPageItem(R.string.setting,"",R.drawable.settings_fill0){navCtrl.navigate("Settings")} SubPageItem(R.string.theme,"",R.drawable.format_paint_fill0){navCtrl.navigate("Theme")}
SubPageItem(R.string.security,"",R.drawable.lock_fill0){navCtrl.navigate("Auth")}
SubPageItem(R.string.about,"",R.drawable.info_fill0){navCtrl.navigate("About")} SubPageItem(R.string.about,"",R.drawable.info_fill0){navCtrl.navigate("About")}
} }
} }
@Composable @Composable
private fun Settings(materialYou:MutableState<Boolean>, blackTheme:MutableState<Boolean>){ private fun ThemeSettings(materialYou:MutableState<Boolean>, blackTheme:MutableState<Boolean>){
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE) val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
if(VERSION.SDK_INT>=31){ if(VERSION.SDK_INT>=31){
@@ -98,6 +92,39 @@ private fun Settings(materialYou:MutableState<Boolean>, blackTheme:MutableState<
} }
} }
@Composable
private fun AuthSettings(){
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
var auth by remember{ mutableStateOf(sharedPref.getBoolean("auth",false)) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
SwitchItem(
R.string.lock_owndroid, "", null,
{ auth },
{
sharedPref.edit().putBoolean("auth",it).apply()
auth = sharedPref.getBoolean("auth",false)
}
)
if(auth){
SwitchItem(
R.string.enable_bio_auth, "", null,
{ sharedPref.getBoolean("bio_auth",false) },
{ sharedPref.edit().putBoolean("bio_auth",it).apply() }
)
SwitchItem(
R.string.lock_in_background, "", null,
{ sharedPref.getBoolean("lock_in_background",false) },
{ sharedPref.edit().putBoolean("lock_in_background",it).apply() }
)
}
Box(modifier = Modifier.padding(horizontal = 8.dp)){
Information {
Text(text = stringResource(R.string.auth_on_start))
}
}
}
}
@Composable @Composable
private fun About(){ private fun About(){
val context = LocalContext.current val context = LocalContext.current

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="0.95"
android:toXScale="1.0"
android:fromYScale="0.95"
android:toYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="false"
android:duration="200" />
<alpha
android:duration="150"
android:fromAlpha="0.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toAlpha="1.0" />
</set>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="250"
android:fromAlpha="1.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toAlpha="0.0" />
</set>

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="M440,880q-33,0 -56.5,-23.5T360,800v-160L240,640q-33,0 -56.5,-23.5T160,560v-280q0,-66 47,-113t113,-47h480v440q0,33 -23.5,56.5T720,640L600,640v160q0,33 -23.5,56.5T520,880h-80ZM240,400h480v-200h-40v160h-80v-160h-40v80h-80v-80L320,200q-33,0 -56.5,23.5T240,280v120ZM240,560h480v-80L240,480v80ZM240,560v-80,80Z"
android:fillColor="#FF000000"/>
</vector>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/base"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>

View File

@@ -46,6 +46,7 @@
<string name="file_not_exist">文件不存在</string> <string name="file_not_exist">文件不存在</string>
<string name="io_exception">IO异常</string> <string name="io_exception">IO异常</string>
<string name="current_status_is">当前状态:</string> <string name="current_status_is">当前状态:</string>
<string name="start">开始</string>
<!--Permissions--> <!--Permissions-->
<string name="click_to_activate">点击以激活</string> <string name="click_to_activate">点击以激活</string>
@@ -478,9 +479,20 @@
<string name="about_desc">使用安卓的Device admin、Device owner、Profile owner全方位掌控你的设备</string> <string name="about_desc">使用安卓的Device admin、Device owner、Profile owner全方位掌控你的设备</string>
<string name="user_guide">使用教程</string> <string name="user_guide">使用教程</string>
<string name="source_code">源代码</string> <string name="source_code">源代码</string>
<string name="theme">主题</string>
<string name="amoled_black">纯黑夜间主题</string> <string name="amoled_black">纯黑夜间主题</string>
<string name="blackTheme_desc">需要打开夜间模式</string> <string name="blackTheme_desc">需要打开夜间模式</string>
<string name="security">安全</string>
<string name="lock_owndroid">锁定OwnDroid</string>
<string name="enable_bio_auth">使用生物识别</string>
<string name="authenticate">验证</string>
<string name="auth_on_start">在OwnDroid启动时使用锁屏密码或生物识别进行验证</string>
<string name="use_password">使用密码</string>
<string name="auth_with_password">使用密码进行验证</string>
<string name="auth_with_bio">使用生物识别进行验证</string>
<string name="lock_in_background">处于后台时锁定</string>
<!--AndroidPermission--> <!--AndroidPermission-->
<string name="permission_READ_EXTERNAL_STORAGE">读取外部存储</string> <string name="permission_READ_EXTERNAL_STORAGE">读取外部存储</string>
<string name="permission_WRITE_EXTERNAL_STORAGE">写入外部存储</string> <string name="permission_WRITE_EXTERNAL_STORAGE">写入外部存储</string>

View File

@@ -49,6 +49,7 @@
<string name="file_not_exist">File not exist</string> <string name="file_not_exist">File not exist</string>
<string name="io_exception">IO Exception</string> <string name="io_exception">IO Exception</string>
<string name="current_status_is">Current status:&#160;</string> <string name="current_status_is">Current status:&#160;</string>
<string name="start">Start</string>
<!--Permissions--> <!--Permissions-->
<string name="click_to_activate">Click to activate</string> <string name="click_to_activate">Click to activate</string>
@@ -493,9 +494,20 @@
<string name="about_desc">Use Device admin, Profile owner and Device owner privilege to take full control of your device. </string> <string name="about_desc">Use Device admin, Profile owner and Device owner privilege to take full control of your device. </string>
<string name="user_guide">User guide</string> <string name="user_guide">User guide</string>
<string name="source_code">Source code</string> <string name="source_code">Source code</string>
<string name="theme">Theme</string>
<string name="amoled_black">Black theme</string> <string name="amoled_black">Black theme</string>
<string name="blackTheme_desc">Require dark mode on</string> <string name="blackTheme_desc">Require dark mode on</string>
<string name="security">Security</string>
<string name="lock_owndroid">Lock OwnDroid</string>
<string name="enable_bio_auth">Auth with biometrics</string>
<string name="authenticate">Authenticate</string>
<string name="auth_on_start">Authenticating with keyguard password or biometrics when OwnDroid launch</string>
<string name="use_password">Use password</string>
<string name="auth_with_password">Authenticate OwnDroid with password</string>
<string name="auth_with_bio">Authenticate OwnDroid with biometrics</string>
<string name="lock_in_background">Lock when switch to background</string>
<!--AndroidPermission--> <!--AndroidPermission-->
<string name="permission_READ_EXTERNAL_STORAGE">Read external storage</string> <string name="permission_READ_EXTERNAL_STORAGE">Read external storage</string>
<string name="permission_WRITE_EXTERNAL_STORAGE">Write external storage</string> <string name="permission_WRITE_EXTERNAL_STORAGE">Write external storage</string>

View File

@@ -3,6 +3,5 @@
<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:navigationBarColor">#FFFFFF</item>
<item name="android:statusBarColor">#FFFFFF</item> <item name="android:statusBarColor">#FFFFFF</item>
<item name="android:windowSwipeToDismiss">true</item>
</style> </style>
</resources> </resources>

View File

@@ -7,6 +7,7 @@ navigation-compose = "2.7.7"
material3 = "1.2.1" material3 = "1.2.1"
accompanist-drawablepainter = "0.35.0-alpha" accompanist-drawablepainter = "0.35.0-alpha"
shizuku = "13.1.5" shizuku = "13.1.5"
biometric = "1.2.0-alpha05"
[libraries] [libraries]
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" }
@@ -16,6 +17,7 @@ androidx-ui-graphics = { module = "androidx.compose.ui:ui-graphics" }
androidx-ui = { module = "androidx.compose.ui:ui" } androidx-ui = { module = "androidx.compose.ui:ui" }
accompanist-drawablepainter = { module = "com.google.accompanist:accompanist-drawablepainter", version.ref = "accompanist-drawablepainter" } accompanist-drawablepainter = { module = "com.google.accompanist:accompanist-drawablepainter", version.ref = "accompanist-drawablepainter" }
androidx-biometric = { group = "androidx.biometric", name = "biometric", version.ref = "biometric" }
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" }