Merge branch 'automation' into dev

This commit is contained in:
BinTianqi
2024-07-18 15:34:55 +08:00
8 changed files with 140 additions and 2 deletions

View File

@@ -4,6 +4,10 @@ on:
push: push:
paths-ignore: paths-ignore:
- '**.md' - '**.md'
tags-ignore:
- '**'
branches-ignore:
- 'master'
jobs: jobs:
build: build:

View File

@@ -52,13 +52,24 @@
android:windowSoftInputMode="adjustResize|stateHidden" android:windowSoftInputMode="adjustResize|stateHidden"
android:theme="@style/Theme.OwnDroid"> android:theme="@style/Theme.OwnDroid">
</activity> </activity>
<activity
android:name=".AutomationActivity"
android:exported="true"
android:launchMode="singleInstance"
android:excludeFromRecents="true"
android:windowSoftInputMode="adjustResize|stateHidden"
android:theme="@style/Theme.Transparent">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
<activity <activity
android:name=".InstallAppActivity" android:name=".InstallAppActivity"
android:exported="true" android:exported="true"
android:windowSoftInputMode="adjustResize|stateHidden" android:windowSoftInputMode="adjustResize|stateHidden"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:theme="@style/Theme.OwnDroidAppInstaller"> android:theme="@style/Theme.Transparent">
<intent-filter> <intent-filter>
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.VIEW"/>
@@ -95,6 +106,13 @@
android:name=".StopLockTaskModeReceiver" android:name=".StopLockTaskModeReceiver"
android:description="@string/app_name"> android:description="@string/app_name">
</receiver> </receiver>
<receiver
android:name=".AutomationReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
</receiver>
<provider <provider
android:name="rikka.shizuku.ShizukuProvider" android:name="rikka.shizuku.ShizukuProvider"
android:authorities="${applicationId}.shizuku" android:authorities="${applicationId}.shizuku"

View File

@@ -0,0 +1,27 @@
package com.bintianqi.owndroid
import android.app.AlertDialog
import android.content.Context
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.ui.platform.LocalContext
class AutomationActivity: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val result = handleTask(applicationContext, this.intent)
val sharedPrefs = applicationContext.getSharedPreferences("data", Context.MODE_PRIVATE)
if(sharedPrefs.getBoolean("automation_debug", false)) {
setContent {
AlertDialog.Builder(LocalContext.current)
.setMessage(result)
.setOnDismissListener { finish() }
.setPositiveButton(R.string.confirm) { _, _ -> finish() }
.show()
}
} else {
finish()
}
}
}

View File

@@ -0,0 +1,48 @@
package com.bintianqi.owndroid
import android.annotation.SuppressLint
import android.app.admin.DevicePolicyManager
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import androidx.activity.ComponentActivity
class AutomationReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
handleTask(context, intent)
}
}
@SuppressLint("NewApi")
fun handleTask(context: Context, intent: Intent): String {
val sharedPrefs = context.getSharedPreferences("data", Context.MODE_PRIVATE)
val key = sharedPrefs.getString("automation_key", "") ?: ""
if(key.length < 6) {
return "Key length must longer than 6"
}
if(key != intent.getStringExtra("key")) {
return "Wrong key"
}
val operation = intent.getStringExtra("operation")
val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val receiver = ComponentName(context,Receiver::class.java)
val app = intent.getStringExtra("app")
val restriction = intent.getStringExtra("restriction")
try {
when(operation) {
"suspend" -> dpm.setPackagesSuspended(receiver, arrayOf(app), true)
"unsuspend" -> dpm.setPackagesSuspended(receiver, arrayOf(app), false)
"hide" -> dpm.setApplicationHidden(receiver, app, true)
"unhide" -> dpm.setApplicationHidden(receiver, app, false)
"lock" -> dpm.lockNow()
"reboot" -> dpm.reboot(receiver)
"addUserRestriction" -> dpm.addUserRestriction(receiver, restriction)
"clearUserRestriction" -> dpm.clearUserRestriction(receiver, restriction)
else -> return "Operation not defined"
}
} catch(e: Exception) {
return e.message ?: "Failed to get error message"
}
return "No error, or error is unhandled"
}

View File

@@ -4,13 +4,16 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build.VERSION import android.os.Build.VERSION
import android.widget.Toast
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
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.material3.TextField
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@@ -43,6 +46,7 @@ fun AppSetting(navCtrl:NavHostController, materialYou: MutableState<Boolean>, bl
composable(route = "Home") { Home(localNavCtrl) } composable(route = "Home") { Home(localNavCtrl) }
composable(route = "Theme") { ThemeSettings(materialYou, blackTheme) } composable(route = "Theme") { ThemeSettings(materialYou, blackTheme) }
composable(route = "Auth") { AuthSettings() } composable(route = "Auth") { AuthSettings() }
composable(route = "Automation") { Automation() }
composable(route = "About") { About() } composable(route = "About") { About() }
} }
} }
@@ -53,6 +57,7 @@ private fun Home(navCtrl: NavHostController) {
Column(modifier = Modifier.fillMaxSize()) { Column(modifier = Modifier.fillMaxSize()) {
SubPageItem(R.string.theme, "", R.drawable.format_paint_fill0) { navCtrl.navigate("Theme") } 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.security, "", R.drawable.lock_fill0) { navCtrl.navigate("Auth") }
SubPageItem(R.string.automation_api, "", R.drawable.apps_fill0) { navCtrl.navigate("Automation") }
SubPageItem(R.string.about, "", R.drawable.info_fill0) { navCtrl.navigate("About") } SubPageItem(R.string.about, "", R.drawable.info_fill0) { navCtrl.navigate("About") }
} }
} }
@@ -122,6 +127,36 @@ private fun AuthSettings() {
} }
} }
@Composable
private fun Automation() {
val context = LocalContext.current
val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.automation_api), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
var key by remember { mutableStateOf("") }
TextField(
value = key, onValueChange = { key = it }, label = { Text("Key")},
modifier = Modifier.fillMaxWidth()
)
Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
sharedPref.edit().putString("automation_key", key).apply()
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
}
) {
Text(stringResource(R.string.apply))
}
SwitchItem(
R.string.automation_debug, "", null,
{ sharedPref.getBoolean("automation_debug", false) },
{ sharedPref.edit().putBoolean("automation_debug", it).apply() }
)
}
}
@Composable @Composable
private fun About() { private fun About() {
val context = LocalContext.current val context = LocalContext.current

View File

@@ -543,6 +543,9 @@
<string name="clear_storage">清除存储空间</string> <string name="clear_storage">清除存储空间</string>
<string name="clear_storage_success">清除存储空间成功\n应用即将退出</string> <string name="clear_storage_success">清除存储空间成功\n应用即将退出</string>
<string name="automation_api">自动化API</string>
<string name="automation_debug">调试模式</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

@@ -559,6 +559,9 @@
<string name="clear_storage">Clear storage</string> <string name="clear_storage">Clear storage</string>
<string name="clear_storage_success">Clear storage success\nApplication will exit</string> <string name="clear_storage_success">Clear storage success\nApplication will exit</string>
<string name="automation_api">Automation API</string>
<string name="automation_debug">Debug mode</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

@@ -4,7 +4,7 @@
<item name="android:navigationBarColor">#FFFFFF</item> <item name="android:navigationBarColor">#FFFFFF</item>
<item name="android:statusBarColor">#FFFFFF</item> <item name="android:statusBarColor">#FFFFFF</item>
</style> </style>
<style name="Theme.OwnDroidAppInstaller" parent="android:Theme.Material.Light.NoActionBar"> <style name="Theme.Transparent" parent="Theme.OwnDroid">
<item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item> <item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item> <item name="android:windowIsTranslucent">true</item>