mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 11:05:59 +00:00
Refactor code of API
Rename Automation API to API Add API section to READMEs
This commit is contained in:
18
Readme-en.md
18
Readme-en.md
@@ -43,6 +43,24 @@ Use Android Device owner privilege to manage your device.
|
|||||||
- Set screen timeout
|
- Set screen timeout
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
| ID | Description | Extras | Minimum Android version |
|
||||||
|
|:---------:|------------------|---------------------------------------|:-----------------------:|
|
||||||
|
| HIDE | Hide an app | `package`: package name of target app | |
|
||||||
|
| UNHIDE | Unhide an app | `package`: package name of target app | |
|
||||||
|
| SUSPEND | Suspend an app | `package`: package name of target app | 7 |
|
||||||
|
| UNSUSPEND | Unsuspend an app | `package`: package name of target app | 7 |
|
||||||
|
| LOCK | Lock screen | | |
|
||||||
|
|
||||||
|
Use this API in adb shell
|
||||||
|
```shell
|
||||||
|
am broadcast -a com.bintianqi.owndroid.action.<ID> -n com.bintianqi.owndroid/.ApiReceiver --es key <API_KEY>
|
||||||
|
# Example
|
||||||
|
am broadcast -a com.bintianqi.owndroid.action.HIDE -n com.bintianqi.owndroid/.ApiReceiver --es key abcdefg --es package com.example.app
|
||||||
|
```
|
||||||
|
If the return value is 0, the operation is successful.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[License.md](LICENSE.md)
|
[License.md](LICENSE.md)
|
||||||
|
|||||||
18
Readme.md
18
Readme.md
@@ -43,6 +43,24 @@
|
|||||||
- 设置屏幕超时
|
- 设置屏幕超时
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
| ID | 描述 | Extras | 最小安卓版本 |
|
||||||
|
|:---------:|----------|--------------------|:------:|
|
||||||
|
| HIDE | 隐藏一个应用 | `package`: 目标应用的包名 | |
|
||||||
|
| UNHIDE | 取消隐藏一个应用 | `package`: 目标应用的包名 | |
|
||||||
|
| SUSPEND | 挂起一个应用 | `package`: 目标应用的包名 | 7 |
|
||||||
|
| UNSUSPEND | 取消挂起一个应用 | `package`: 目标应用的包名 | 7 |
|
||||||
|
| LOCK | 锁屏 | | |
|
||||||
|
|
||||||
|
在adb shell中使用API
|
||||||
|
```shell
|
||||||
|
am broadcast -a com.bintianqi.owndroid.action.<ID> -n com.bintianqi.owndroid/.ApiReceiver --es key <API_KEY>
|
||||||
|
# 示例
|
||||||
|
am broadcast -a com.bintianqi.owndroid.action.HIDE -n com.bintianqi.owndroid/.ApiReceiver --es key abcdefg --es package com.example.app
|
||||||
|
```
|
||||||
|
如果返回值为0,操作成功
|
||||||
|
|
||||||
## 许可证
|
## 许可证
|
||||||
|
|
||||||
[License.md](LICENSE.md)
|
[License.md](LICENSE.md)
|
||||||
|
|||||||
@@ -52,17 +52,6 @@
|
|||||||
android:windowSoftInputMode="adjustResize|stateHidden"
|
android:windowSoftInputMode="adjustResize|stateHidden"
|
||||||
android:theme="@style/Theme.Transparent">
|
android:theme="@style/Theme.Transparent">
|
||||||
</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"
|
||||||
@@ -107,10 +96,14 @@
|
|||||||
android:description="@string/app_name">
|
android:description="@string/app_name">
|
||||||
</receiver>
|
</receiver>
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".AutomationReceiver"
|
android:name=".ApiReceiver"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="com.bintianqi.owndroid.action.HIDE"/>
|
||||||
|
<action android:name="com.bintianqi.owndroid.action.UNHIDE"/>
|
||||||
|
<action android:name="com.bintianqi.owndroid.action.SUSPEND"/>
|
||||||
|
<action android:name="com.bintianqi.owndroid.action.UNSUSPEND"/>
|
||||||
|
<action android:name="com.bintianqi.owndroid.action.LOCK"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<provider
|
<provider
|
||||||
|
|||||||
51
app/src/main/java/com/bintianqi/owndroid/ApiReceiver.kt
Normal file
51
app/src/main/java/com/bintianqi/owndroid/ApiReceiver.kt
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package com.bintianqi.owndroid
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
|
import com.bintianqi.owndroid.dpm.getDPM
|
||||||
|
import com.bintianqi.owndroid.dpm.getReceiver
|
||||||
|
|
||||||
|
class ApiReceiver: BroadcastReceiver() {
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
val sharedPrefs = context.getSharedPreferences("data", Context.MODE_PRIVATE)
|
||||||
|
if(sharedPrefs.getBoolean("enable_api", false)) return
|
||||||
|
val key = sharedPrefs.getString("api_key", null)
|
||||||
|
if(key != null && key == intent.getStringExtra("key")) {
|
||||||
|
val dpm = context.getDPM()
|
||||||
|
val receiver = context.getReceiver()
|
||||||
|
val app = intent.getStringExtra("package") ?: ""
|
||||||
|
try {
|
||||||
|
val ok = when(intent.action) {
|
||||||
|
"com.bintianqi.owndroid.action.HIDE" -> dpm.setApplicationHidden(receiver, app, true)
|
||||||
|
"com.bintianqi.owndroid.action.UNHIDE" -> dpm.setApplicationHidden(receiver, app, false)
|
||||||
|
"com.bintianqi.owndroid.action.SUSPEND" -> dpm.setPackagesSuspended(receiver, arrayOf(app), true).isEmpty()
|
||||||
|
"com.bintianqi.owndroid.action.UNSUSPEND" -> dpm.setPackagesSuspended(receiver, arrayOf(app), false).isEmpty()
|
||||||
|
"com.bintianqi.owndroid.action.LOCK" -> { dpm.lockNow(); true }
|
||||||
|
else -> {
|
||||||
|
Log.w(TAG, "Invalid action")
|
||||||
|
resultData = "Invalid action"
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!ok) resultCode = 1
|
||||||
|
} catch(e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
val message = (e::class.qualifiedName ?: "Exception") + ": " + (e.message ?: "")
|
||||||
|
Log.w(TAG, message)
|
||||||
|
resultCode = 1
|
||||||
|
resultData = message
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Unauthorized")
|
||||||
|
resultCode = 1
|
||||||
|
resultData = "Unauthorized"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "API"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package com.bintianqi.owndroid
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import com.bintianqi.owndroid.dpm.getDPM
|
|
||||||
import com.bintianqi.owndroid.dpm.getReceiver
|
|
||||||
|
|
||||||
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 == null || key != intent.getStringExtra("key")) {
|
|
||||||
return "Wrong key"
|
|
||||||
}
|
|
||||||
val operation = intent.getStringExtra("operation")
|
|
||||||
val dpm = context.getDPM()
|
|
||||||
val receiver = context.getReceiver()
|
|
||||||
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"
|
|
||||||
}
|
|
||||||
@@ -299,7 +299,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
|||||||
composable(route = "Options") { SettingsOptions(navCtrl) }
|
composable(route = "Options") { SettingsOptions(navCtrl) }
|
||||||
composable(route = "Appearance") { Appearance(navCtrl, vm) }
|
composable(route = "Appearance") { Appearance(navCtrl, vm) }
|
||||||
composable(route = "AuthSettings") { AuthSettings(navCtrl) }
|
composable(route = "AuthSettings") { AuthSettings(navCtrl) }
|
||||||
composable(route = "Automation") { Automation(navCtrl) }
|
composable(route = "ApiSettings") { ApiSettings(navCtrl) }
|
||||||
composable(route = "About") { About(navCtrl) }
|
composable(route = "About") { About(navCtrl) }
|
||||||
|
|
||||||
composable(route = "PackageSelector") { PackageSelector(navCtrl) }
|
composable(route = "PackageSelector") { PackageSelector(navCtrl) }
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class Receiver : DeviceAdminReceiver() {
|
|||||||
|
|
||||||
val installAppDone = MutableStateFlow(false)
|
val installAppDone = MutableStateFlow(false)
|
||||||
|
|
||||||
class PackageInstallerReceiver:BroadcastReceiver(){
|
class PackageInstallerReceiver: BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
val toastText = when(intent.getIntExtra(EXTRA_STATUS, 999)){
|
val toastText = when(intent.getIntExtra(EXTRA_STATUS, 999)){
|
||||||
STATUS_PENDING_USER_ACTION -> R.string.status_pending_action
|
STATUS_PENDING_USER_ACTION -> R.string.status_pending_action
|
||||||
|
|||||||
@@ -32,9 +32,11 @@ import androidx.compose.ui.res.painterResource
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.DpOffset
|
import androidx.compose.ui.unit.DpOffset
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.core.content.edit
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import com.bintianqi.owndroid.ui.FunctionItem
|
import com.bintianqi.owndroid.ui.FunctionItem
|
||||||
|
import com.bintianqi.owndroid.ui.InfoCard
|
||||||
import com.bintianqi.owndroid.ui.MyScaffold
|
import com.bintianqi.owndroid.ui.MyScaffold
|
||||||
import com.bintianqi.owndroid.ui.SwitchItem
|
import com.bintianqi.owndroid.ui.SwitchItem
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
@@ -45,7 +47,7 @@ fun Settings(navCtrl: NavHostController) {
|
|||||||
FunctionItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("Options") }
|
FunctionItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("Options") }
|
||||||
FunctionItem(R.string.appearance, "", R.drawable.format_paint_fill0) { navCtrl.navigate("Appearance") }
|
FunctionItem(R.string.appearance, "", R.drawable.format_paint_fill0) { navCtrl.navigate("Appearance") }
|
||||||
FunctionItem(R.string.security, "", R.drawable.lock_fill0) { navCtrl.navigate("AuthSettings") }
|
FunctionItem(R.string.security, "", R.drawable.lock_fill0) { navCtrl.navigate("AuthSettings") }
|
||||||
FunctionItem(R.string.automation_api, "", R.drawable.apps_fill0) { navCtrl.navigate("Automation") }
|
FunctionItem(R.string.api, "", R.drawable.apps_fill0) { navCtrl.navigate("ApiSettings") }
|
||||||
FunctionItem(R.string.about, "", R.drawable.info_fill0) { navCtrl.navigate("About") }
|
FunctionItem(R.string.about, "", R.drawable.info_fill0) { navCtrl.navigate("About") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,43 +156,46 @@ fun AuthSettings(navCtrl: NavHostController) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Automation(navCtrl: NavHostController) {
|
fun ApiSettings(navCtrl: NavHostController) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)
|
val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)
|
||||||
MyScaffold(R.string.automation_api, 8.dp, navCtrl) {
|
MyScaffold(R.string.api, 8.dp, navCtrl) {
|
||||||
Spacer(Modifier.padding(vertical = 5.dp))
|
var enabled by remember { mutableStateOf(sharedPref.getBoolean("enable_api", false)) }
|
||||||
var key by remember { mutableStateOf("") }
|
LaunchedEffect(enabled) {
|
||||||
OutlinedTextField(
|
sharedPref.edit {
|
||||||
value = key, onValueChange = { key = it }, label = { Text("Key")},
|
putBoolean("enable_api", enabled)
|
||||||
modifier = Modifier.fillMaxWidth(),
|
if(!enabled) remove("api_key")
|
||||||
trailingIcon = {
|
|
||||||
IconButton(
|
|
||||||
onClick = {
|
|
||||||
val charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
|
||||||
val sr = SecureRandom()
|
|
||||||
key = (1..20).map { charset[sr.nextInt(charset.length)] }.joinToString("")
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Icon(painter = painterResource(R.drawable.casino_fill0), contentDescription = "Random")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
|
||||||
Button(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
onClick = {
|
|
||||||
sharedPref.edit().putString("automation_key", key).apply()
|
|
||||||
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
|
|
||||||
},
|
|
||||||
enabled = key.length >= 20
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.apply))
|
|
||||||
}
|
}
|
||||||
SwitchItem(
|
SwitchItem(R.string.enable, "", null, enabled, { enabled = it }, padding = false)
|
||||||
R.string.automation_debug, "", null,
|
if(enabled) {
|
||||||
{ sharedPref.getBoolean("automation_debug", false) },
|
var key by remember { mutableStateOf("") }
|
||||||
{ sharedPref.edit().putBoolean("automation_debug", it).apply() },
|
OutlinedTextField(
|
||||||
padding = false
|
value = key, onValueChange = { key = it }, label = { Text(stringResource(R.string.api_key)) },
|
||||||
)
|
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp), readOnly = true,
|
||||||
|
trailingIcon = {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
val charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
|
val sr = SecureRandom()
|
||||||
|
key = (1..20).map { charset[sr.nextInt(charset.length)] }.joinToString("")
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(painter = painterResource(R.drawable.casino_fill0), contentDescription = "Random")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(bottom = 10.dp),
|
||||||
|
onClick = {
|
||||||
|
sharedPref.edit().putString("api_key", key).apply()
|
||||||
|
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.apply))
|
||||||
|
}
|
||||||
|
if(sharedPref.contains("api_key")) InfoCard(R.string.api_key_exist)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import java.text.SimpleDateFormat
|
|||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.time.format.FormatStyle
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@@ -143,7 +142,3 @@ fun parseTimestamp(timestamp: Long): String {
|
|||||||
|
|
||||||
val Long.humanReadableDate: String
|
val Long.humanReadableDate: String
|
||||||
get() = SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(Date(this))
|
get() = SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(Date(this))
|
||||||
|
|
||||||
val Long.humanReadableTime: String
|
|
||||||
get() = SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(Date(this))
|
|
||||||
|
|
||||||
|
|||||||
@@ -555,8 +555,9 @@
|
|||||||
<string name="lock_in_background">Блокировать при переключении в фоновый режим</string>
|
<string name="lock_in_background">Блокировать при переключении в фоновый режим</string>
|
||||||
<string name="clear_storage">Очистить хранилище</string>
|
<string name="clear_storage">Очистить хранилище</string>
|
||||||
|
|
||||||
<string name="automation_api">API автоматизации</string>
|
<!--TODO-->
|
||||||
<string name="automation_debug">Режим отладки</string>
|
<string name="api_key">API key</string>
|
||||||
|
<string name="api_key_exist">The API key already exists, setting a new key will overwrite the current key.</string>
|
||||||
|
|
||||||
<!--Разрешения Android-->
|
<!--Разрешения Android-->
|
||||||
<string name="permission_POST_NOTIFICATIONS">Отправлять уведомления</string>
|
<string name="permission_POST_NOTIFICATIONS">Отправлять уведомления</string>
|
||||||
|
|||||||
@@ -550,8 +550,9 @@
|
|||||||
<string name="lock_in_background">Arka plana geçince kilitle</string>
|
<string name="lock_in_background">Arka plana geçince kilitle</string>
|
||||||
<string name="clear_storage">Depolamayı temizle</string>
|
<string name="clear_storage">Depolamayı temizle</string>
|
||||||
|
|
||||||
<string name="automation_api">Automation API</string> <!--TODO-->
|
<!--TODO-->
|
||||||
<string name="automation_debug">Debug mode</string> <!--TODO-->
|
<string name="api_key">API key</string>
|
||||||
|
<string name="api_key_exist">The API key already exists, setting a new key will overwrite the current key.</string>
|
||||||
|
|
||||||
<!--AndroidPermission-->
|
<!--AndroidPermission-->
|
||||||
<string name="permission_POST_NOTIFICATIONS">Bildirim gönder</string>
|
<string name="permission_POST_NOTIFICATIONS">Bildirim gönder</string>
|
||||||
|
|||||||
@@ -540,8 +540,8 @@
|
|||||||
<string name="lock_in_background">处于后台时锁定</string>
|
<string name="lock_in_background">处于后台时锁定</string>
|
||||||
<string name="clear_storage">清除存储空间</string>
|
<string name="clear_storage">清除存储空间</string>
|
||||||
|
|
||||||
<string name="automation_api">自动化API</string>
|
<string name="api_key">API密钥</string>
|
||||||
<string name="automation_debug">调试模式</string>
|
<string name="api_key_exist">API密钥已存在,设置新的密钥将会覆盖当前密钥</string>
|
||||||
|
|
||||||
<!--AndroidPermission-->
|
<!--AndroidPermission-->
|
||||||
<string name="permission_POST_NOTIFICATIONS">发送通知</string>
|
<string name="permission_POST_NOTIFICATIONS">发送通知</string>
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
<string name="alias">Alias</string>
|
<string name="alias">Alias</string>
|
||||||
<string name="unknown_error">Unknown error</string>
|
<string name="unknown_error">Unknown error</string>
|
||||||
<string name="permission_denied">Permission denied</string>
|
<string name="permission_denied">Permission denied</string>
|
||||||
|
<string name="api" translatable="false">API</string>
|
||||||
|
|
||||||
<!--Permissions-->
|
<!--Permissions-->
|
||||||
<string name="click_to_activate">Click to activate</string>
|
<string name="click_to_activate">Click to activate</string>
|
||||||
@@ -553,9 +554,9 @@
|
|||||||
<string name="authenticate">Authenticate</string>
|
<string name="authenticate">Authenticate</string>
|
||||||
<string name="lock_in_background">Lock when switch to background</string>
|
<string name="lock_in_background">Lock when switch to background</string>
|
||||||
<string name="clear_storage">Clear storage</string>
|
<string name="clear_storage">Clear storage</string>
|
||||||
|
|
||||||
<string name="automation_api">Automation API</string>
|
<string name="api_key">API key</string>
|
||||||
<string name="automation_debug">Debug mode</string>
|
<string name="api_key_exist">The API key already exists, setting a new key will overwrite the current key.</string>
|
||||||
|
|
||||||
<!--AndroidPermission-->
|
<!--AndroidPermission-->
|
||||||
<string name="permission_POST_NOTIFICATIONS">Post notifications</string>
|
<string name="permission_POST_NOTIFICATIONS">Post notifications</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user