From 0b39bdc7883e6504c789bebfca1b3e6425593c8d Mon Sep 17 00:00:00 2001 From: BinTianqi Date: Thu, 20 Jun 2024 23:42:02 +0800 Subject: [PATCH 1/4] add TaskReceiver --- app/src/main/AndroidManifest.xml | 7 ++++ .../java/com/bintianqi/owndroid/Setting.kt | 19 ++++++++++ .../com/bintianqi/owndroid/TaskReceiver.kt | 38 +++++++++++++++++++ app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 5 files changed, 66 insertions(+) create mode 100644 app/src/main/java/com/bintianqi/owndroid/TaskReceiver.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 93b4c89..9c895ed 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -90,6 +90,13 @@ android:description="@string/app_name" android:permission="android.permission.BIND_DEVICE_ADMIN"> + + + + + , bl composable(route = "Home") { Home(localNavCtrl) } composable(route = "Theme") { ThemeSettings(materialYou, blackTheme) } composable(route = "Auth") { AuthSettings() } + composable(route = "Automation") { Automation() } composable(route = "About") { About() } } } @@ -53,6 +56,7 @@ private fun Home(navCtrl: NavHostController) { Column(modifier = Modifier.fillMaxSize()) { 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.automation, "", R.drawable.apps_fill0) { navCtrl.navigate("Automation") } SubPageItem(R.string.about, "", R.drawable.info_fill0) { navCtrl.navigate("About") } } } @@ -122,6 +126,21 @@ private fun AuthSettings() { } } +@Composable +private fun Automation() { + val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE) + Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { + var pkgName by remember { mutableStateOf("") } + LaunchedEffect(Unit) { + pkgName = sharedPref.getString("AutomationApp", "")?: "" + } + TextField(value = pkgName, onValueChange = { pkgName = it }, label = { Text("Package name")}) + Button(onClick = {sharedPref.edit().putString("AutomationApp", pkgName).apply()}) { + Text("apply") + } + } +} + @Composable private fun About() { val context = LocalContext.current diff --git a/app/src/main/java/com/bintianqi/owndroid/TaskReceiver.kt b/app/src/main/java/com/bintianqi/owndroid/TaskReceiver.kt new file mode 100644 index 0000000..ddf601b --- /dev/null +++ b/app/src/main/java/com/bintianqi/owndroid/TaskReceiver.kt @@ -0,0 +1,38 @@ +package com.bintianqi.owndroid + +import android.app.admin.DevicePolicyManager +import android.content.BroadcastReceiver +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.os.Build.VERSION +import android.util.Log +import androidx.activity.ComponentActivity + +class TaskReceiver: BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + Log.d("OwnDroid", ("TaskReceiver: pkgName: " + intent.component?.packageName)) + Log.d("OwnDroid", ("TaskReceiver: pkg: " + intent.`package`)) + val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE) + if(sharedPref.getString("AutomationApp", "") != intent.component?.packageName) return + val category = intent.getStringExtra("category") + if(category == "app") { + val action = intent.getStringExtra("action") + if(action == "suspend") { + val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager + val receiver = ComponentName(context,Receiver::class.java) + val app = intent.getStringExtra("app") + val mode = intent.getBooleanExtra("mode", false) + if(VERSION.SDK_INT >= 24) { + dpm.setPackagesSuspended(receiver, arrayOf(app), mode) + } else { + Log.d("OwnDroid", "unsupported") + } + } else { + Log.d("OwnDroid", "unknown action") + } + } else { + Log.d("OwnDroid", "unknown category") + } + } +} diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 05a71bb..585b315 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -535,6 +535,7 @@ 你不能清除OwnDroid的存储空间 清除存储空间 清除存储空间成功\n应用即将退出 + 自动化 读取外部存储 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index da159d2..21abef9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -551,6 +551,7 @@ You can\'t clear storage of OwnDroid Clear storage Clear storage success\nApplication will exit + Automation Read external storage From 015c5715469d0c964bbbc527c1a80b726ffd1b5a Mon Sep 17 00:00:00 2001 From: BinTianqi Date: Sat, 29 Jun 2024 10:59:36 +0800 Subject: [PATCH 2/4] automation: unsuspend app --- .github/workflows/build.yml | 1 + .../com/bintianqi/owndroid/TaskReceiver.kt | 30 ++++++------------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 01da48b..e50da26 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,6 +4,7 @@ on: push: paths-ignore: - '**.md' + branches: [ "master" ] jobs: build: diff --git a/app/src/main/java/com/bintianqi/owndroid/TaskReceiver.kt b/app/src/main/java/com/bintianqi/owndroid/TaskReceiver.kt index ddf601b..5e92e60 100644 --- a/app/src/main/java/com/bintianqi/owndroid/TaskReceiver.kt +++ b/app/src/main/java/com/bintianqi/owndroid/TaskReceiver.kt @@ -11,28 +11,16 @@ import androidx.activity.ComponentActivity class TaskReceiver: BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { - Log.d("OwnDroid", ("TaskReceiver: pkgName: " + intent.component?.packageName)) - Log.d("OwnDroid", ("TaskReceiver: pkg: " + intent.`package`)) - val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE) - if(sharedPref.getString("AutomationApp", "") != intent.component?.packageName) return - val category = intent.getStringExtra("category") - if(category == "app") { - val action = intent.getStringExtra("action") - if(action == "suspend") { - val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager - val receiver = ComponentName(context,Receiver::class.java) - val app = intent.getStringExtra("app") - val mode = intent.getBooleanExtra("mode", false) - if(VERSION.SDK_INT >= 24) { - dpm.setPackagesSuspended(receiver, arrayOf(app), mode) - } else { - Log.d("OwnDroid", "unsupported") - } - } else { - Log.d("OwnDroid", "unknown action") - } + val action = intent.getStringExtra("action") + val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager + val receiver = ComponentName(context,Receiver::class.java) + val app = intent.getStringExtra("app") + if(action == "suspend") { + dpm.setPackagesSuspended(receiver, arrayOf(app), true) + } else if(action == "unsuspend") { + dpm.setPackagesSuspended(receiver, arrayOf(app), false) } else { - Log.d("OwnDroid", "unknown category") + Log.d("OwnDroid", "unknown action") } } } From 172f7d081ea0e586dd3eac3f383f772af67be4ea Mon Sep 17 00:00:00 2001 From: BinTianqi Date: Tue, 2 Jul 2024 14:31:01 +0800 Subject: [PATCH 3/4] add AutomationActivity --- app/src/main/AndroidManifest.xml | 12 ++++- .../bintianqi/owndroid/AutomationActivity.kt | 25 +++++++++++ .../bintianqi/owndroid/AutomationReceiver.kt | 44 +++++++++++++++++++ .../java/com/bintianqi/owndroid/Setting.kt | 30 ++++++++++--- .../com/bintianqi/owndroid/TaskReceiver.kt | 26 ----------- app/src/main/res/values-zh-rCN/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + 7 files changed, 107 insertions(+), 34 deletions(-) create mode 100644 app/src/main/java/com/bintianqi/owndroid/AutomationActivity.kt create mode 100644 app/src/main/java/com/bintianqi/owndroid/AutomationReceiver.kt delete mode 100644 app/src/main/java/com/bintianqi/owndroid/TaskReceiver.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9c895ed..ee5b5f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -51,6 +51,16 @@ android:windowSoftInputMode="adjustResize|stateHidden" android:theme="@style/Theme.OwnDroid"> + + + + + diff --git a/app/src/main/java/com/bintianqi/owndroid/AutomationActivity.kt b/app/src/main/java/com/bintianqi/owndroid/AutomationActivity.kt new file mode 100644 index 0000000..464f93c --- /dev/null +++ b/app/src/main/java/com/bintianqi/owndroid/AutomationActivity.kt @@ -0,0 +1,25 @@ +package com.bintianqi.owndroid + +import android.content.Context +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.text.selection.SelectionContainer +import androidx.compose.material3.Text + +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 { + SelectionContainer { + Text(result) + } + } + } else { + finish() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bintianqi/owndroid/AutomationReceiver.kt b/app/src/main/java/com/bintianqi/owndroid/AutomationReceiver.kt new file mode 100644 index 0000000..a360199 --- /dev/null +++ b/app/src/main/java/com/bintianqi/owndroid/AutomationReceiver.kt @@ -0,0 +1,44 @@ +package com.bintianqi.owndroid + +import android.app.admin.DevicePolicyManager +import android.content.BroadcastReceiver +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.util.Log +import androidx.activity.ComponentActivity + +class AutomationReceiver: BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + handleTask(context, intent) + } +} + +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") + 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) + else -> return "Operation not defined" + } + } catch(e: Exception) { + return e.message ?: "Failed to get error message" + } + return "No error, or error is unhandled" +} diff --git a/app/src/main/java/com/bintianqi/owndroid/Setting.kt b/app/src/main/java/com/bintianqi/owndroid/Setting.kt index 43a0852..92f026e 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Setting.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Setting.kt @@ -4,6 +4,7 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.os.Build.VERSION +import android.widget.Toast import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState @@ -128,16 +129,31 @@ private fun AuthSettings() { @Composable private fun Automation() { - val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE) - Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { - var pkgName by remember { mutableStateOf("") } + val context = LocalContext.current + val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE) + Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) { + var key by remember { mutableStateOf("") } LaunchedEffect(Unit) { - pkgName = sharedPref.getString("AutomationApp", "")?: "" + key = sharedPref.getString("automation_key", "")?: "" } - TextField(value = pkgName, onValueChange = { pkgName = it }, label = { Text("Package name")}) - Button(onClick = {sharedPref.edit().putString("AutomationApp", pkgName).apply()}) { - Text("apply") + 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() } + ) } } diff --git a/app/src/main/java/com/bintianqi/owndroid/TaskReceiver.kt b/app/src/main/java/com/bintianqi/owndroid/TaskReceiver.kt deleted file mode 100644 index 5e92e60..0000000 --- a/app/src/main/java/com/bintianqi/owndroid/TaskReceiver.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.bintianqi.owndroid - -import android.app.admin.DevicePolicyManager -import android.content.BroadcastReceiver -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.os.Build.VERSION -import android.util.Log -import androidx.activity.ComponentActivity - -class TaskReceiver: BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - val action = intent.getStringExtra("action") - val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager - val receiver = ComponentName(context,Receiver::class.java) - val app = intent.getStringExtra("app") - if(action == "suspend") { - dpm.setPackagesSuspended(receiver, arrayOf(app), true) - } else if(action == "unsuspend") { - dpm.setPackagesSuspended(receiver, arrayOf(app), false) - } else { - Log.d("OwnDroid", "unknown action") - } - } -} diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 585b315..d9a0639 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -535,7 +535,9 @@ 你不能清除OwnDroid的存储空间 清除存储空间 清除存储空间成功\n应用即将退出 + 自动化 + 调试模式 读取外部存储 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 21abef9..9ff1e1a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -551,7 +551,9 @@ You can\'t clear storage of OwnDroid Clear storage Clear storage success\nApplication will exit + Automation + Debug mode Read external storage From 97cd7447e4c61f08cd7b19fd25bc5978cea1bb42 Mon Sep 17 00:00:00 2001 From: BinTianqi Date: Tue, 16 Jul 2024 21:15:12 +0800 Subject: [PATCH 4/4] update Automation API --- app/src/main/AndroidManifest.xml | 5 +++-- .../com/bintianqi/owndroid/AutomationActivity.kt | 12 +++++++----- .../com/bintianqi/owndroid/AutomationReceiver.kt | 6 +++++- app/src/main/java/com/bintianqi/owndroid/Setting.kt | 8 ++++---- app/src/main/res/values-zh-rCN/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- app/src/main/res/values/themes.xml | 2 +- 7 files changed, 22 insertions(+), 15 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ee5b5f3..3da0824 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,8 +55,9 @@ android:name=".AutomationActivity" android:exported="true" android:launchMode="singleInstance" + android:excludeFromRecents="true" android:windowSoftInputMode="adjustResize|stateHidden" - android:theme="@style/Theme.OwnDroid"> + android:theme="@style/Theme.Transparent"> @@ -67,7 +68,7 @@ android:windowSoftInputMode="adjustResize|stateHidden" android:excludeFromRecents="true" android:launchMode="singleInstance" - android:theme="@style/Theme.OwnDroidAppInstaller"> + android:theme="@style/Theme.Transparent"> diff --git a/app/src/main/java/com/bintianqi/owndroid/AutomationActivity.kt b/app/src/main/java/com/bintianqi/owndroid/AutomationActivity.kt index 464f93c..2245e64 100644 --- a/app/src/main/java/com/bintianqi/owndroid/AutomationActivity.kt +++ b/app/src/main/java/com/bintianqi/owndroid/AutomationActivity.kt @@ -1,11 +1,11 @@ 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.foundation.text.selection.SelectionContainer -import androidx.compose.material3.Text +import androidx.compose.ui.platform.LocalContext class AutomationActivity: ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -14,9 +14,11 @@ class AutomationActivity: ComponentActivity() { val sharedPrefs = applicationContext.getSharedPreferences("data", Context.MODE_PRIVATE) if(sharedPrefs.getBoolean("automation_debug", false)) { setContent { - SelectionContainer { - Text(result) - } + AlertDialog.Builder(LocalContext.current) + .setMessage(result) + .setOnDismissListener { finish() } + .setPositiveButton(R.string.confirm) { _, _ -> finish() } + .show() } } else { finish() diff --git a/app/src/main/java/com/bintianqi/owndroid/AutomationReceiver.kt b/app/src/main/java/com/bintianqi/owndroid/AutomationReceiver.kt index a360199..ee32652 100644 --- a/app/src/main/java/com/bintianqi/owndroid/AutomationReceiver.kt +++ b/app/src/main/java/com/bintianqi/owndroid/AutomationReceiver.kt @@ -1,11 +1,11 @@ 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 android.util.Log import androidx.activity.ComponentActivity class AutomationReceiver: BroadcastReceiver() { @@ -14,6 +14,7 @@ class AutomationReceiver: BroadcastReceiver() { } } +@SuppressLint("NewApi") fun handleTask(context: Context, intent: Intent): String { val sharedPrefs = context.getSharedPreferences("data", Context.MODE_PRIVATE) val key = sharedPrefs.getString("automation_key", "") ?: "" @@ -27,6 +28,7 @@ fun handleTask(context: Context, intent: Intent): String { 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) @@ -35,6 +37,8 @@ fun handleTask(context: Context, intent: Intent): String { "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) { diff --git a/app/src/main/java/com/bintianqi/owndroid/Setting.kt b/app/src/main/java/com/bintianqi/owndroid/Setting.kt index 92f026e..e0ed1bc 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Setting.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Setting.kt @@ -57,7 +57,7 @@ private fun Home(navCtrl: NavHostController) { Column(modifier = Modifier.fillMaxSize()) { 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.automation, "", R.drawable.apps_fill0) { navCtrl.navigate("Automation") } + SubPageItem(R.string.automation_api, "", R.drawable.apps_fill0) { navCtrl.navigate("Automation") } SubPageItem(R.string.about, "", R.drawable.info_fill0) { navCtrl.navigate("About") } } } @@ -132,10 +132,10 @@ 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("") } - LaunchedEffect(Unit) { - key = sharedPref.getString("automation_key", "")?: "" - } TextField( value = key, onValueChange = { key = it }, label = { Text("Key")}, modifier = Modifier.fillMaxWidth() diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index d9a0639..19c025d 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -536,7 +536,7 @@ 清除存储空间 清除存储空间成功\n应用即将退出 - 自动化 + 自动化API 调试模式 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9ff1e1a..b6573d3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -552,7 +552,7 @@ Clear storage Clear storage success\nApplication will exit - Automation + Automation API Debug mode diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 83f2a43..7ed11ac 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -4,7 +4,7 @@ #FFFFFF #FFFFFF -