diff --git a/README.md b/README.md index d2537dcf..7478c8e2 100644 --- a/README.md +++ b/README.md @@ -131,26 +131,33 @@ AutoJs6 在 Auto.js 最终项目的基础上, 于 Dec 1, 2021 进行二次开发 [comment]: <> "Version history only shows last 3 versions" -# v6.3.4 +# v6.4.0 -###### 2023/10/03 +###### 2023/10/25 * `新增` ocr 模块支持 Paddle Lite 引擎 (by [TonyJiangWJ](https://github.com/TonyJiangWJ)) _[`pr #120`](http://pr.autojs6.com/120)_ -* `新增` WebSocket 模块 (参阅 项目文档 > [颜色类](https://docs.autojs6.com/#/webSocketType)) +* `新增` 打包功能支持内置插件与外部插件两种打包方式 (by [LZX284](https://github.com/LZX284)) _[`pr #151`](http://pr.autojs6.com/151)_ +* `新增` WebSocket 模块 (参阅 项目文档 > [WebSocket](https://docs.autojs6.com/#/webSocketType)) +* `新增` barcode / qrcode 模块 (参阅 项目文档 > [条码](https://docs.autojs6.com/#/barcode) / [二维码](https://docs.autojs6.com/#/qrcode)) +* `新增` shizuku 模块 (参阅 项目文档 > [Shizuku](https://docs.autojs6.com/#/shizuku)) * `新增` device.rotation / device.orientation 等方法 * `新增` 内部 Java 类支持 class 静态属性访问 +* `新增` 支持在安卓系统设置页面选择并切换应用语言 (安卓 13 及以上) +* `新增` 支持设置页面添加或长按应用图标激活 [应用快捷方式](https://developer.android.com/guide/topics/ui/shortcuts?hl=zh-cn) , 可启动文档和设置等页面 +* `修复` 重新合并部分 PR (by [aiselp](https://github.com/aiselp)) 以解决部分脚本无法正常结束运行的问题 _[`pr #75`](http://pr.autojs6.com/75)_ _[`pr #78`](http://pr.autojs6.com/78)_ +* `修复` 打包应用无法使用 AutoJs6 新增 API 的问题 (by [LZX284](https://github.com/LZX284)) _[`pr #151`](http://pr.autojs6.com/151)_ * `修复` VSCode 插件保存文件到本地时文件扩展名信息丢失的问题 * `修复` 使用协程特性运行项目产生未捕获异常致使应用崩溃的问题 * `修复` 重启或退出应用时浮动按钮无法记录其位置状态信息的问题 -* `修复` 设备屏幕方向改变时无法获取更新后的设备配置信息的问题 +* `修复` 设备屏幕方向改变时无法获取更新后的设备配置信息的问题 _[`issue #153`](http://issues.autojs6.com/153)_ * `修复` 屏幕旋转至横向时 Toolbar 标题字体过小的问题 * `修复` 屏幕旋转至横向时应用主页的页签排版过于拥挤的问题 * `修复` 屏幕旋转至横向时浮动按钮可能溢出屏幕的问题 _[`issue #90`](http://issues.autojs6.com/90)_ * `修复` 屏幕多次旋转时无法恢复浮动按钮的坐标及屏幕侧边方向的问题 +* `修复` 部分设备消息浮动框可能出现遗漏显示或重复显示的问题 * `修复` 消息浮动框在多个脚本同时运行时可能存在被遮蔽的问题 _[`issue #67`](http://issues.autojs6.com/67)_ * `修复` 使用广播分析布局时点击布局无法弹出菜单且导致应用崩溃的问题 * `修复` 第二次及以后创建的 WebSocket 实例均无法正常触发监听器的问题 -* `修复` 重新合并部分 PR (by [aiselp](https://github.com/aiselp)) 以解决部分脚本无法正常结束运行的问题 _[`pr #75`](http://pr.autojs6.com/75)_ _[`pr #78`](http://pr.autojs6.com/78)_ * `修复` 撤销 importPackage 的全局重定向方法以避免某些作用域下的包导入异常 _[`issue #88`](http://issues.autojs6.com/88)_ * `修复` 日志活动页面使用复制或导出功能时可能导致应用崩溃的问题 * `优化` 日志活动页面导出功能重命名为发送功能并重新实现符合实际意义的导出功能 @@ -158,6 +165,7 @@ AutoJs6 在 Auto.js 最终项目的基础上, 于 Dec 1, 2021 进行二次开发 * `优化` ocr 模块同时兼容 Google MLKit 及 Paddle Lite 引擎 (参阅 项目文档 > [光学字符识别](https://docs.autojs6.com/#/ocr?id=p-mode)) * `优化` 提升无障碍服务自动启动的成功概率 * `优化` 构建工具自适应 Java 发行版本以尽量避免 "无效的发行版本" 问题 +* `优化` 构建工具优化 IDE 及相关插件的版本退级逻辑并增加版本预测能力 * `优化` 部分 Kotlin 注解处理由 kapt 迁移至 KSP # v6.3.3 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5f6e6dc8..1331aa68 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,17 +2,30 @@ import com.android.build.gradle.internal.api.ApplicationVariantImpl import com.android.build.gradle.internal.api.BaseVariantOutputImpl +import org.gradle.kotlin.dsl.support.uppercaseFirstChar import org.jetbrains.kotlin.gradle.dsl.JvmTarget import java.io.FileInputStream import java.io.FileNotFoundException import java.text.SimpleDateFormat -import java.util.* +import java.util.Date +import java.util.Locale +import java.util.Properties +import java.util.TimeZone import java.util.zip.CRC32 +import kotlin.text.RegexOption.IGNORE_CASE val applicationId = "org.autojs.autojs6" val sign = Sign("$rootDir/sign.properties") val versions = Versions("$rootDir/version.properties") +val dimention = "channel" +val flavorNameApp = "app" +val flavorNameInrt = "inrt" +val buildTypeDebug = "debug" +val buildTypeRelease = "release" +val buildActionAssemble = "assemble" +val templateName = "template" + plugins { id("com.android.application") id("com.google.devtools.ksp") @@ -27,7 +40,7 @@ dependencies /* Unclassified */ { // Android supports implementation("androidx.cardview:cardview:1.0.0") implementation("androidx.multidex:multidex:2.0.1") - implementation("com.google.android.material:material:1.9.0") + implementation("com.google.android.material:material:1.10.0") // SwipeRefreshLayout implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") @@ -103,11 +116,8 @@ dependencies /* Unclassified */ { // Dex implementation(files("$rootDir/libs/com.android.dx-1.7.0.jar")) - // LocaleHelper - implementation(project(":libs:com.zeugmasolutions.localehelper-1.5.1")) - // OpenCV - implementation(project(":libs:org.opencv-4.5.5")) + implementation(project(":libs:org.opencv-4.8.0")) // PaddleOCR implementation(project(":libs:paddleocr")) @@ -132,9 +142,13 @@ dependencies /* Unclassified */ { implementation(files("$rootDir/libs/javamail-android/mail.jar")) // Shizuku - implementation("dev.rikka.shizuku:api:13.1.5") - implementation("dev.rikka.shizuku:provider:13.1.5") - implementation("org.lsposed.hiddenapibypass:hiddenapibypass:4.3@aar") + implementation(project(":libs:dev.rikka.shizuku-shared-13.1.5")) + implementation(project(":libs:dev.rikka.shizuku-aidl-13.1.5")) + implementation(project(":libs:dev.rikka.shizuku-api-13.1.5")) + implementation(project(":libs:dev.rikka.shizuku-provider-13.1.5")) + + // ARSCLib + implementation("io.github.reandroid:ARSCLib:1.2.4") } dependencies /* Test */ { @@ -159,12 +173,22 @@ dependencies /* Annotations */ { } dependencies /* AppCompat */ { - implementation("androidx.appcompat:appcompat") { - version { - strictly("1.4.2") - because("version 1.5.0 duplicates some classes") - } - } + // @Obsoleted by SuperMonster003 on Oct 5, 2023. + // ! Comment with related code will be removed since Jan 5, 2024. + // + // @Hint by SuperMonster003 on Oct 5, 2023. + // ! It look like that bugs below in version 1.5.x has gone away since 1.6.x. + // implementation("androidx.appcompat:appcompat") { + // version { + // strictly("1.4.2") + // because("version 1.5.0 duplicates some classes") + // } + // } + // + // @Hint by SuperMonster003 on Oct 5, 2023. + // ! To check the releases for Appcompat library, + // ! visit https://developer.android.com/jetpack/androidx/releases/appcompat + implementation("androidx.appcompat:appcompat:1.6.1") // AppCompat for legacy views (such as JsTextViewLegacy) implementation(project(":libs:androidx.appcompat-1.0.2")) { @@ -213,18 +237,13 @@ dependencies /* View */ { dependencies /* GitHub API */ { implementation(files("$rootDir/libs/github-api-1.306.jar")) - implementation("commons-io:commons-io") { - version { - strictly("2.8.0") - because("Exception on newer versions: 'NoClassDefFoundError: org.apache.commons.io.IOUtils'") - } - } + implementation("commons-io:commons-io:2.14.0") implementation("com.fasterxml.jackson.core:jackson-databind") { because("compatibility for Android API Level < 26 (Android 8.0) [O]") - version { - strictly("2.13.3") - because("Exception on 2.14.x: 'No virtual method getParameterCount()I in class Ljava/lang/reflect/Method'") + version /* as of Oct 12, 2023 */ { + strictly("2.14.3") + because("Exception on 2.15.x: 'IllegalArgumentException: Unsupported class file major version 63'") } } @@ -234,7 +253,11 @@ dependencies /* GitHub API */ { } dependencies /* MLKit */ { + // OCR implementation("com.google.mlkit:text-recognition-chinese:16.0.0") + + // Barcode + implementation("com.google.mlkit:barcode-scanning:17.2.0") } dependencies /* Auto.js Extensions */ { @@ -257,7 +280,7 @@ dependencies /* Auto.js Extensions */ { // Extracted from com.github.hyb1996:MutableTheme:1.0.0 // @Legacy com.jrummyapps:colorpicker:2.1.7 implementation("com.jaredrummler:colorpicker:1.1.0") - implementation("androidx.recyclerview:recyclerview:1.3.1") + implementation("androidx.recyclerview:recyclerview:1.3.2") implementation("com.github.ozodrukh:CircularReveal:2.0.1") } @@ -280,6 +303,7 @@ dependencies /* Reserved for auto append by IDE */ { } android { + namespace = applicationId compileSdk = versions.sdkVersionCompile @@ -288,45 +312,95 @@ android { minSdk = versions.sdkVersionMin targetSdk = versions.sdkVersionTarget testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - buildConfigField("boolean", "isInrt", "false") + multiDexEnabled = true + buildConfigField("boolean", "is${flavorNameInrt.uppercaseFirstChar()}", "false") } - flavorDimensions.add("channel") + flavorDimensions.add(dimention) + productFlavors { - create("app") { - dimension = "channel" + + create(flavorNameApp) { + dimension = dimention versionCode = versions.appVersionCode versionName = versions.appVersionName - buildConfigField("String", "CHANNEL", "\"app\"") - buildConfigField("boolean", "isInrt", "false") + buildConfigField("String", "CHANNEL", "\"$flavorNameApp\"") + buildConfigField("boolean", "is${flavorNameInrt.uppercaseFirstChar()}", "false") manifestPlaceholders.putAll( mapOf( - "CHANNEL" to "app", + "CHANNEL" to flavorNameApp, "appName" to "@string/app_name", "intentCategory" to "android.intent.category.LAUNCHER", "intentCategoryInrt" to "android.intent.category.DEFAULT", - "authorities" to "org.autojs.autojs6.fileprovider" + "authorities" to "org.autojs.autojs6.fileprovider", + "icon" to "@drawable/autojs6_material", ) ) } - create("inrt") { - dimension = "channel" - applicationIdSuffix = ".inrt" + create(flavorNameInrt) { + dimension = dimention + applicationIdSuffix = ".$flavorNameInrt" + minSdk = versions.sdkVersionMin + targetSdk = versions.sdkVersionTargetInrt + compileSdk = versions.sdkVersionCompile versionCode = versions.appVersionCode versionName = versions.appVersionName - buildConfigField("String", "CHANNEL", "\"inrt\"") - buildConfigField("boolean", "isInrt", "true") + buildConfigField("String", "CHANNEL", "\"$flavorNameInrt\"") + buildConfigField("boolean", "is${flavorNameInrt.uppercaseFirstChar()}", "true") manifestPlaceholders.putAll( mapOf( - "CHANNEL" to "inrt", - "appName" to "AutoJs6.inrt", + "CHANNEL" to flavorNameInrt, + "appName" to "AutoJs6.$flavorNameInrt", "intentCategory" to "android.intent.category.DEFAULT", "intentCategoryInrt" to "android.intent.category.LAUNCHER", - "authorities" to "org.autojs.autojs6.inrt.fileprovider" + "authorities" to "org.autojs.autojs6.$flavorNameInrt.fileprovider", + "icon" to "@mipmap/ic_launcher", ) ) + + gradle.taskGraph.whenReady(object : Action { + override fun execute(taskGraph: TaskExecutionGraph) { + val task = project.getTasksByName("${buildTypeRelease}InrtRelease", true).firstOrNull() ?: return + task.doLast { + copy { + val src = "build/outputs/apk/$flavorNameInrt/$buildTypeRelease" + val dst = "src/main/assets" + val ext = Utils.FILE_EXTENSION_APK + + if (!file(src).isDirectory) { + return@copy + } + + from(src); into(dst) + + val verName = versionName?.replace(Regex("\\s"), "-")?.lowercase() + val srcFileName = "$flavorNameInrt-v$verName-universal.$ext" /* e.g. inrt-v6.4.0-beta-universal.apk */ + val dstFileName = "$templateName.$ext" + val isOverridden = file(File(dst, dstFileName)).exists() + include(srcFileName) + rename(srcFileName, dstFileName) + println("Source: ${file(File(src, srcFileName))}") + println("Destination: ${file(File(dst, dstFileName))}${if (isOverridden) " [overridden]" else ""}") + } + } + } + }) } + + androidResources { + if (gradle.startParameter.taskNames.any { it.contains(Regex("^(:?$flavorNameApp:)?$buildActionAssemble")) }) { + ignoreAssetsPatterns.add(".idea") + } + if (gradle.startParameter.taskNames.any { it.contains(Regex("^(:?$flavorNameApp:)?$buildActionAssemble$flavorNameInrt", IGNORE_CASE)) }) { + // @Hint by SuperMonster003 on Oct 16, 2023. + // ! Nothing needs to be added into assets for flavor "inrt", + // ! as assets will be copied from flavor "app" + // ! while building an apk on org.autojs.autojs.ui.project.BuildActivity. + ignoreAssetsPatterns.add("!*") /* Ignore everything. */ + } + } + } compileOptions { @@ -337,8 +411,8 @@ android { // Utils.Version(ANDROID_GRADLE_PLUGIN_VERSION) < Utils.Version("8.0") - @Suppress("DEPRECATION") - packagingOptions { + // @Legacy packagingOptions { ... } + packaging { arrayOf( "META-INF/DEPENDENCIES", "META-INF/LICENSE", @@ -350,7 +424,12 @@ android { "META-INF/notice.*", "META-INF/ASL2.0", "META-INF/*.kotlin_module", + "lib/x86/libc++_shared.so", + "lib/x86_64/libc++_shared.so", + "lib/armeabi-v7a/libc++_shared.so", + "lib/arm64-v8a/libc++_shared.so", ).let { resources.pickFirsts.addAll(it) } + jniLibs { useLegacyPackaging = true } @@ -366,8 +445,8 @@ android { } signingConfigs { - takeIf { sign.isValid }?.let { - create("release") { + if (sign.isValid) { + create(buildTypeRelease) { storeFile = sign.properties["storeFile"]?.let { file(it as String) } keyPassword = sign.properties["keyPassword"] as String keyAlias = sign.properties["keyAlias"] as String @@ -382,23 +461,23 @@ android { "proguard-rules.pro", ) val niceSigningConfig = takeIf { sign.isValid }?.let { - signingConfigs.getByName("release") + signingConfigs.getByName(buildTypeRelease) } - getByName("release") { + getByName(buildTypeRelease) { isMinifyEnabled = false proguardFiles(*proguardFiles) niceSigningConfig?.let { signingConfig = it } } - getByName("debug") { - isMinifyEnabled = getByName("release").isMinifyEnabled + getByName(buildTypeDebug) { + isMinifyEnabled = getByName(buildTypeRelease).isMinifyEnabled proguardFiles(*proguardFiles) niceSigningConfig?.let { signingConfig = it } } } buildFeatures { + aidl = true viewBinding = true - // @Hint by SuperMonster003 on Aug 14, 2023. // ! Substitution of "android.defaults.buildfeatures.buildconfig=true" buildConfig = true @@ -459,6 +538,7 @@ android { isUniversalApk = true } } + } tasks { @@ -477,24 +557,30 @@ tasks { } register("appendDigestToReleasedFiles") { - val src = "release" - val dst = "${src}s" - val ext = Utils.FILE_EXTENSION_APK + listOf(flavorNameApp, flavorNameInrt).forEach { flavorName -> + val src = "$flavorName/$buildTypeRelease" + val dst = "${src}s" + val ext = Utils.FILE_EXTENSION_APK - from(src); into(dst); include("*.$ext") - - rename { name -> - Utils.digestCRC32(file("${src}/$name")).let { digest -> - name.replace("^(.+?)(\\.$ext)\$".toRegex(), "\$1-$digest\$2") + if (!file(src).isDirectory) { + return@forEach } - } - doLast { println("Destination: ${file(dst)}") } + from(src); into(dst); include("*.$ext") + + rename { name -> + Utils.digestCRC32(file("${src}/$name")).let { digest -> + name.replace("^(.+?)(\\.$ext)\$".toRegex(), "\$1-$digest\$2") + } + } + + doLast { println("Destination: ${file(dst)}") } + } } } extra { - versions.handleIfNeeded(project) + versions.handleIfNeeded(project, flavorNameApp, listOf(buildTypeDebug, buildTypeRelease)) } class Sign(filePath: String) { @@ -523,6 +609,7 @@ class Versions(filePath: String) { val sdkVersionMin = properties["MIN_SDK_VERSION"].let { it as String }.toInt() val sdkVersionTarget = properties["TARGET_SDK_VERSION"].let { it as String }.toInt() + val sdkVersionTargetInrt = properties["TARGET_SDK_VERSION_INRT"].let { it as String }.toInt() val sdkVersionCompile = properties["COMPILE_SDK_VERSION"].let { it as String }.toInt() val appVersionName = properties["VERSION_NAME"] as String val appVersionCode = properties["VERSION_BUILD"].let { it as String }.toInt() @@ -559,7 +646,6 @@ class Versions(filePath: String) { var versionInt = javaVersionRaw.toInt() while (versionInt > javaVersionMinSupported) { - @Suppress("EnumValuesSoftDeprecate") if (JvmTarget.values().any { it.name.contains(Regex("_$versionInt$")) }) { break } @@ -590,15 +676,14 @@ class Versions(filePath: String) { private var isBuildNumberAutoIncremented = false private val minBuildTimeGap = Utils.hours2Millis(0.75) - private val assembleTargets = mapOf("app" to listOf("debug", "release")) private val isBuildGapEnough get() = properties["BUILD_TIME"]?.let { Date().time - (it as String).toLong() > minBuildTimeGap } ?: false - private fun appendToTask(project: Project, buildType: String) { - project.tasks.getByName(Utils.getAssembleTaskName(buildType)).doLast { + private fun appendToTask(project: Project, flavorName: String, buildType: String) { + project.tasks.getByName(Utils.getAssembleTaskName(flavorName, buildType)).doLast { updateProperties() println() showInfo() @@ -618,7 +703,7 @@ class Versions(filePath: String) { val title = "Version information for AutoJs6 app library" val infoVerName = "Version name: $appVersionName" - val infoVerCode = "Version code: $appVersionCode${" [auto-incremented]".takeIf { isBuildNumberAutoIncremented } ?: ""}" + val infoVerCode = "Version code: ${if (isBuildNumberAutoIncremented) "${appVersionCode + 1} [auto-incremented]" else appVersionCode}" val infoVerSdk = "SDK versions: min [$sdkVersionMin] / target [$sdkVersionTarget] / compile [$sdkVersionCompile]" val infoVerJava = "Java version: $javaVersion$javaVersionInfoSuffix" @@ -637,21 +722,17 @@ class Versions(filePath: String) { ).forEach { println(it) } } - fun handleIfNeeded(project: Project) = assembleTargets.forEach { - val targetName = it.key - val targetBuildType = it.value - if (targetName == project.name) { - project.gradle.taskGraph.whenReady(object : Action { - override fun execute(taskGraph: TaskExecutionGraph) { - for (buildType in targetBuildType) { - if (taskGraph.hasTask(Utils.getAssembleFullTaskName(targetName, buildType))) { - return appendToTask(project, buildType) - } + fun handleIfNeeded(project: Project, flavorName: String, targetBuildType: List) { + project.gradle.taskGraph.whenReady(object : Action { + override fun execute(taskGraph: TaskExecutionGraph) { + for (buildType in targetBuildType) { + if (taskGraph.hasTask(Utils.getAssembleFullTaskName(project.name, flavorName, buildType))) { + return appendToTask(project, flavorName, buildType) } - return showInfo() } - }) - } + return showInfo() + } + }) } } @@ -676,9 +757,9 @@ object Utils { return "$autojs-v$version-$architecture.$extension".lowercase(Locale.getDefault()) } - fun getAssembleTaskName(buildType: String) = "assemble${capitalize(buildType)}" + fun getAssembleTaskName(flavorName: String, buildType: String) = "assemble${capitalize(flavorName)}${capitalize(buildType)}" - fun getAssembleFullTaskName(name: String, buildType: String) = ":$name:${getAssembleTaskName(buildType)}" + fun getAssembleFullTaskName(projectName: String, flavorName: String, buildType: String) = ":$projectName:${getAssembleTaskName(flavorName, buildType)}" fun digestCRC32(file: File): String { val fis = FileInputStream(file) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 60658c6f..cb10a9f2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -74,7 +74,9 @@ - + + + + tools:ignore="DataExtractionRules" + tools:targetApi="tiramisu"> + + + + + + + + - + @@ -562,14 +585,25 @@ android:multiprocess="false" android:permission="android.permission.INTERACT_ACROSS_USERS_FULL"/> + + + + + + @@ -577,15 +611,12 @@ - - - + android:name="rikka.shizuku.ShizukuProvider" + android:authorities="org.autojs.autojs6.shizuku" + android:enabled="true" + android:exported="true" + android:multiprocess="false" + android:permission="android.permission.INTERACT_ACROSS_USERS_FULL"/> \ No newline at end of file diff --git a/app/src/main/aidl/org/autojs/autojs/core/shizuku/IUserService.aidl b/app/src/main/aidl/org/autojs/autojs/core/shizuku/IUserService.aidl new file mode 100644 index 00000000..ace5800b --- /dev/null +++ b/app/src/main/aidl/org/autojs/autojs/core/shizuku/IUserService.aidl @@ -0,0 +1,11 @@ +package org.autojs.autojs.core.shizuku; + +interface IUserService { + + void destroy() = 16777114; // Destroy method defined by Shizuku server + + void exit() = 1; // Exit method defined by user + + String execCommand(String command) = 2; + +} \ No newline at end of file diff --git a/app/src/main/assets/doc/CHANGELOG.md b/app/src/main/assets/doc/CHANGELOG.md index a230157b..a94c6c45 100644 --- a/app/src/main/assets/doc/CHANGELOG.md +++ b/app/src/main/assets/doc/CHANGELOG.md @@ -4,26 +4,33 @@ ****** -# v6.3.4 +# v6.4.0 -###### 2023/10/03 +###### 2023/10/25 * `新增` ocr 模块支持 Paddle Lite 引擎 (by [TonyJiangWJ](https://github.com/TonyJiangWJ)) _[`pr #120`](http://pr.autojs6.com/120)_ -* `新增` WebSocket 模块 (参阅 项目文档 > [颜色类](https://docs.autojs6.com/#/webSocketType)) +* `新增` 打包功能支持内置插件与外部插件两种打包方式 (by [LZX284](https://github.com/LZX284)) _[`pr #151`](http://pr.autojs6.com/151)_ +* `新增` WebSocket 模块 (参阅 项目文档 > [WebSocket](https://docs.autojs6.com/#/webSocketType)) +* `新增` barcode / qrcode 模块 (参阅 项目文档 > [条码](https://docs.autojs6.com/#/barcode) / [二维码](https://docs.autojs6.com/#/qrcode)) +* `新增` shizuku 模块 (参阅 项目文档 > [Shizuku](https://docs.autojs6.com/#/shizuku)) * `新增` device.rotation / device.orientation 等方法 * `新增` 内部 Java 类支持 class 静态属性访问 +* `新增` 支持在安卓系统设置页面选择并切换应用语言 (安卓 13 及以上) +* `新增` 支持设置页面添加或长按应用图标激活 [应用快捷方式](https://developer.android.com/guide/topics/ui/shortcuts?hl=zh-cn) , 可启动文档和设置等页面 +* `修复` 重新合并部分 PR (by [aiselp](https://github.com/aiselp)) 以解决部分脚本无法正常结束运行的问题 _[`pr #75`](http://pr.autojs6.com/75)_ _[`pr #78`](http://pr.autojs6.com/78)_ +* `修复` 打包应用无法使用 AutoJs6 新增 API 的问题 (by [LZX284](https://github.com/LZX284)) _[`pr #151`](http://pr.autojs6.com/151)_ * `修复` VSCode 插件保存文件到本地时文件扩展名信息丢失的问题 * `修复` 使用协程特性运行项目产生未捕获异常致使应用崩溃的问题 * `修复` 重启或退出应用时浮动按钮无法记录其位置状态信息的问题 -* `修复` 设备屏幕方向改变时无法获取更新后的设备配置信息的问题 +* `修复` 设备屏幕方向改变时无法获取更新后的设备配置信息的问题 _[`issue #153`](http://issues.autojs6.com/153)_ * `修复` 屏幕旋转至横向时 Toolbar 标题字体过小的问题 * `修复` 屏幕旋转至横向时应用主页的页签排版过于拥挤的问题 * `修复` 屏幕旋转至横向时浮动按钮可能溢出屏幕的问题 _[`issue #90`](http://issues.autojs6.com/90)_ * `修复` 屏幕多次旋转时无法恢复浮动按钮的坐标及屏幕侧边方向的问题 +* `修复` 部分设备消息浮动框可能出现遗漏显示或重复显示的问题 * `修复` 消息浮动框在多个脚本同时运行时可能存在被遮蔽的问题 _[`issue #67`](http://issues.autojs6.com/67)_ * `修复` 使用广播分析布局时点击布局无法弹出菜单且导致应用崩溃的问题 * `修复` 第二次及以后创建的 WebSocket 实例均无法正常触发监听器的问题 -* `修复` 重新合并部分 PR (by [aiselp](https://github.com/aiselp)) 以解决部分脚本无法正常结束运行的问题 _[`pr #75`](http://pr.autojs6.com/75)_ _[`pr #78`](http://pr.autojs6.com/78)_ * `修复` 撤销 importPackage 的全局重定向方法以避免某些作用域下的包导入异常 _[`issue #88`](http://issues.autojs6.com/88)_ * `修复` 日志活动页面使用复制或导出功能时可能导致应用崩溃的问题 * `优化` 日志活动页面导出功能重命名为发送功能并重新实现符合实际意义的导出功能 @@ -31,17 +38,26 @@ * `优化` ocr 模块同时兼容 Google MLKit 及 Paddle Lite 引擎 (参阅 项目文档 > [光学字符识别](https://docs.autojs6.com/#/ocr?id=p-mode)) * `优化` 提升无障碍服务自动启动的成功概率 * `优化` 构建工具自适应 Java 发行版本以尽量避免 "无效的发行版本" 问题 +* `优化` 构建工具优化 IDE 及相关插件的版本退级逻辑并增加版本预测能力 * `优化` 部分 Kotlin 注解处理由 kapt 迁移至 KSP -* `优化` 附加 Rikka Shizuku 版本 13.1.5 -* `优化` 升级 Gradle Compile 版本 33 -> 34 -* `优化` 升级 Gradle 版本 8.3-rc-1 -> 8.4-rc-3 -* `优化` 升级 Apache Commons Lang3 版本 3.12.0 -> 3.13.0 -* `优化` 升级 Glide 版本 4.15.1 -> 4.16.0 -* `优化` 升级 Android Analytics 版本 14.3.0 -> 14.4.0 -* `优化` 升级 Androidx WebKit 版本 1.7.0 -> 1.8.0 -* `优化` 升级 Androidx Preference 版本 1.2.0 -> 1.2.1 -* `优化` 升级 Androidx Annotation 版本 1.6.0 -> 1.7.0 -* `优化` 升级 Androidx Recyclerview 版本 1.3.0 -> 1.3.1 +* `依赖` 附加 Rikka Shizuku 版本 13.1.5 +* `依赖` 附加 MLKit Barcode Scanning 版本 17.2.0 +* `依赖` 升级 OpenCV 版本 4.5.5 -> 4.8.0 (Ref to [TonyJiangWJ](https://github.com/TonyJiangWJ)) +* `依赖` 升级 Gradle Compile 版本 33 -> 34 +* `依赖` 升级 Gradle 版本 8.3-rc-1 -> 8.4-rc-3 +* `依赖` 升级 Apache Commons Lang3 版本 3.12.0 -> 3.13.0 +* `依赖` 升级 Glide 版本 4.15.1 -> 4.16.0 +* `依赖` 升级 Android Analytics 版本 14.3.0 -> 14.4.0 +* `依赖` 升级 Androidx AppCompat 版本 1.4.2 -> 1.6.0-alpha05 +* `依赖` 升级 Androidx WebKit 版本 1.7.0 -> 1.8.0 +* `依赖` 升级 Androidx Preference 版本 1.2.0 -> 1.2.1 +* `依赖` 升级 Androidx Annotation 版本 1.6.0 -> 1.7.0 +* `依赖` 升级 Androidx Recyclerview 版本 1.3.0 -> 1.3.2 +* `依赖` 升级 Android Material 版本 1.9.0 -> 1.10.0 +* `依赖` 升级 Androidx AppCompat 版本 1.4.2 -> 1.6.1 +* `依赖` 升级 Commons IO 版本 2.8.0 -> 2.14.0 +* `依赖` 升级 Jackson DataBind 版本 2.13.3 -> 2.14.3 +* `依赖` 移除 Zeugma Solutions LocaleHelper 版本 1.5.1 # v6.3.3 @@ -63,7 +79,7 @@ * `优化` 在 _[`pr #98`](http://pr.autojs6.com/98)_ 基础上添加代码注释菜单项 * `优化` 适配 VSCode 插件 1.0.6 * `优化` UiObject#parent 方法增加级数参数支持 (参阅 项目文档 > [控件节点](https://docs.autojs6.com/#/uiObjectType)) -* `优化` 升级 Gradle 版本 8.2 -> 8.3-rc-1 +* `依赖` 升级 Gradle 版本 8.2 -> 8.3-rc-1 # v6.3.2 @@ -97,9 +113,9 @@ * `优化` 增加短信数据读取权限 (android.permission.READ_SMS) (默认关闭) * `优化` findMultiColors 方法内部实现 (by [LYS86](https://github.com/LYS86)) _[`pr #72`](http://pr.autojs6.com/72)_ * `优化` runtime.loadDex/loadJar/load 支持按目录级别加载或同时加载多个文件 -* `优化` 升级 Leakcanary 版本 2.11 -> 2.12 -* `优化` 升级 Android Analytics 版本 14.2.0 -> 14.3.0 -* `优化` 升级 Gradle 版本 8.2-milestone-1 -> 8.2 +* `依赖` 升级 Leakcanary 版本 2.11 -> 2.12 +* `依赖` 升级 Android Analytics 版本 14.2.0 -> 14.3.0 +* `依赖` 升级 Gradle 版本 8.2-milestone-1 -> 8.2 # v6.3.1 @@ -131,11 +147,11 @@ * `优化` 视图 (View) 绑定方式由 ButterKnife 迁移至 View Binding _[`issue #48`](http://issues.autojs6.com/48)_ * `优化` 服务端模式非正常关闭时将于 AutoJs6 启动时自动开启 _[`issue #64`](http://issues.autojs6.com/64)_ * `优化` 客户端模式非正常关闭时将于 AutoJs6 启动时按最近一次的历史地址自动连接 -* `优化` 升级 Leakcanary 版本 2.10 -> 2.11 -* `优化` 升级 Android Material 版本 1.8.0 -> 1.9.0 -* `优化` 升级 Androidx WebKit 版本 1.6.1 -> 1.7.0 -* `优化` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.9 -> 5.0.0-alpha.11 -* `优化` 升级 MLKit Text Recognition Chinese 版本 16.0.0-beta6 -> 16.0.0 +* `依赖` 升级 Leakcanary 版本 2.10 -> 2.11 +* `依赖` 升级 Android Material 版本 1.8.0 -> 1.9.0 +* `依赖` 升级 Androidx WebKit 版本 1.6.1 -> 1.7.0 +* `依赖` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.9 -> 5.0.0-alpha.11 +* `依赖` 升级 MLKit Text Recognition Chinese 版本 16.0.0-beta6 -> 16.0.0 # v6.3.0 @@ -184,23 +200,23 @@ * `优化` http 模块相关方法支持超时参数 (timeout) * `优化` Gradle 构建脚本支持 JDK 版本主动降级 (fallback) * `优化` Gradle 构建脚本支持根据平台类型及版本自动选择合适的构建工具版本 (程度有限) -* `优化` 本地化 Auto.js APK Builder 版本 1.0.3 -* `优化` 本地化 MultiLevelListView 版本 1.1 -* `优化` 本地化 Settings Compat 版本 1.1.5 -* `优化` 本地化 Enhanced Floaty 版本 0.31 -* `优化` 附加 MLKit Text Recognition Chinese 版本 16.0.0-beta6 -* `优化` 升级 Gradle 版本 8.0-rc-1 -> 8.2-milestone-1 -* `优化` 升级 Android Material 版本 1.7.0 -> 1.8.0 -* `优化` 升级 Glide 版本 4.14.2 -> 4.15.1 -* `优化` 升级 Joda Time 版本 2.12.2 -> 2.12.5 -* `优化` 升级 Android Analytics 版本 14.0.0 -> 14.2.0 -* `优化` 升级 Androidx WebKit 版本 1.5.0 -> 1.6.1 -* `优化` 升级 Androidx Recyclerview 版本 1.2.1 -> 1.3.0 -* `优化` 升级 Zip4j 版本 2.11.2 -> 2.11.5 -* `优化` 升级 Junit 版本 5.9.2 -> 5.9.3 -* `优化` 升级 Androidx Annotation 版本 1.5.0 -> 1.6.0 -* `优化` 升级 Jackson DataBind 版本 2.14.1 -> 2.14.2 -* `优化` 升级 Desugar JDK Libs 版本 2.0.0 -> 2.0.3 +* `依赖` 本地化 Auto.js APK Builder 版本 1.0.3 +* `依赖` 本地化 MultiLevelListView 版本 1.1 +* `依赖` 本地化 Settings Compat 版本 1.1.5 +* `依赖` 本地化 Enhanced Floaty 版本 0.31 +* `依赖` 附加 MLKit Text Recognition Chinese 版本 16.0.0-beta6 +* `依赖` 升级 Gradle 版本 8.0-rc-1 -> 8.2-milestone-1 +* `依赖` 升级 Android Material 版本 1.7.0 -> 1.8.0 +* `依赖` 升级 Glide 版本 4.14.2 -> 4.15.1 +* `依赖` 升级 Joda Time 版本 2.12.2 -> 2.12.5 +* `依赖` 升级 Android Analytics 版本 14.0.0 -> 14.2.0 +* `依赖` 升级 Androidx WebKit 版本 1.5.0 -> 1.6.1 +* `依赖` 升级 Androidx Recyclerview 版本 1.2.1 -> 1.3.0 +* `依赖` 升级 Zip4j 版本 2.11.2 -> 2.11.5 +* `依赖` 升级 Junit 版本 5.9.2 -> 5.9.3 +* `依赖` 升级 Androidx Annotation 版本 1.5.0 -> 1.6.0 +* `依赖` 升级 Jackson DataBind 版本 2.14.1 -> 2.14.2 +* `依赖` 升级 Desugar JDK Libs 版本 2.0.0 -> 2.0.3 # v6.2.0 @@ -300,32 +316,32 @@ * `优化` 提升 console.show 显示的日志浮动窗口文字亮度以增强内容辨识度 * `优化` ImageWrapper#saveTo 支持相对路径保存图像文件 * `优化` 重新设计 colors 全局对象并增加 HSV / HSL 等色彩模式支持 (参阅 项目文档 > [颜色](https://docs.autojs6.com/#/color)) -* `优化` 升级 Gradle Compile 版本 32 -> 33 -* `优化` 本地化 Android Job 版本 1.4.3 -* `优化` 本地化 Android Plugin Client SDK For Locale 版本 9.0.0 -* `优化` 本地化 GitHub API 版本 1.306 -* `优化` 附加 JCIP Annotations 版本 1.0 -* `优化` 附加 Androidx WebKit 版本 1.5.0 -* `优化` 附加 Commons IO 版本 2.8.0 -* `优化` 附加 Desugar JDK Libs 版本 2.0.0 -* `优化` 附加 Jackson DataBind 版本 2.13.3 -* `优化` 附加 Jaredrummler Android Device Names 版本 2.1.0 -* `优化` 附加 Jaredrummler Animated SVG View 版本 1.0.6 -* `优化` 替换 Jrummyapps ColorPicker 版本 2.1.7 为 Jaredrummler ColorPicker 版本 1.1.0 -* `优化` 升级 Gradle 版本 7.5-rc-1 -> 8.0-rc-1 -* `优化` 升级 Gradle 构建工具版本 7.4.0-alpha02 -> 8.0.0-alpha09 -* `优化` 升级 Kotlin Gradle 插件版本 1.6.10 -> 1.8.0-RC2 -* `优化` 升级 Android Material 版本 1.6.0 -> 1.7.0 -* `优化` 升级 Androidx Annotation 版本 1.3.0 -> 1.5.0 -* `优化` 升级 Androidx AppCompat 版本 1.4.1 -> 1.4.2 -* `优化` 升级 Android Analytics 版本 13.3.0 -> 14.0.0 -* `优化` 升级 Gson 版本 2.9.0 -> 2.10 -* `优化` 升级 Joda Time 版本 2.10.14 -> 2.12.1 -* `优化` 升级 Kotlinx Coroutines 版本 1.6.1-native-mt -> 1.6.1 -* `优化` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.7 -> 5.0.0-alpha.9 -* `优化` 升级 Zip4j 版本 2.10.0 -> 2.11.2 -* `优化` 升级 Glide 版本 4.13.2 -> 4.14.2 -* `优化` 升级 Junit 版本 5.9.0 -> 5.9.1 +* `依赖` 升级 Gradle Compile 版本 32 -> 33 +* `依赖` 本地化 Android Job 版本 1.4.3 +* `依赖` 本地化 Android Plugin Client SDK For Locale 版本 9.0.0 +* `依赖` 本地化 GitHub API 版本 1.306 +* `依赖` 附加 JCIP Annotations 版本 1.0 +* `依赖` 附加 Androidx WebKit 版本 1.5.0 +* `依赖` 附加 Commons IO 版本 2.8.0 +* `依赖` 附加 Desugar JDK Libs 版本 2.0.0 +* `依赖` 附加 Jackson DataBind 版本 2.13.3 +* `依赖` 附加 Jaredrummler Android Device Names 版本 2.1.0 +* `依赖` 附加 Jaredrummler Animated SVG View 版本 1.0.6 +* `依赖` 替换 Jrummyapps ColorPicker 版本 2.1.7 为 Jaredrummler ColorPicker 版本 1.1.0 +* `依赖` 升级 Gradle 版本 7.5-rc-1 -> 8.0-rc-1 +* `依赖` 升级 Gradle 构建工具版本 7.4.0-alpha02 -> 8.0.0-alpha09 +* `依赖` 升级 Kotlin Gradle 插件版本 1.6.10 -> 1.8.0-RC2 +* `依赖` 升级 Android Material 版本 1.6.0 -> 1.7.0 +* `依赖` 升级 Androidx Annotation 版本 1.3.0 -> 1.5.0 +* `依赖` 升级 Androidx AppCompat 版本 1.4.1 -> 1.4.2 +* `依赖` 升级 Android Analytics 版本 13.3.0 -> 14.0.0 +* `依赖` 升级 Gson 版本 2.9.0 -> 2.10 +* `依赖` 升级 Joda Time 版本 2.10.14 -> 2.12.1 +* `依赖` 升级 Kotlinx Coroutines 版本 1.6.1-native-mt -> 1.6.1 +* `依赖` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.7 -> 5.0.0-alpha.9 +* `依赖` 升级 Zip4j 版本 2.10.0 -> 2.11.2 +* `依赖` 升级 Glide 版本 4.13.2 -> 4.14.2 +* `依赖` 升级 Junit 版本 5.9.0 -> 5.9.1 # v6.1.1 @@ -338,8 +354,8 @@ * `修复` 编辑器页面选项菜单中 "粘贴" 功能缺失的问题 * `优化` 部分异常消息字符串资源化 (en / zh) * `优化` 调整内容未保存对话框的按钮布局并增加颜色区分 -* `优化` 附加 github-api 版本 1.306 -* `优化` 替换 retrofit2-rxjava2-adapter 版本 1.0.0 为 adapter-rxjava2 版本 2.9.0 +* `依赖` 附加 github-api 版本 1.306 +* `依赖` 替换 retrofit2-rxjava2-adapter 版本 1.0.0 为 adapter-rxjava2 版本 2.9.0 # v6.1.0 @@ -385,22 +401,22 @@ * `优化` 外部存储读写权限适配高版本安卓系统 (API >= 30) * `优化` 控制台字体采用 Material Color 增强普通及夜间主题下的字体可读性 * `优化` 保存 ImageWrapper 所有实例弱引用并在脚本结束时自动回收 (实验性) -* `优化` 附加 CircleImageView 版本 3.1.0 -* `优化` 升级 Android Analytics 版本 13.1.0 -> 13.3.0 -* `优化` 升级 Gradle 构建工具版本 7.3.0-alpha06 -> 7.4.0-alpha02 -* `优化` 升级 Android Job 版本 1.4.2 -> 1.4.3 -* `优化` 升级 Android Material 版本 1.5.0 -> 1.6.0 -* `优化` 升级 CrashReport 版本 2.6.6 -> 4.0.4 -* `优化` 升级 Glide 版本 4.13.1 -> 4.13.2 -* `优化` 升级 Joda Time 版本 2.10.13 -> 2.10.14 -* `优化` 升级 Kotlin Gradle 插件版本 1.6.10 -> 1.6.21 -* `优化` 升级 Kotlinx Coroutines 版本 1.6.0 -> 1.6.1-native-mt -* `优化` 升级 Leakcanary 版本 2.8.1 -> 2.9.1 -* `优化` 升级 Okhttp3 版本 5.0.0-alpha.6 -> 5.0.0-alpha.7 -* `优化` 升级 Rhino 引擎版本 1.7.14 -> 1.7.15-snapshot -* `优化` 升级 Zip4j 版本 2.9.1 -> 2.10.0 -* `优化` 移除 Groovy JSON 版本 3.0.8 -* `优化` 移除 Kotlin Stdlib JDK7 版本 1.6.21 +* `依赖` 附加 CircleImageView 版本 3.1.0 +* `依赖` 升级 Android Analytics 版本 13.1.0 -> 13.3.0 +* `依赖` 升级 Gradle 构建工具版本 7.3.0-alpha06 -> 7.4.0-alpha02 +* `依赖` 升级 Android Job 版本 1.4.2 -> 1.4.3 +* `依赖` 升级 Android Material 版本 1.5.0 -> 1.6.0 +* `依赖` 升级 CrashReport 版本 2.6.6 -> 4.0.4 +* `依赖` 升级 Glide 版本 4.13.1 -> 4.13.2 +* `依赖` 升级 Joda Time 版本 2.10.13 -> 2.10.14 +* `依赖` 升级 Kotlin Gradle 插件版本 1.6.10 -> 1.6.21 +* `依赖` 升级 Kotlinx Coroutines 版本 1.6.0 -> 1.6.1-native-mt +* `依赖` 升级 Leakcanary 版本 2.8.1 -> 2.9.1 +* `依赖` 升级 Okhttp3 版本 5.0.0-alpha.6 -> 5.0.0-alpha.7 +* `依赖` 升级 Rhino 引擎版本 1.7.14 -> 1.7.15-snapshot +* `依赖` 升级 Zip4j 版本 2.9.1 -> 2.10.0 +* `依赖` 移除 Groovy JSON 版本 3.0.8 +* `依赖` 移除 Kotlin Stdlib JDK7 版本 1.6.21 # v6.0.3 @@ -423,17 +439,17 @@ * `优化` 浮动按钮初始化时同时应用透明度设置 (无需点击后再应用透明度) * `优化` 重置文件内容时增加是否为示例代码文件的检测并增加结果提示 * `优化` 转移打包插件下载地址 GitHub -> JsDelivr -* `优化` 附加 Zeugma Solutions LocaleHelper 版本 1.5.1 -* `优化` 降级 Android Material 版本 1.6.0-alpha02 -> 1.5.0 -* `优化` 升级 Kotlinx Coroutines 版本 1.6.0-native-mt -> 1.6.0 -* `优化` 升级 OpenCV 版本 3.4.3 -> 4.5.4 -> 4.5.5 (Ref to [TonyJiangWJ](https://github.com/TonyJiangWJ)) -* `优化` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.4 -> 5.0.0-alpha.6 -* `优化` 升级 Gradle 构建工具版本 7.2.0-beta01 -> 7.3.0-alpha06 -* `优化` 升级 Auto.js-ApkBuilder 版本 1.0.1 -> 1.0.3 -* `优化` 升级 Glide Compiler 版本 4.12.0 -> 4.13.1 -* `优化` 升级 Gradle 发行版本 7.4-rc-2 -> 7.4.1 -* `优化` 升级 Gradle Compile 版本 31 -> 32 -* `优化` 升级 Gson 版本 2.8.9 -> 2.9.0 +* `依赖` 附加 Zeugma Solutions LocaleHelper 版本 1.5.1 +* `依赖` 降级 Android Material 版本 1.6.0-alpha02 -> 1.5.0 +* `依赖` 升级 Kotlinx Coroutines 版本 1.6.0-native-mt -> 1.6.0 +* `依赖` 升级 OpenCV 版本 3.4.3 -> 4.5.4 -> 4.5.5 (Ref to [TonyJiangWJ](https://github.com/TonyJiangWJ)) +* `依赖` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.4 -> 5.0.0-alpha.6 +* `依赖` 升级 Gradle 构建工具版本 7.2.0-beta01 -> 7.3.0-alpha06 +* `依赖` 升级 Auto.js-ApkBuilder 版本 1.0.1 -> 1.0.3 +* `依赖` 升级 Glide Compiler 版本 4.12.0 -> 4.13.1 +* `依赖` 升级 Gradle 发行版本 7.4-rc-2 -> 7.4.1 +* `依赖` 升级 Gradle Compile 版本 31 -> 32 +* `依赖` 升级 Gson 版本 2.8.9 -> 2.9.0 # v6.0.2 @@ -446,14 +462,14 @@ * `修复` 客户端模式及服务端模式开关状态不能正常刷新的问题 * `修复` Android 7.x 解析 UI 模式 text 元素异常 (Ref to [TonyJiangWJ](https://github.com/TonyJiangWJ)) _[`issue #4`](http://issues.autojs6.com/4)_ _[`issue #9`](http://issues.autojs6.com/9)_ * `优化` 忽略 sleep() 的 ScriptInterruptedException 异常 -* `优化` 附加 Androidx AppCompat (Legacy) 版本 1.0.2 -* `优化` 升级 Androidx AppCompat 版本 1.4.0 -> 1.4.1 -* `优化` 升级 Androidx Preference 版本 1.1.1 -> 1.2.0 -* `优化` 升级 Rhino 引擎版本 1.7.14-snapshot -> 1.7.14 -* `优化` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.3 -> 5.0.0-alpha.4 -* `优化` 升级 Android Material 版本 1.6.0-alpha01 -> 1.6.0-alpha02 -* `优化` 升级 Gradle 构建工具版本 7.2.0-alpha06 -> 7.2.0-beta01 -* `优化` 升级 Gradle 发行版本 7.3.3 -> 7.4-rc-2 +* `依赖` 附加 Androidx AppCompat (Legacy) 版本 1.0.2 +* `依赖` 升级 Androidx AppCompat 版本 1.4.0 -> 1.4.1 +* `依赖` 升级 Androidx Preference 版本 1.1.1 -> 1.2.0 +* `依赖` 升级 Rhino 引擎版本 1.7.14-snapshot -> 1.7.14 +* `依赖` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.3 -> 5.0.0-alpha.4 +* `依赖` 升级 Android Material 版本 1.6.0-alpha01 -> 1.6.0-alpha02 +* `依赖` 升级 Gradle 构建工具版本 7.2.0-alpha06 -> 7.2.0-beta01 +* `依赖` 升级 Gradle 发行版本 7.3.3 -> 7.4-rc-2 # v6.0.1 @@ -467,11 +483,11 @@ * `优化` 扩展 global.sleep 支持 随机范围/负数兼容 * `优化` 扩展 global.toast 支持 时长控制/强制覆盖控制/dismiss * `优化` 包名对象全局化 (okhttp3/androidx/de) -* `优化` 升级 Android Material 版本 1.5.0-beta01 -> 1.6.0-alpha01 -* `优化` 升级 Gradle 构建工具版本 7.2.0-alpha04 -> 7.2.0-alpha06 -* `优化` 升级 Kotlinx Coroutines 版本 1.5.2-native-mt -> 1.6.0-native-mt -* `优化` 升级 Kotlin Gradle 插件版本 1.6.0 -> 1.6.10 -* `优化` 升级 Gradle 发行版本 7.3 -> 7.3.3 +* `依赖` 升级 Android Material 版本 1.5.0-beta01 -> 1.6.0-alpha01 +* `依赖` 升级 Gradle 构建工具版本 7.2.0-alpha04 -> 7.2.0-alpha06 +* `依赖` 升级 Kotlinx Coroutines 版本 1.5.2-native-mt -> 1.6.0-native-mt +* `依赖` 升级 Kotlin Gradle 插件版本 1.6.0 -> 1.6.10 +* `依赖` 升级 Gradle 发行版本 7.3 -> 7.3.3 # v6.0.0 @@ -499,39 +515,39 @@ * `优化` ResourceMonitor 使用 ReentrantLock 增强安全性 (Ref to [TonyJiangWJ](https://github.com/TonyJiangWJ)) * `优化` 使用 Maven Central 等仓库替换 JCenter 仓库 * `优化` 抽离并移除重复的本地库文件 -* `优化` 本地化 CrashReport 版本 2.6.6 -* `优化` 本地化 MutableTheme 版本 1.0.0 -* `优化` 附加 Androidx Preference 版本 1.1.1 -* `优化` 附加 SwipeRefreshLayout 版本 1.1.0 -* `优化` 升级 Android Analytics 版本 7.0.0 -> 13.1.0 -* `优化` 升级 Android Annotations 版本 4.5.2 -> 4.8.0 -* `优化` 升级 Gradle 构建工具版本 3.2.1 -> 4.1.0 -> 7.0.3 -> 7.2.0-alpha04 -* `优化` 升级 Android Job 版本 1.2.6 -> 1.4.2 -* `优化` 升级 Android Material 版本 1.1.0-alpha01 -> 1.5.0-beta01 -* `优化` 升级 Androidx MultiDex 版本 2.0.0 -> 2.0.1 -* `优化` 升级 Apache Commons Lang3 版本 3.6 -> 3.12.0 -* `优化` 升级 Appcompat 版本 1.0.2 -> 1.4.0 -* `优化` 升级 ButterKnife Gradle 插件版本 9.0.0-rc2 -> 10.2.1 -> 10.2.3 -* `优化` 升级 ColorPicker 版本 2.1.5 -> 2.1.7 -* `优化` 升级 Espresso Core 版本 3.1.1-alpha01 -> 3.5.0-alpha03 -* `优化` 升级 Eventbus 版本 3.0.0 -> 3.2.0 -* `优化` 升级 Glide Compiler 版本 4.8.0 -> 4.12.0 -> 4.12.0 -* `优化` 升级 Gradle Build Tool 版本 29.0.2 -> 30.0.2 -* `优化` 升级 Gradle Compile 版本 28 -> 30 -> 31 -* `优化` 升级 Gradle 发行版本 4.10.2 -> 6.5 -> 7.0.2 -> 7.3 -* `优化` 升级 Groovy-Json 插件版本 3.0.7 -> 3.0.8 -* `优化` 升级 Gson 版本 2.8.2 -> 2.8.9 -* `优化` 升级 JavaVersion 版本 1.8 -> 11 -> 16 -* `优化` 升级 Joda Time 版本 2.9.9 -> 2.10.13 -* `优化` 升级 Junit 版本 4.12 -> 4.13.2 -* `优化` 升级 Kotlin Gradle 插件版本 1.3.10 -> 1.4.10 -> 1.6.0 -* `优化` 升级 Kotlinx Coroutines 版本 1.0.1 -> 1.5.2-native-mt -* `优化` 升级 Leakcanary 版本 1.6.1 -> 2.7 -* `优化` 升级 LicensesDialog 版本 1.8.1 -> 2.2.0 -* `优化` 升级 Material Dialogs 版本 0.9.2.3 -> 0.9.6.0 -* `优化` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.2 -> 5.0.0-alpha.3 -* `优化` 升级 Reactivex RxJava2 RxAndroid 版本 2.0.1 -> 2.1.1 -* `优化` 升级 Reactivex RxJava2 版本 2.1.2 -> 2.2.21 -* `优化` 升级 Retrofit2 Converter Gson 版本 2.3.0 -> 2.9.0 -* `优化` 升级 Retrofit2 Retrofit 版本 2.3.0 -> 2.9.0 -* `优化` 升级 Zip4j 版本 1.3.2 -> 2.9.1 \ No newline at end of file +* `依赖` 本地化 CrashReport 版本 2.6.6 +* `依赖` 本地化 MutableTheme 版本 1.0.0 +* `依赖` 附加 Androidx Preference 版本 1.1.1 +* `依赖` 附加 SwipeRefreshLayout 版本 1.1.0 +* `依赖` 升级 Android Analytics 版本 7.0.0 -> 13.1.0 +* `依赖` 升级 Android Annotations 版本 4.5.2 -> 4.8.0 +* `依赖` 升级 Gradle 构建工具版本 3.2.1 -> 4.1.0 -> 7.0.3 -> 7.2.0-alpha04 +* `依赖` 升级 Android Job 版本 1.2.6 -> 1.4.2 +* `依赖` 升级 Android Material 版本 1.1.0-alpha01 -> 1.5.0-beta01 +* `依赖` 升级 Androidx MultiDex 版本 2.0.0 -> 2.0.1 +* `依赖` 升级 Apache Commons Lang3 版本 3.6 -> 3.12.0 +* `依赖` 升级 Appcompat 版本 1.0.2 -> 1.4.0 +* `依赖` 升级 ButterKnife Gradle 插件版本 9.0.0-rc2 -> 10.2.1 -> 10.2.3 +* `依赖` 升级 ColorPicker 版本 2.1.5 -> 2.1.7 +* `依赖` 升级 Espresso Core 版本 3.1.1-alpha01 -> 3.5.0-alpha03 +* `依赖` 升级 Eventbus 版本 3.0.0 -> 3.2.0 +* `依赖` 升级 Glide Compiler 版本 4.8.0 -> 4.12.0 -> 4.12.0 +* `依赖` 升级 Gradle Build Tool 版本 29.0.2 -> 30.0.2 +* `依赖` 升级 Gradle Compile 版本 28 -> 30 -> 31 +* `依赖` 升级 Gradle 发行版本 4.10.2 -> 6.5 -> 7.0.2 -> 7.3 +* `依赖` 升级 Groovy-Json 插件版本 3.0.7 -> 3.0.8 +* `依赖` 升级 Gson 版本 2.8.2 -> 2.8.9 +* `依赖` 升级 JavaVersion 版本 1.8 -> 11 -> 16 +* `依赖` 升级 Joda Time 版本 2.9.9 -> 2.10.13 +* `依赖` 升级 Junit 版本 4.12 -> 4.13.2 +* `依赖` 升级 Kotlin Gradle 插件版本 1.3.10 -> 1.4.10 -> 1.6.0 +* `依赖` 升级 Kotlinx Coroutines 版本 1.0.1 -> 1.5.2-native-mt +* `依赖` 升级 Leakcanary 版本 1.6.1 -> 2.7 +* `依赖` 升级 LicensesDialog 版本 1.8.1 -> 2.2.0 +* `依赖` 升级 Material Dialogs 版本 0.9.2.3 -> 0.9.6.0 +* `依赖` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.2 -> 5.0.0-alpha.3 +* `依赖` 升级 Reactivex RxJava2 RxAndroid 版本 2.0.1 -> 2.1.1 +* `依赖` 升级 Reactivex RxJava2 版本 2.1.2 -> 2.2.21 +* `依赖` 升级 Retrofit2 Converter Gson 版本 2.3.0 -> 2.9.0 +* `依赖` 升级 Retrofit2 Retrofit 版本 2.3.0 -> 2.9.0 +* `依赖` 升级 Zip4j 版本 1.3.2 -> 2.9.1 \ No newline at end of file diff --git a/app/src/main/assets/init.js b/app/src/main/assets/init.js index b34bbfd2..0c25a550 100644 --- a/app/src/main/assets/init.js +++ b/app/src/main/assets/init.js @@ -47,12 +47,16 @@ let ColorUtils = org.autojs.autojs.util.ColorUtils; let TextUtils = org.autojs.autojs.util.TextUtils; let ProxyObject = org.autojs.autojs.rhino.ProxyObject; let ProxyJavaObject = org.autojs.autojs.rhino.ProxyJavaObject; +let JavaScriptSource = org.autojs.autojs.script.JavaScriptSource; let NotificationManager = android.app.NotificationManager; let NotificationCompat = Packages.androidx.core.app.NotificationCompat; let SecurityException = java.lang.SecurityException; +let FileProvider = androidx.core.content.FileProvider; +let AppUtils = org.autojs.autojs.runtime.api.AppUtils; let Locale = java.util.Locale; let URI = java.net.URI; let File = java.io.File; +let Uri = android.net.Uri; /* Global View classes. */ @@ -492,13 +496,16 @@ Object.assign(this, { /* ! Numberx < Mathx */ [ 'plugins', 'Arrayx', 'Numberx', 'Mathx' ], - /* ! ocr < images */ - /* ! ocr < files */ - [ 'ocr' ], + /* ! images < ocr */ + /* ! images < barcode */ + /* ! images < qrcode */ + /* ! barcode < qrcode */ + /* ! files < ocr */ + [ 'ocr', 'barcode', 'qrcode' ], /* Safe to put last regardless of the order, no guarantee ;). */ [ 'floaty', 'storages', 'device', 'recorder', 'toast' ], - [ 'media', 'sensors', 'events', 'base64', 'notice' ], + [ 'media', 'sensors', 'events', 'base64', 'notice', 'shizuku' ], /* Last but not the least */ [ 'globals' ], diff --git a/app/src/main/assets/modules/__app__.js b/app/src/main/assets/modules/__app__.js index 1b9b7436..b427c78b 100644 --- a/app/src/main/assets/modules/__app__.js +++ b/app/src/main/assets/modules/__app__.js @@ -10,11 +10,7 @@ let { autojs, shell, files, util } = global; * @return {Internal.App} */ module.exports = function (scriptRuntime, scope) { - const File = java.io.File; - const Uri = android.net.Uri; const JavaInteger = java.lang.Integer; - const FileProvider = androidx.core.content.FileProvider; - const AppUtils = org.autojs.autojs.runtime.api.AppUtils; /** * @type {org.autojs.autojs.runtime.api.AppUtils} diff --git a/app/src/main/assets/modules/__barcode__.js b/app/src/main/assets/modules/__barcode__.js new file mode 100644 index 00000000..c27f14b9 --- /dev/null +++ b/app/src/main/assets/modules/__barcode__.js @@ -0,0 +1,146 @@ +// noinspection JSUnusedLocalSymbols,UnnecessaryLocalVariableJS + +/* Overwritten protection. */ + +let { images } = global; + +/** + * @param {ScriptRuntime} scriptRuntime + * @param {org.mozilla.javascript.Scriptable | global} scope + * @return {Internal.Barcode} + */ +module.exports = function (scriptRuntime, scope) { + + let _ = { + BarcodeCtor: (/* @IIFE */ () => { + const instanceFunc = function __(img, options) { + if (typeof arguments[0] === 'string') { + let image = images.read(/* path = */ arguments[0]); + if (image === null) { + throw TypeError(`Invalid image of path "${arguments[0]}" for barcode(img, options?)`); + } + let args = [ image.oneShot() ].concat(Array.from(arguments).slice(1)); + return BarcodeCtor.prototype.recognizeText.apply(BarcodeCtor.prototype, args); + } + return BarcodeCtor.prototype.recognizeText.apply(BarcodeCtor.prototype, arguments); + }; + + /** + * @implements Internal.Barcode + */ + const BarcodeCtor = function () { + let o = Object.assign(instanceFunc, BarcodeCtor.prototype); + Object.defineProperties(instanceFunc, Object.getOwnPropertyDescriptors(BarcodeCtor.prototype)); + return o; + }; + + BarcodeCtor.prototype = { + constructor: BarcodeCtor, + recognizeTexts() { + let results = this.detectAll.apply(this, arguments); + return results.map(result => result.getRawValue()).filter(o => o !== null); + }, + recognizeText() { + let results = this.recognizeTexts.apply(this, arguments); + if (_.shouldTakenAsAll(arguments)) { + return results; + } + return results.length > 0 ? results[0] : null; + }, + /** + * @returns {Internal.Barcode.Result[]} + */ + detectAll() { + if (typeof arguments[0] === 'string') { + + // @Signature + // detectAll(imgPath: string): Barcode.Result[]; + // detectAll(imgPath: string, options: DetectOptionsWithoutIsAll): Barcode.Result[]; + + let img = images.read(/* path = */ arguments[0]); + if (img === null) { + throw TypeError(`Invalid image of path "${arguments[0]}" for barcode.detectAll(img, options?)`); + } + // @Overload + // detectAll(img: ImageWrapper): Barcode.Result[]; + // detectAll(img: ImageWrapper, options: DetectOptionsWithoutIsAll): Barcode.Result[]; + return this.detectAll(img.oneShot(), arguments[1]); + } + + if (!(arguments[0] instanceof ImageWrapper)) { + + // @Signature detectAll(options?: DetectOptionsWithoutIsAll): Barcode.Result[]; + + // @Overload detectAll(img: ImageWrapper, options?: DetectOptionsWithoutIsAll): Barcode.Result[]; + return this.detectAll.apply(this, [ images.captureScreen() ].concat(Array.from(arguments))); + } + + // @Signature detectAll(img: ImageWrapper, options?: DetectOptionsWithoutIsAll): Barcode.Result[]; + + let img = arguments[0]; + /** @type {Internal.Barcode.DetectOptionsWithoutIsAll} */ + let opt = /* options */ arguments[1] || {}; + let formats = (() => { + if (isNullish(opt.format)) { + return []; + } + let results = Array.isArray(opt.format) ? opt.format : [ opt.format ]; + let transformer = { + FORMAT_QRCODE: 'FORMAT_QR_CODE', + }; + return results.map((result) => { + if (typeof result === 'number') { + return result; + } + if (typeof result === 'string') { + let tmp = result.toUpperCase().replace(/\W+/g, '_'); + let prefix = 'FORMAT_'; + if (!result.startsWith(prefix)) { + tmp = prefix + tmp; + } + if (tmp in transformer) { + tmp = transformer[tmp]; + } + return com.google.mlkit.vision.barcode.common.Barcode[tmp]; + } + throw TypeError(`Unknown format (value: ${result}, species: ${species(result)}) for barcode`); + }); + })(); + let enableAllPotentialBarcodes = Boolean(opt.enableAllPotentialBarcodes); + // noinspection JSValidateTypes + return scriptRuntime.barcode.detect(img, formats, enableAllPotentialBarcodes); + }, + detect() { + let results = this.detectAll.apply(this, arguments); + if (_.shouldTakenAsAll(arguments)) { + return results; + } + return results.length > 0 ? results[0] : null; + }, + }; + + return BarcodeCtor; + })(), + /** + * @param {IArguments} args + * @returns {boolean} + */ + shouldTakenAsAll(args) { + if (args.length === 0) { + return false; + } + /** + * @type {Internal.Barcode.DetectOptions | boolean | OmniRegion} + */ + let arg = args[args.length - 1]; + return arg === true || isObject(arg) && Boolean(arg.isAll); + }, + }; + + /** + * @type {Internal.Barcode} + */ + const barcode = new _.BarcodeCtor(); + + return barcode; +}; \ No newline at end of file diff --git a/app/src/main/assets/modules/__colors__.js b/app/src/main/assets/modules/__colors__.js index 26fa8cec..4ec20cc7 100644 --- a/app/src/main/assets/modules/__colors__.js +++ b/app/src/main/assets/modules/__colors__.js @@ -638,7 +638,7 @@ module.exports = function (scriptRuntime, scope) { if (alphaMatters === true) { return this.toInt(colorA) === this.toInt(colorB); } - throw TypeError(`Invalid argument isStrict (value: ${alphaMatters}, type: ${species(alphaMatters)}) for colors.isEqual`); + throw TypeError(`Invalid argument isStrict (value: ${alphaMatters}, species: ${species(alphaMatters)}) for colors.isEqual`); }, /** * Get a ColorStateList containing a single color or more. diff --git a/app/src/main/assets/modules/__engines__.js b/app/src/main/assets/modules/__engines__.js index e3915820..b8c8aaf5 100644 --- a/app/src/main/assets/modules/__engines__.js +++ b/app/src/main/assets/modules/__engines__.js @@ -71,7 +71,7 @@ module.exports = function (scriptRuntime, scope) { setEngineExecArgv() { engines.myEngine().setExecArgv(/* @IIFE */ ((e) => { let execArgv = {}; - let iterator = e.getTag(ExecutionConfig.CREATOR.getTag()).arguments.entrySet().iterator(); + let iterator = e.getTag(ExecutionConfig.tag).arguments.entrySet().iterator(); while (iterator.hasNext()) { let entry = iterator.next(); execArgv[entry.getKey()] = entry.getValue(); diff --git a/app/src/main/assets/modules/__images__.js b/app/src/main/assets/modules/__images__.js index 4dcb8119..a5a7be2d 100644 --- a/app/src/main/assets/modules/__images__.js +++ b/app/src/main/assets/modules/__images__.js @@ -49,6 +49,9 @@ module.exports = function (scriptRuntime, scope) { Images.prototype = { constructor: Images, captureScreen(path) { + if (rtImages.getScreenCapturer() === null) { + this.requestScreenCapture(); + } return path === undefined ? rtImages.captureScreen() : rtImages.captureScreen(path); diff --git a/app/src/main/assets/modules/__ocr__.js b/app/src/main/assets/modules/__ocr__.js index 6e405ca1..ca1d3ae3 100644 --- a/app/src/main/assets/modules/__ocr__.js +++ b/app/src/main/assets/modules/__ocr__.js @@ -40,7 +40,7 @@ module.exports = function (scriptRuntime, scope) { enumerable: true, /* Emphasis. */ }; - const instanceFunc = function (img, options) { + const instanceFunc = function __(img, options) { if (typeof arguments[0] === 'string') { let img = images.read(/* path = */ arguments[0]); if (img === null) { @@ -87,7 +87,7 @@ module.exports = function (scriptRuntime, scope) { // @Signature // recognizeText(imgPath: string, options?: DetectOptionsMLKit | DetectOptionsPaddle): string[]; - // recognizeText(imgPath: string, region: Images.Options.Region): string[]; + // recognizeText(imgPath: string, region: OmniRegion): string[]; let img = images.read(/* path = */ arguments[0]); if (img === null) { @@ -95,12 +95,25 @@ module.exports = function (scriptRuntime, scope) { } // @Overload // recognizeText(img: ImageWrapper, options?: DetectOptionsMLKit | DetectOptionsPaddle): string[]; - // recognizeText(img: ImageWrapper, region: Images.Options.Region): string[]; + // recognizeText(img: ImageWrapper, region: OmniRegion): string[]; return this.recognizeText(img.oneShot(), arguments[1]); } + + if (!(arguments[0] instanceof ImageWrapper)) { + + // @Signature + // recognizeText(options?: DetectOptionsMLKit | DetectOptionsPaddle): string[]; + // recognizeText(region: OmniRegion): string[]; + + // @Overload + // recognizeText(img: ImageWrapper, options?: DetectOptionsMLKit | DetectOptionsPaddle): string[]; + // recognizeText(img: ImageWrapper, region: OmniRegion): string[]; + return this.recognizeText.apply(this, [ images.captureScreen() ].concat(Array.from(arguments))); + } + if (_.shouldTakenAsRegion(arguments[1])) { - // @Signature recognizeText(img: ImageWrapper, region: Images.Options.Region): string[]; + // @Signature recognizeText(img: ImageWrapper, region: OmniRegion): string[]; // @Overload recognizeText(img: ImageWrapper, options: DetectOptionsMLKit | DetectOptionsPaddle): string[]; return this.recognizeText(img, { region: arguments[1] }); @@ -144,7 +157,7 @@ module.exports = function (scriptRuntime, scope) { // @Signature // detect(imgPath: string, options?: DetectOptionsMLKit | DetectOptionsPaddle): org.autojs.autojs.runtime.api.OcrResult[]; - // detect(imgPath: string, region: Images.Options.Region): org.autojs.autojs.runtime.api.OcrResult[]; + // detect(imgPath: string, region: OmniRegion): org.autojs.autojs.runtime.api.OcrResult[]; let img = images.read(/* path = */ arguments[0]); if (img === null) { @@ -152,12 +165,25 @@ module.exports = function (scriptRuntime, scope) { } // @Overload // detect(img: ImageWrapper, options?: DetectOptionsMLKit | DetectOptionsPaddle): org.autojs.autojs.runtime.api.OcrResult[]; - // detect(img: ImageWrapper, region: Images.Options.Region): org.autojs.autojs.runtime.api.OcrResult[]; + // detect(img: ImageWrapper, region: OmniRegion): org.autojs.autojs.runtime.api.OcrResult[]; return this.detect(img.oneShot(), arguments[1]); } + + if (!(arguments[0] instanceof ImageWrapper)) { + + // @Signature + // detect(options?: DetectOptionsMLKit | DetectOptionsPaddle): string[]; + // detect(region: OmniRegion): string[]; + + // @Overload + // detect(img: ImageWrapper, options?: DetectOptionsMLKit | DetectOptionsPaddle): string[]; + // detect(img: ImageWrapper, region: OmniRegion): string[]; + return this.detect.apply(this, [ images.captureScreen() ].concat(Array.from(arguments))); + } + if (_.shouldTakenAsRegion(arguments[1])) { - // @Signature detect(img: ImageWrapper, region: Images.Options.Region): org.autojs.autojs.runtime.api.OcrResult[]; + // @Signature detect(img: ImageWrapper, region: OmniRegion): org.autojs.autojs.runtime.api.OcrResult[]; // @Overload detect(img: ImageWrapper, options: DetectOptionsMLKit | DetectOptionsPaddle): org.autojs.autojs.runtime.api.OcrResult[]; return this.detect(img, { region: arguments[1] }); diff --git a/app/src/main/assets/modules/__qrcode__.js b/app/src/main/assets/modules/__qrcode__.js new file mode 100644 index 00000000..111c6b32 --- /dev/null +++ b/app/src/main/assets/modules/__qrcode__.js @@ -0,0 +1,121 @@ +// noinspection JSUnusedLocalSymbols,UnnecessaryLocalVariableJS + +/* Overwritten protection. */ + +let { images, qrcode } = global; + +/** + * @param {ScriptRuntime} scriptRuntime + * @param {org.mozilla.javascript.Scriptable | global} scope + * @return {Internal.QrCode} + */ +module.exports = function (scriptRuntime, scope) { + + let _ = { + QrCodeCtor: (/* @IIFE */ () => { + const instanceFunc = function __(img, options) { + if (typeof arguments[0] === 'string') { + let image = images.read(/* path = */ arguments[0]); + if (image === null) { + throw TypeError(`Invalid image of path "${arguments[0]}" for qrcode(img, options?)`); + } + let args = [ image.oneShot() ].concat(Array.from(arguments).slice(1)); + return QrCodeCtor.prototype.recognizeText.apply(QrCodeCtor.prototype, args); + } + return QrCodeCtor.prototype.recognizeText.apply(QrCodeCtor.prototype, arguments); + }; + + /** + * @implements Internal.QrCode + */ + const QrCodeCtor = function () { + let o = Object.assign(instanceFunc, QrCodeCtor.prototype); + Object.defineProperties(instanceFunc, Object.getOwnPropertyDescriptors(QrCodeCtor.prototype)); + return o; + }; + + QrCodeCtor.prototype = { + constructor: QrCodeCtor, + recognizeTexts() { + let results = this.detectAll.apply(this, arguments); + return results.map(result => result.getRawValue()).filter(o => o !== null); + }, + recognizeText() { + let results = this.recognizeTexts.apply(this, arguments); + if (_.shouldTakenAsAll(arguments)) { + return results; + } + return results.length > 0 ? results[0] : null; + }, + /** + * @returns {Internal.Barcode.Result[]} + */ + detectAll() { + if (typeof arguments[0] === 'string') { + + // @Signature + // detectAll(imgPath: string): QrCode.Result[]; + // detectAll(imgPath: string, options: DetectOptionsWithoutIsAll): QrCode.Result[]; + + let img = images.read(/* path = */ arguments[0]); + if (img === null) { + throw TypeError(`Invalid image of path "${arguments[0]}" for qrcode.detectAll(img, options?)`); + } + // @Overload + // detectAll(img: ImageWrapper): QrCode.Result[]; + // detectAll(img: ImageWrapper, options: DetectOptionsWithoutIsAll): QrCode.Result[]; + return this.detectAll(img.oneShot(), arguments[1]); + } + + if (!(arguments[0] instanceof ImageWrapper)) { + + // @Signature detectAll(options?: DetectOptionsWithoutIsAll): QrCode.Result[]; + + // @Overload detectAll(img: ImageWrapper, options?: DetectOptionsWithoutIsAll): QrCode.Result[]; + return this.detectAll.apply(this, [ images.captureScreen() ].concat(Array.from(arguments))); + } + + // @Signature detectAll(img: ImageWrapper, options?: DetectOptionsWithoutIsAll): QrCode.Result[]; + + let img = arguments[0]; + /** @type {Internal.QrCode.DetectOptionsWithoutIsAll} */ + let opt = /* options */ arguments[1] || {}; + let enableAllPotentialBarcodes = Boolean(opt.enableAllPotentialBarcodes); + let formats = [ com.google.mlkit.vision.barcode.common.Barcode.FORMAT_QR_CODE ]; + // noinspection JSValidateTypes + return scriptRuntime.barcode.detect(img, formats, enableAllPotentialBarcodes); + }, + detect() { + let results = this.detectAll.apply(this, arguments); + if (_.shouldTakenAsAll(arguments)) { + return results; + } + return results.length > 0 ? results[0] : null; + }, + }; + + return QrCodeCtor; + })(), + /** + * @param {IArguments} args + * @returns {boolean} + */ + shouldTakenAsAll(args) { + if (args.length === 0) { + return false; + } + /** + * @type {Internal.QrCode.DetectOptions | boolean | OmniRegion} + */ + let arg = args[args.length - 1]; + return arg === true || isObject(arg) && Boolean(arg.isAll); + }, + }; + + /** + * @type {Internal.QrCode} + */ + const qrcode = new _.QrCodeCtor(); + + return qrcode; +}; \ No newline at end of file diff --git a/app/src/main/assets/modules/__shizuku__.js b/app/src/main/assets/modules/__shizuku__.js new file mode 100644 index 00000000..498845b2 --- /dev/null +++ b/app/src/main/assets/modules/__shizuku__.js @@ -0,0 +1,45 @@ +// noinspection UnnecessaryLocalVariableJS,JSUnusedLocalSymbols + +/** + * @param {ScriptRuntime} scriptRuntime + * @param {org.mozilla.javascript.Scriptable | global} scope + * @return {Internal.Shizuku} + */ +module.exports = function (scriptRuntime, scope) { + + const rtShizuku = scriptRuntime.shizuku; + + let _ = { + ShizukuCtor: (/* @IIFE */ () => { + /** + * @implements Internal.Shizuku + */ + const ShizukuCtor = function () { + /** @global */ + const shizuku = function (cmd) { + return rtShizuku.execCommand(cmd); + }; + return Object.assign(shizuku, ShizukuCtor.prototype); + }; + + ShizukuCtor.prototype = { + constructor: ShizukuCtor, + ensureService() { + rtShizuku.ensureService(); + }, + execCommand() { + return rtShizuku.execCommand.apply(rtShizuku, arguments); + }, + }; + + return ShizukuCtor; + })(), + }; + + /** + * @type {Internal.Shizuku} + */ + const shizuku = new _.ShizukuCtor(); + + return shizuku; +}; \ No newline at end of file diff --git a/app/src/main/assets/modules/__toast__.js b/app/src/main/assets/modules/__toast__.js index 9d6d3dd8..f3e69624 100644 --- a/app/src/main/assets/modules/__toast__.js +++ b/app/src/main/assets/modules/__toast__.js @@ -1,86 +1,113 @@ -// noinspection UnnecessaryLocalVariableJS,JSUnusedLocalSymbols +// noinspection JSUnusedLocalSymbols,UnnecessaryLocalVariableJS /** - * @param {ScriptRuntime} scriptRuntime + * @param {org.autojs.autojs.runtime.ScriptRuntime} scriptRuntime * @param {org.mozilla.javascript.Scriptable | global} scope * @return {Internal.Toast} */ module.exports = function (scriptRuntime, scope) { - let rtToast = scriptRuntime.toast; + + const ScriptToast = org.autojs.autojs.runtime.api.ScriptToast; + let _ = { + uiHandler: runtime.getUiHandler(), ToastCtor: (/* @IIFE */ () => { /** * @implements Internal.Toast */ - const Ctor = function () { + const ToastCtor = function () { + // @Caution by SuperMonster003 on Oct 11, 2022. + // ! android.widget.Toast.makeText() doesn't work well on Android API Level 28 (Android 9) [P]. + // ! There hasn't been a solution for this so far. + // ! Tested devices: + // ! 1. SONY XPERIA XZ1 Compact (G8441) + // ! 2. Android Studio AVD (Android 9.0 x86) /** @global */ - const instance = function (msg, isLong, isForcible) { + const toast = function (msg, isLong, isForcible) { let $ = { badge: { long: /^l(ong)?$/i, short: /^s(hort)?$/i, forcible: /^f(orcible)?$/i, }, + toast() { + this.init(arguments); + this.show(); + }, init() { this.message = isNullish(msg) ? '' : String(msg); - this.isForcible = this.parseIsForcible(isForcible); this.isLong = this.parseIsLong(isLong); + this.isForcible = this.parseIsForcible(isForcible); }, - parseIsLong(isLong) { - if (typeof isLong === 'boolean') { - return isLong; + parseIsLong(o) { + let def = typeof this.isLong === 'boolean' ? this.isLong : false; + if (typeof o === 'boolean') { + return o; } - if (typeof isLong === 'number') { - return Boolean(isLong); + if (typeof o === 'number') { + return Boolean(o); } - if (typeof isLong === 'string') { - if (this.badge.long.test(isLong)) { + if (typeof o === 'string') { + if (this.badge.long.test(o)) { return true; } - if (this.badge.short.test(isLong)) { + if (this.badge.short.test(o)) { return false; } - if (this.badge.forcible.test(isLong)) { + if (this.badge.forcible.test(o)) { this.isForcible = true; - return false; + return def; } - throw Error(`Invalid param: {name: isLong, value: ${isLong}, type: ${species(isLong)}.`); + throw Error(`Invalid param: {name: isLong, value: ${o}, type: ${species(o)}.`); } - return false; + return def; }, - parseIsForcible(isForcible) { - if (typeof isForcible === 'boolean') { - return isForcible; + parseIsForcible(o) { + let def = typeof this.isForcible === 'boolean' ? this.isForcible : false; + if (typeof o === 'boolean') { + return o; } - if (typeof isForcible === 'number') { - return Boolean(isForcible); + if (typeof o === 'number') { + return Boolean(o); } - if (typeof isForcible === 'string') { - if (this.badge.forcible.test(isForcible)) { + if (typeof o === 'string') { + if (this.badge.forcible.test(o)) { return true; } - throw Error(`Invalid param: {name: isForcible, value: ${isForcible}, type: ${species(isForcible)}.`); + if (this.badge.long.test(o)) { + this.isLong = true; + return def; + } + if (this.badge.short.test(o)) { + this.isLong = false; + return def; + } + throw Error(`Invalid param: {name: isForcible, value: ${o}, type: ${species(o)}.`); } - return false; + return def; }, - makeToast() { - rtToast.makeToast(this.message, this.isLong, this.isForcible); + show() { + if ($.isForcible) { + ToastCtor.prototype.dismissAll(); + } + scriptRuntime.uiHandler.toast($.message, $.isLong); }, }; - $.init(); - $.makeToast(); + $.toast(); }; - return Object.assign(instance, Ctor.prototype); + return Object.assign(toast, ToastCtor.prototype); }; - Ctor.prototype = { - constructor: Ctor, - dismissAll: () => rtToast.dismissAll(), + ToastCtor.prototype = { + constructor: ToastCtor, + dismissAll() { + runtime.uiHandler.dismissAllToasts(); + }, }; - return Ctor; + return ToastCtor; })(), }; diff --git a/app/src/main/assets/modules/__ui__.js b/app/src/main/assets/modules/__ui__.js index ff284d99..5439203c 100644 --- a/app/src/main/assets/modules/__ui__.js +++ b/app/src/main/assets/modules/__ui__.js @@ -317,7 +317,7 @@ module.exports = function (scriptRuntime, scope) { })(); }, afterApplyAttribute(context, inflater, view, ns, attrName, value, parent) { - // Empty method body + /* Empty body. */ }, afterApplyAttributes(context, view, inflater, attrs, parent) { context.remove('widget'); @@ -326,13 +326,13 @@ module.exports = function (scriptRuntime, scope) { return false; }, afterInflateChildren(context, inflater, node, parent) { - // Empty method body + /* Empty body. */ }, beforeApplyPendingAttributesOfChildren(context, inflater, view) { return false; }, afterApplyPendingAttributesOfChildren(context, inflater, view) { - // Empty method body + /* Empty body. */ }, afterInflateView(context, view, node, parent, attachToParent) { let { widget } = view; diff --git a/app/src/main/assets/modules/ocr-mlkit.js b/app/src/main/assets/modules/ocr-mlkit.js index f6319d4b..41c3c84d 100644 --- a/app/src/main/assets/modules/ocr-mlkit.js +++ b/app/src/main/assets/modules/ocr-mlkit.js @@ -15,12 +15,16 @@ module.exports = function (scriptRuntime, scope) { * @implements Internal.OcrMLKit */ const OcrMLKitCtor = function () { - return Object.assign(function () { + let instanceFunc = function __() { let argArray = Array.from(arguments); + if (arguments.length === 0 || !(arguments[0] instanceof ImageWrapper)) { + return __.apply(this, [ images.captureScreen() ].concat(argArray)); + } /** @type {Internal.Ocr.ModeName} */ argArray[ocr['_forcibleModeArgIndex']] = ocr['_modeName']['mlkit']; return ocr.recognizeText.apply(ocr, argArray); - }, OcrMLKitCtor.prototype); + }; + return Object.assign(instanceFunc, OcrMLKitCtor.prototype); }; OcrMLKitCtor.prototype = { diff --git a/app/src/main/assets/modules/ocr-paddle.js b/app/src/main/assets/modules/ocr-paddle.js index b9b75d11..8a373b64 100644 --- a/app/src/main/assets/modules/ocr-paddle.js +++ b/app/src/main/assets/modules/ocr-paddle.js @@ -15,12 +15,16 @@ module.exports = function (scriptRuntime, scope) { * @implements Internal.OcrPaddle */ const OcrPaddleCtor = function () { - return Object.assign(function () { + const instanceFunc = function __() { let argArray = Array.from(arguments); + if (arguments.length === 0 || !(arguments[0] instanceof ImageWrapper)) { + return __.apply(this, [ images.captureScreen() ].concat(argArray)); + } /** @type {Internal.Ocr.ModeName} */ argArray[ocr['_forcibleModeArgIndex']] = ocr['_modeName']['paddle']; return ocr.recognizeText.apply(ocr, argArray); - }, OcrPaddleCtor.prototype); + }; + return Object.assign(instanceFunc, OcrPaddleCtor.prototype); }; OcrPaddleCtor.prototype = { diff --git a/app/src/main/assets/sample/测试/基本功能测试 (main) [v6.3.1+].js b/app/src/main/assets/sample/测试/基本功能测试 (main) [v6.3.1+].js index 9baac0e4..30243124 100644 --- a/app/src/main/assets/sample/测试/基本功能测试 (main) [v6.3.1+].js +++ b/app/src/main/assets/sample/测试/基本功能测试 (main) [v6.3.1+].js @@ -147,11 +147,11 @@ assert(util.getClass(java.lang.String) === java.lang.String, 'util.getClass()'); assert(util.getClassName(java.lang.String) === 'java.lang.String', 'util.getClassName()'); assert(isFunc(new (function () { let C = function () { - // Empty constructor + /* Empty body. */ }; util.extend(C, (function () { let P = function () { - // Empty constructor + /* Empty body. */ }; P.prototype.getName = () => context.packageName; return P; diff --git a/app/src/main/java/org/autojs/autojs/AbstractAutoJs.kt b/app/src/main/java/org/autojs/autojs/AbstractAutoJs.kt index d839fd77..eae1c215 100644 --- a/app/src/main/java/org/autojs/autojs/AbstractAutoJs.kt +++ b/app/src/main/java/org/autojs/autojs/AbstractAutoJs.kt @@ -20,7 +20,7 @@ import org.autojs.autojs.engine.RootAutomatorEngine import org.autojs.autojs.engine.ScriptEngineManager import org.autojs.autojs.engine.ScriptEngineService import org.autojs.autojs.engine.ScriptEngineServiceBuilder -import org.autojs.autojs.inrt.autojs.XJavaScriptEngine +import org.autojs.autojs.inrt.autojs.LoopBasedJavaScriptEngineWithDecryption import org.autojs.autojs.pref.Pref.registerOnSharedPreferenceChangeListener import org.autojs.autojs.rhino.InterruptibleAndroidContextFactory import org.autojs.autojs.runtime.ScriptRuntime @@ -35,6 +35,7 @@ import org.autojs.autojs.util.ResourceMonitor import org.autojs.autojs.util.ResourceMonitor.UnclosedResourceException import org.autojs.autojs.util.StringUtils import org.autojs.autojs.util.ViewUtils +import org.autojs.autojs6.BuildConfig import org.autojs.autojs6.R import org.mozilla.javascript.ContextFactory import org.mozilla.javascript.WrappedException @@ -51,6 +52,12 @@ abstract class AbstractAutoJs protected constructor(protected val application: A lateinit var runtime: ScriptRuntime private set + private val scriptEngine + get() = when (BuildConfig.isInrt) { + true -> LoopBasedJavaScriptEngineWithDecryption(context) + else -> LoopBasedJavaScriptEngine(context) + } + val context: Context = application.applicationContext val appUtils by lazy { createAppUtils(context) } val globalConsole by lazy { createGlobalConsole() } @@ -58,19 +65,11 @@ abstract class AbstractAutoJs protected constructor(protected val application: A val layoutInspector = LayoutInspector(context) val uiHandler = UiHandler(context) val infoProvider = ActivityInfoProvider(context) - val scriptEngineManager = ScriptEngineManager(context) val scriptEngineService: ScriptEngineService = run { - if (org.autojs.autojs6.BuildConfig.isInrt) { - scriptEngineManager.registerEngine(JavaScriptSource.ENGINE) { - XJavaScriptEngine(context).also { engine -> - engine.runtime = createRuntime().also { runtime = it } - } - } - } else { - scriptEngineManager.registerEngine(JavaScriptSource.ENGINE) { - LoopBasedJavaScriptEngine(context).also { engine -> - engine.runtime = createRuntime().also { runtime = it } - } + val scriptEngineManager = ScriptEngineManager(context) + scriptEngineManager.registerEngine(JavaScriptSource.ENGINE) { + scriptEngine.also { engine -> + engine.runtime = createRuntime().also { runtime = it } } } initContextFactory() diff --git a/app/src/main/java/org/autojs/autojs/App.kt b/app/src/main/java/org/autojs/autojs/App.kt index d0b6cdd6..4624e974 100644 --- a/app/src/main/java/org/autojs/autojs/App.kt +++ b/app/src/main/java/org/autojs/autojs/App.kt @@ -20,8 +20,6 @@ import com.bumptech.glide.request.transition.Transition import com.flurry.android.FlurryAgent import com.tencent.bugly.Bugly import com.tencent.bugly.crashreport.CrashReport -import com.zeugmasolutions.localehelper.LocaleHelper -import com.zeugmasolutions.localehelper.LocaleHelperApplicationDelegate import org.autojs.autojs.app.GlobalAppContext import org.autojs.autojs.core.accessibility.AccessibilityTool import org.autojs.autojs.core.ui.inflater.ImageLoader @@ -38,11 +36,9 @@ import org.autojs.autojs.ui.floating.FloatyWindowManger import org.autojs.autojs.util.ViewUtils import org.autojs.autojs6.BuildConfig import org.autojs.autojs6.R -import org.lsposed.hiddenapibypass.HiddenApiBypass import java.lang.ref.WeakReference import java.lang.reflect.Method - /** * Created by Stardust on 2017/1/27. * Modified by SuperMonster003 as of Aug 23, 2022. @@ -55,8 +51,6 @@ class App : MultiDexApplication() { lateinit var devPluginService: DevPluginService private set - private val localeAppDelegate = LocaleHelperApplicationDelegate() - override fun onCreate() { super.onCreate() @@ -79,21 +73,8 @@ class App : MultiDexApplication() { } override fun attachBaseContext(base: Context) { - // @Caution by SuperMonster003 on Aug 2, 2023. - // ! This will cause AutoJs6 not being aware of - // ! configuration changes (like orientation and so forth). - // super.attachBaseContext(localeAppDelegate.attachBaseContext(base)) - super.attachBaseContext(base) - - // @Dubious by SuperMonster003 on Aug 2, 2023. - // ! Locale helper may be not work as expected ? - localeAppDelegate.attachBaseContext(base) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - HiddenApiBypass.addHiddenApiExemptions("L"); - } - Log.d("Shizuku", "${App::class.java.getSimpleName()} attachBaseContext | Process=${getProcessNameCompat()}") + Log.d("Shizuku", "${App::class.java.simpleName} attachBaseContext | Process=${getProcessNameCompat()}") } private fun setUpStaticsTool() { @@ -129,6 +110,7 @@ class App : MultiDexApplication() { else -> ViewUtils.MODE.DAY } } + else -> ViewUtils.MODE.NULL } ) @@ -234,14 +216,11 @@ class App : MultiDexApplication() { } override fun onConfigurationChanged(newConfig: Configuration) { - localeAppDelegate.onConfigurationChanged(this) ViewUtils.onConfigurationChanged(newConfig) FloatyWindowManger.getCircularMenu()?.savePosition(newConfig) super.onConfigurationChanged(newConfig) } - override fun getApplicationContext() = LocaleHelper.onAttach(super.getApplicationContext()) - companion object { private const val BUGLY_APP_ID = "19b3607b53" diff --git a/app/src/main/java/org/autojs/autojs/AutoJs.kt b/app/src/main/java/org/autojs/autojs/AutoJs.kt index 7cbed361..f7bc9f10 100644 --- a/app/src/main/java/org/autojs/autojs/AutoJs.kt +++ b/app/src/main/java/org/autojs/autojs/AutoJs.kt @@ -1,5 +1,6 @@ package org.autojs.autojs +import android.annotation.SuppressLint import android.app.Application import android.content.BroadcastReceiver import android.content.Context @@ -30,8 +31,10 @@ import org.autojs.autojs.ui.main.MainActivity import org.autojs.autojs.ui.project.BuildActivity import org.autojs.autojs.ui.settings.AboutActivity import org.autojs.autojs.ui.settings.PreferencesActivity +import org.autojs.autojs6.BuildConfig import org.autojs.autojs6.R import java.util.concurrent.Executors +import org.autojs.autojs.inrt.autojs.AutoJs as AutoJsInrt /** * Created by Stardust on 2017/4/2. @@ -179,6 +182,7 @@ open class AutoJs(private val appContext: Application) : AbstractAutoJs(appConte companion object { private var isInitialized = false + @SuppressLint("StaticFieldLeak") @JvmStatic lateinit var instance: AutoJs private set @@ -187,7 +191,10 @@ open class AutoJs(private val appContext: Application) : AbstractAutoJs(appConte @JvmStatic fun initInstance(application: Application) { if (!isInitialized) { - instance = AutoJs(application) + instance = when (BuildConfig.isInrt) { + true -> AutoJsInrt(application) + else -> AutoJs(application) + } isInitialized = true } } diff --git a/app/src/main/java/org/autojs/autojs/apkbuilder/ApkBuilder.kt b/app/src/main/java/org/autojs/autojs/apkbuilder/ApkBuilder.kt index 2f05c718..6f608d3d 100644 --- a/app/src/main/java/org/autojs/autojs/apkbuilder/ApkBuilder.kt +++ b/app/src/main/java/org/autojs/autojs/apkbuilder/ApkBuilder.kt @@ -1,7 +1,10 @@ package org.autojs.autojs.apkbuilder +import android.content.res.AssetManager import android.graphics.Bitmap import android.graphics.BitmapFactory +import android.util.Log +import com.reandroid.arsc.chunk.TableBlock import org.autojs.autojs.apkbuilder.util.StreamUtils import org.autojs.autojs.app.GlobalAppContext import org.autojs.autojs.engine.encryption.AdvancedEncryptionStandard @@ -30,9 +33,14 @@ open class ApkBuilder(apkInputStream: InputStream?, private val mOutApkFile: Fil private var mInitVector: String? = null private var mKey: String? = null + private val mAssetManager: AssetManager by lazy { GlobalAppContext.get().assets } + private val mManifestFile get() = File(mWorkspacePath, "AndroidManifest.xml") + private val mResourcesArscFile + get() = File(mWorkspacePath, "resources.arsc") + private lateinit var mAppConfig: AppConfig init { @@ -43,9 +51,10 @@ open class ApkBuilder(apkInputStream: InputStream?, private val mOutApkFile: Fil @Throws(IOException::class) fun prepare() = also { - mProgressCallback?.run { GlobalAppContext.post { onPrepare(this@ApkBuilder) } } + mProgressCallback?.let { callback -> GlobalAppContext.post { callback.onPrepare(this) } } File(mWorkspacePath).mkdirs() mApkPackager.unzip() + copyAssetsRecursively("", File(mWorkspacePath, "assets")) } @Throws(IOException::class) @@ -147,13 +156,24 @@ open class ApkBuilder(apkInputStream: InputStream?, private val mOutApkFile: Fil @Throws(IOException::class) fun build() = also { - mProgressCallback?.run { GlobalAppContext.post { onBuild(this@ApkBuilder) } } - mAppConfig.icon?.run { + mProgressCallback?.let { callback -> GlobalAppContext.post { callback.onBuild(this) } } + mAppConfig.icon?.let { callable -> try { - call()?.compress( - Bitmap.CompressFormat.PNG, 100, - FileOutputStream(File(mWorkspacePath, "res/mipmap/ic_launcher.png")) - ) + val tableBlock = TableBlock.load(mResourcesArscFile) + val packageName = "${GlobalAppContext.get().packageName}.inrt" + val packageBlock = tableBlock.getOrCreatePackage(0x7f, packageName).also { + tableBlock.currentPackage = it + } + val appIcon = packageBlock.getOrCreate("", ICON_RES_DIR, ICON_NAME) + val appIconPath = appIcon.resValue.decodeValue() + Log.d(TAG, "Icon path: $appIconPath") + val file = File(mWorkspacePath, appIconPath).also { + if (!it.exists()) { + File(it.parent!!).mkdirs() + it.createNewFile() + } + } + callable.call()?.compress(Bitmap.CompressFormat.PNG, 100, FileOutputStream(file)) } catch (e: Exception) { throw RuntimeException(e) } @@ -162,16 +182,36 @@ open class ApkBuilder(apkInputStream: InputStream?, private val mOutApkFile: Fil mArscPackageName?.let { buildArsc() } } + private fun copyAssetsRecursively(assetPath: String, targetFile: File) { + if (targetFile.isFile && targetFile.exists()) return + val list = mAssetManager.list(assetPath) ?: return + if (list.isEmpty()) /* asset is file */ { + mAssetManager.open(assetPath).use { input -> + FileOutputStream(targetFile.absolutePath).use { output -> + input.copyTo(output) + output.flush() + } + } + } else /* asset is folder */ { + targetFile.delete() + targetFile.mkdir() + list.forEach { + val sourcePath = if (assetPath.isEmpty()) it else "$assetPath/$it" + copyAssetsRecursively(sourcePath, File(targetFile, it)) + } + } + } + @Throws(Exception::class) fun sign() = also { - mProgressCallback?.run { GlobalAppContext.post { onSign(this@ApkBuilder) } } + mProgressCallback?.let { callback -> GlobalAppContext.post { callback.onSign(this) } } val fos = FileOutputStream(mOutApkFile) TinySign.sign(File(mWorkspacePath), fos) fos.close() } fun cleanWorkspace() = also { - mProgressCallback?.run { GlobalAppContext.post { onClean(this@ApkBuilder) } } + mProgressCallback?.let { callback -> GlobalAppContext.post { callback.onClean(this) } } delete(File(mWorkspacePath)) } @@ -258,4 +298,13 @@ open class ApkBuilder(apkInputStream: InputStream?, private val mOutApkFile: Fil } } + companion object { + + private val TAG = ApkBuilder::class.java.simpleName + + const val ICON_NAME = "ic_launcher" + const val ICON_RES_DIR = "mipmap" + + } + } \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/apkbuilder/ApkBuilderPluginHelper.java b/app/src/main/java/org/autojs/autojs/apkbuilder/ApkBuilderPluginHelper.java index 51a585a9..b8417d95 100644 --- a/app/src/main/java/org/autojs/autojs/apkbuilder/ApkBuilderPluginHelper.java +++ b/app/src/main/java/org/autojs/autojs/apkbuilder/ApkBuilderPluginHelper.java @@ -19,11 +19,12 @@ import java.io.InputStream; public class ApkBuilderPluginHelper { private static final String PLUGIN_PACKAGE_NAME = "org.autojs.apkbuilderplugin"; - private static final String TEMPLATE_APK_PATH = "template.apk"; private static final boolean DEBUG_APK_PLUGIN = false; + public static final String TEMPLATE_APK_PATH = "template.apk"; + public static boolean isPluginAvailable(Context context) { -// return DeveloperUtils.checkSignature(context, PLUGIN_PACKAGE_NAME); + // return DeveloperUtils.checkSignature(context, PLUGIN_PACKAGE_NAME); try { context.getPackageManager().getPackageInfo(PLUGIN_PACKAGE_NAME, 0); } catch (PackageManager.NameNotFoundException e) { @@ -55,5 +56,3 @@ public class ApkBuilderPluginHelper { } } } - - diff --git a/app/src/main/java/org/autojs/autojs/apkbuilder/ManifestEditor.java b/app/src/main/java/org/autojs/autojs/apkbuilder/ManifestEditor.java index 2e233754..64f11686 100644 --- a/app/src/main/java/org/autojs/autojs/apkbuilder/ManifestEditor.java +++ b/app/src/main/java/org/autojs/autojs/apkbuilder/ManifestEditor.java @@ -22,7 +22,6 @@ public class ManifestEditor { private String mPackageName; private byte[] mManifestData; - public ManifestEditor(InputStream manifestInputStream) { mManifestInputStream = manifestInputStream; } @@ -54,7 +53,7 @@ public class ManifestEditor { mManifestData = writer.toByteArray(); return this; } - + private static byte[] readFully(InputStream is) throws IOException { byte[] bytes = new byte[is.available()]; is.read(bytes); @@ -90,7 +89,6 @@ public class ManifestEditor { } } - private class MutableAxmlWriter extends AxmlWriter { private class MutableNodeImpl extends AxmlWriter.NodeImpl { diff --git a/app/src/main/java/org/autojs/autojs/core/accessibility/AccessibilityTool.kt b/app/src/main/java/org/autojs/autojs/core/accessibility/AccessibilityTool.kt index 3657bf90..007cfeae 100644 --- a/app/src/main/java/org/autojs/autojs/core/accessibility/AccessibilityTool.kt +++ b/app/src/main/java/org/autojs/autojs/core/accessibility/AccessibilityTool.kt @@ -9,7 +9,7 @@ import android.provider.Settings.Secure import android.text.TextUtils import android.util.Log import org.autojs.autojs.pref.Pref -import org.autojs.autojs.runtime.api.ProcessShell.execCommand +import org.autojs.autojs.runtime.api.ProcessShell import org.autojs.autojs.util.RootUtils import org.autojs.autojs.util.SettingsUtils import org.autojs.autojs.util.ViewUtils @@ -102,10 +102,10 @@ class AccessibilityTool(val context: Context) { val services = getEnabledWithRoot(true) val cmdServices = "settings put secure enabled_accessibility_services $services" - val resultServices = execCommand(cmdServices, true) + val resultServices = ProcessShell.execCommand(cmdServices, true) val cmdState = "settings put secure accessibility_enabled 1" - val resultState = execCommand(cmdState, true) + val resultState = ProcessShell.execCommand(cmdState, true) TextUtils.isEmpty(resultServices.error) && TextUtils.isEmpty(resultState.error) } catch (e: Exception) { @@ -136,10 +136,10 @@ class AccessibilityTool(val context: Context) { val services = getEnabledWithRoot(false) val cmdServices = "settings put secure enabled_accessibility_services $services" - val resultServices = execCommand(cmdServices, true) + val resultServices = ProcessShell.execCommand(cmdServices, true) val cmdState = "settings put secure accessibility_enabled 0" - val resultState = execCommand(cmdState, true) + val resultState = ProcessShell.execCommand(cmdState, true) TextUtils.isEmpty(resultServices.error) && TextUtils.isEmpty(resultState.error) } catch (e: Exception) { @@ -159,7 +159,7 @@ class AccessibilityTool(val context: Context) { false -> detachAutoJs(getEnabledWithRoot()) else -> { val cmd = "settings get secure enabled_accessibility_services" - execCommand(cmd, true).result.takeUnless { it == "null" }?.replace("\n", "") ?: "" + ProcessShell.execCommand(cmd, true).result.takeUnless { it == "null" }?.replace("\n", "") ?: "" } } diff --git a/app/src/main/java/org/autojs/autojs/core/accessibility/SimpleActionAutomator.kt b/app/src/main/java/org/autojs/autojs/core/accessibility/SimpleActionAutomator.kt index 89414f27..324822a6 100644 --- a/app/src/main/java/org/autojs/autojs/core/accessibility/SimpleActionAutomator.kt +++ b/app/src/main/java/org/autojs/autojs/core/accessibility/SimpleActionAutomator.kt @@ -34,18 +34,19 @@ import android.accessibilityservice.AccessibilityService as AndroidAccessibility */ class SimpleActionAutomator(private val accessibilityBridge: AccessibilityBridge, private val scriptRuntime: ScriptRuntime) { - private val globalActionAutomatorRaw by lazy { - GlobalActionAutomator(Handler(scriptRuntime.loopers.servantLooper)) { + private val globalActionAutomatorRaw + get() = GlobalActionAutomator(Handler(scriptRuntime.loopers.servantLooper)) { ensureService() accessibilityBridge.service!! } + + private val globalActionAutomator by lazy { + globalActionAutomatorRaw } - private val globalActionAutomator - get() = globalActionAutomatorRaw - - private val globalActionAutomatorForGesture - get() = globalActionAutomatorRaw.apply { setScreenMetrics(mScreenMetrics) } + private val globalActionAutomatorForGesture by lazy { + globalActionAutomatorRaw.apply { setScreenMetrics(mScreenMetrics) } + } private val isRunningPackageSelf get() = DeveloperUtils.isSelfPackage(accessibilityBridge.infoProvider.latestPackage) diff --git a/app/src/main/java/org/autojs/autojs/core/console/ConsoleImpl.kt b/app/src/main/java/org/autojs/autojs/core/console/ConsoleImpl.kt index aa56ba09..5d9195fc 100644 --- a/app/src/main/java/org/autojs/autojs/core/console/ConsoleImpl.kt +++ b/app/src/main/java/org/autojs/autojs/core/console/ConsoleImpl.kt @@ -332,6 +332,7 @@ open class ConsoleImpl(val uiHandler: UiHandler) : AbstractConsole() { // SecurityException: https://github.com/hyb1996-guest/AutoJsIssueReport/issues/4781 } catch (e: Exception) { e.printStackTrace() + ScriptRuntime.popException(e.message) uiHandler.toast(R.string.error_no_display_over_other_apps_permission) } } diff --git a/app/src/main/java/org/autojs/autojs/core/looper/Loopers.kt b/app/src/main/java/org/autojs/autojs/core/looper/Loopers.kt index 39e48c37..024f0451 100644 --- a/app/src/main/java/org/autojs/autojs/core/looper/Loopers.kt +++ b/app/src/main/java/org/autojs/autojs/core/looper/Loopers.kt @@ -25,11 +25,13 @@ class Loopers(val runtime: ScriptRuntime) { @Volatile private var mServantLooper: Looper? = null + @Suppress("DEPRECATION") private var mMainLooperQuitHandler: LooperQuitHandler? = null - private var waitWhenIdle: Boolean - private val allTasks = ConcurrentLinkedQueue() + private var mWaitWhenIdle: Boolean + + private val allTasks = ConcurrentLinkedQueue() private val lock = ReentrantLock() private val condition = lock.newCondition() @@ -55,7 +57,7 @@ class Loopers(val runtime: ScriptRuntime) { prepare() myLooper = Looper.myLooper()!! timer = Timer(runtime, myLooper) - waitWhenIdle = myLooper == Looper.getMainLooper() + mWaitWhenIdle = myLooper == Looper.getMainLooper() } @Deprecated("Deprecated in Java", ReplaceWith("AsyncTask")) @@ -111,10 +113,9 @@ class Loopers(val runtime: ScriptRuntime) { return when { Thread.currentThread().isInterrupted -> true timer.hasPendingCallbacks() -> false - // 检查是否有运行中的线程 - checkTask() -> false - waitWhenIdle -> false - (Context.getCurrentContext() as AutoJsContext).hasPendingContinuation() -> false + checkTask() /* 检查是否有运行中的线程. */ -> false + (Context.getCurrentContext() as? AutoJsContext)?.hasPendingContinuation() == true -> false + mWaitWhenIdle -> false else -> true } } @@ -133,7 +134,7 @@ class Loopers(val runtime: ScriptRuntime) { @Deprecated("Deprecated in Java", ReplaceWith("AsyncTask")) fun waitWhenIdle(b: Boolean) { - waitWhenIdle = b + mWaitWhenIdle = b } fun recycle() { @@ -160,7 +161,7 @@ class Loopers(val runtime: ScriptRuntime) { Looper.myQueue().addIdleHandler(MessageQueue.IdleHandler { if (this == runtime.loopers) { Log.d(LOG_TAG, "main looper queueIdle") - if (shouldQuitLooper() && mMainLooperQuitHandler?.shouldQuit() == true) { + if (shouldQuitLooper() && mMainLooperQuitHandler?.shouldQuit() != false) { Log.d(LOG_TAG, "main looper quit") Looper.myLooper()?.quitSafely() } diff --git a/app/src/main/java/org/autojs/autojs/core/shizuku/UserService.java b/app/src/main/java/org/autojs/autojs/core/shizuku/UserService.java new file mode 100644 index 00000000..e5f1cd23 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/core/shizuku/UserService.java @@ -0,0 +1,61 @@ +package org.autojs.autojs.core.shizuku; + +import android.content.Context; +import android.os.RemoteException; +import android.util.Log; + +import androidx.annotation.Keep; + +import org.autojs.autojs.runtime.api.AbstractShell; +import org.autojs.autojs.runtime.api.ProcessShell; + +public class UserService extends IUserService.Stub { + + /** + * Constructor is required. + */ + public UserService() { + Log.i("UserService", "constructor"); + } + + /** + * Constructor with Context. This is only available from Shizuku API v13. + *

+ * This method need to be annotated with {@link Keep} to prevent ProGuard from removing it. + * + * @param context Context created with createPackageContextAsUser + * @see code used to create the instance of this class + */ + @Keep + public UserService(Context context) { + Log.i("UserService", "constructor with Context: context=" + context.toString()); + } + + /** + * Reserved destroy method + */ + @Override + public void destroy() { + Log.i("UserService", "destroy"); + } + + @Override + public void exit() { + destroy(); + } + + @Override + public String execCommand(String command) throws RemoteException { + try { + return ProcessShell + .execCommand(command.split("\n"), ProcessShell.getShellProcess()) + .toJson(); + } catch (Exception e) { + AbstractShell.Result result = new AbstractShell.Result(); + result.code = 1; + result.error = e.getMessage(); + return result.toJson(); + } + } + +} diff --git a/app/src/main/java/org/autojs/autojs/engine/RootAutomatorEngine.kt b/app/src/main/java/org/autojs/autojs/engine/RootAutomatorEngine.kt index 3e061bed..ef4be2e5 100644 --- a/app/src/main/java/org/autojs/autojs/engine/RootAutomatorEngine.kt +++ b/app/src/main/java/org/autojs/autojs/engine/RootAutomatorEngine.kt @@ -5,6 +5,7 @@ import android.util.Log import androidx.preference.PreferenceManager import org.autojs.autojs.core.inputevent.InputDevices import org.autojs.autojs.pio.PFiles +import org.autojs.autojs.runtime.api.AbstractShell import org.autojs.autojs.runtime.api.ProcessShell import org.autojs.autojs.runtime.exception.ScriptException import org.autojs.autojs.runtime.exception.ScriptInterruptedException @@ -50,7 +51,7 @@ class RootAutomatorEngine @JvmOverloads constructor(private val mContext: Contex "exit", ) try { - Runtime.getRuntime().exec("su").also { + Runtime.getRuntime().exec(AbstractShell.COMMAND_SU).also { mProcess = it executeCommands(it, commands) mPid = readPid(it) diff --git a/app/src/main/java/org/autojs/autojs/execution/ExecutionConfig.kt b/app/src/main/java/org/autojs/autojs/execution/ExecutionConfig.kt index 9c6beb67..ea419e6a 100644 --- a/app/src/main/java/org/autojs/autojs/execution/ExecutionConfig.kt +++ b/app/src/main/java/org/autojs/autojs/execution/ExecutionConfig.kt @@ -86,8 +86,10 @@ data class ExecutionConfig( companion object CREATOR : Parcelable.Creator { + const val tag = "execution.config" + @JvmStatic - val tag = "execution.config" + fun getTag() = tag @JvmStatic val default: ExecutionConfig diff --git a/app/src/main/java/org/autojs/autojs/execution/RunnableScriptExecution.java b/app/src/main/java/org/autojs/autojs/execution/RunnableScriptExecution.java index 9b522c81..67c77619 100644 --- a/app/src/main/java/org/autojs/autojs/execution/RunnableScriptExecution.java +++ b/app/src/main/java/org/autojs/autojs/execution/RunnableScriptExecution.java @@ -30,7 +30,7 @@ public class RunnableScriptExecution extends ScriptExecution.AbstractScriptExecu public Object execute() { mScriptEngine = mScriptEngineManager.createEngineOfSourceOrThrow(getSource(), getId()); - mScriptEngine.setTag(ExecutionConfig.getTag(), getConfig()); + mScriptEngine.setTag(ExecutionConfig.tag, getConfig()); return execute(mScriptEngine); } diff --git a/app/src/main/java/org/autojs/autojs/execution/ScriptExecuteActivity.java b/app/src/main/java/org/autojs/autojs/execution/ScriptExecuteActivity.java index 83d46218..587e81f8 100644 --- a/app/src/main/java/org/autojs/autojs/execution/ScriptExecuteActivity.java +++ b/app/src/main/java/org/autojs/autojs/execution/ScriptExecuteActivity.java @@ -144,6 +144,7 @@ public class ScriptExecuteActivity extends AppCompatActivity { mScriptEngine.destroy(); } mScriptExecution = null; + mRuntime.loopers.waitWhenIdle(false); } @Override @@ -243,7 +244,7 @@ public class ScriptExecuteActivity extends AppCompatActivity { mScriptEngine.forceStop(); } mScriptEngine = mScriptEngineManager.createEngineOfSourceOrThrow(getSource(), getId()); - mScriptEngine.setTag(ExecutionConfig.getTag(), getConfig()); + mScriptEngine.setTag(ExecutionConfig.tag, getConfig()); return mScriptEngine; } diff --git a/app/src/main/java/org/autojs/autojs/external/foreground/MainActivityForegroundService.kt b/app/src/main/java/org/autojs/autojs/external/foreground/MainActivityForegroundService.kt index b12b0a5f..deeb5ca9 100644 --- a/app/src/main/java/org/autojs/autojs/external/foreground/MainActivityForegroundService.kt +++ b/app/src/main/java/org/autojs/autojs/external/foreground/MainActivityForegroundService.kt @@ -3,7 +3,7 @@ package org.autojs.autojs.external.foreground import android.app.Service import android.content.Intent import org.autojs.autojs.tool.ForegroundServiceCreator -import org.autojs.autojs.ui.main.MainActivity.Companion.getIntent +import org.autojs.autojs.ui.main.MainActivity import org.autojs.autojs.util.ForegroundServiceUtils import org.autojs.autojs6.R @@ -23,7 +23,7 @@ class MainActivityForegroundService : Service() { ForegroundServiceUtils.startForeground( ForegroundServiceCreator.Builder(this) .setClassName(sClassName) - .setIntent(getIntent(this)) + .setIntent(MainActivity.getIntent(this)) .setNotificationId(NOTIFICATION_ID) .setServiceName(R.string.foreground_notification_channel_name) .setServiceDescription(R.string.foreground_notification_channel_name) diff --git a/app/src/main/java/org/autojs/autojs/external/shortcut/ShortcutManager.java b/app/src/main/java/org/autojs/autojs/external/shortcut/ShortcutManager.java index 5b4714e2..a81156a5 100644 --- a/app/src/main/java/org/autojs/autojs/external/shortcut/ShortcutManager.java +++ b/app/src/main/java/org/autojs/autojs/external/shortcut/ShortcutManager.java @@ -18,7 +18,6 @@ import java.util.List; @RequiresApi(api = Build.VERSION_CODES.N_MR1) public class ShortcutManager { - private static ShortcutManager sInstance; private final Context mContext; private final android.content.pm.ShortcutManager mShortcutManager; diff --git a/app/src/main/java/org/autojs/autojs/external/widget/ScriptWidgetSettingsActivity.java b/app/src/main/java/org/autojs/autojs/external/widget/ScriptWidgetSettingsActivity.java index fa6c367e..0777dea9 100644 --- a/app/src/main/java/org/autojs/autojs/external/widget/ScriptWidgetSettingsActivity.java +++ b/app/src/main/java/org/autojs/autojs/external/widget/ScriptWidgetSettingsActivity.java @@ -15,6 +15,7 @@ import org.autojs.autojs.model.explorer.ExplorerFileProvider; import org.autojs.autojs.model.script.Scripts; import org.autojs.autojs.ui.BaseActivity; import org.autojs.autojs.ui.explorer.ExplorerView; +import org.autojs.autojs.util.WorkingDirectoryUtils; import org.autojs.autojs6.R; import org.autojs.autojs6.databinding.ActivityScriptWidgetSettingsBinding; @@ -42,9 +43,10 @@ public class ScriptWidgetSettingsActivity extends BaseActivity { private void initScriptListRecyclerView() { - mExplorer = new Explorer(new ExplorerFileProvider(Scripts.getFILE_FILTER()), 0); + mExplorer = new Explorer(new ExplorerFileProvider(Scripts.FILE_FILTER), 0); ExplorerView explorerView = binding.scriptList; - explorerView.setExplorer(mExplorer, ExplorerDirPage.createRoot(Environment.getExternalStorageDirectory())); + String workingDirPath = WorkingDirectoryUtils.getPath(); + explorerView.setExplorer(mExplorer, ExplorerDirPage.createRoot(workingDirPath)); explorerView.setOnItemClickListener((view, file) -> { mSelectedScriptFilePath = file.getPath(); finish(); diff --git a/app/src/main/java/org/autojs/autojs/inrt/App.kt b/app/src/main/java/org/autojs/autojs/inrt/App.kt deleted file mode 100644 index f504699f..00000000 --- a/app/src/main/java/org/autojs/autojs/inrt/App.kt +++ /dev/null @@ -1,86 +0,0 @@ -package org.autojs.autojs.inrt - -import android.app.Application -import android.graphics.Bitmap -import android.graphics.drawable.Drawable -import android.net.Uri -import android.view.View -import android.widget.ImageView - -import com.bumptech.glide.Glide -import com.bumptech.glide.request.target.SimpleTarget -import com.bumptech.glide.request.transition.Transition -import org.autojs.autojs.inrt.App -import org.autojs.autojs.AutoJs -import org.autojs.autojs.inrt.autojs.GlobalKeyObserver -import org.autojs.autojs.app.GlobalAppContext -import org.autojs.autojs.core.ui.inflater.ImageLoader -import org.autojs.autojs.core.ui.inflater.util.Drawables -import java.lang.ref.WeakReference - -/** - * Created by Stardust on 2017/7/1. - */ -class App : Application() { - companion object { - - private const val BUGLY_APP_ID = "19b3607b53" - - private lateinit var instance: WeakReference - - val app: App - get() = instance.get()!! - - } - - override fun onCreate() { - super.onCreate() - GlobalAppContext.set(this) - instance = WeakReference(this) - AutoJs.initInstance(this) - GlobalKeyObserver.init() - Drawables.defaultImageLoader=object : ImageLoader { - override fun loadInto(imageView: ImageView, uri: Uri) { - Glide.with(this@App) - .load(uri) - .into(imageView) - } - - override fun loadIntoBackground(view: View, uri: Uri) { - Glide.with(this@App) - .load(uri) - .into(object : SimpleTarget() { - override fun onResourceReady(resource: Drawable, transition: Transition?) { - view.background = resource - } - }) - } - - override fun load(view: View, uri: Uri): Drawable { - throw UnsupportedOperationException() - } - - override fun load(view: View, uri: Uri, drawableCallback: ImageLoader.DrawableCallback) { - Glide.with(this@App) - .load(uri) - .into(object : SimpleTarget() { - override fun onResourceReady(resource: Drawable, transition: Transition?) { - drawableCallback.onLoaded(resource) - } - }) - } - - override fun load(view: View, uri: Uri, bitmapCallback: ImageLoader.BitmapCallback) { - Glide.with(this@App) - .asBitmap() - .load(uri) - .into(object : SimpleTarget() { - override fun onResourceReady(resource: Bitmap, transition: Transition?) { - bitmapCallback.onLoaded(resource) - } - }) - } - } - } - -} diff --git a/app/src/main/java/org/autojs/autojs/inrt/LogActivity.kt b/app/src/main/java/org/autojs/autojs/inrt/LogActivity.kt index 6786b216..f84b26cc 100644 --- a/app/src/main/java/org/autojs/autojs/inrt/LogActivity.kt +++ b/app/src/main/java/org/autojs/autojs/inrt/LogActivity.kt @@ -8,7 +8,7 @@ import android.view.Menu import android.view.MenuItem import android.view.View -import org.autojs.autojs.AutoJs +import org.autojs.autojs.inrt.autojs.AutoJs import org.autojs.autojs.inrt.launch.GlobalProjectLauncher import org.autojs.autojs.core.console.ConsoleImpl import org.autojs.autojs.core.console.ConsoleView diff --git a/app/src/main/java/org/autojs/autojs/inrt/SplashActivity.kt b/app/src/main/java/org/autojs/autojs/inrt/SplashActivity.kt index b760e121..4347e73e 100644 --- a/app/src/main/java/org/autojs/autojs/inrt/SplashActivity.kt +++ b/app/src/main/java/org/autojs/autojs/inrt/SplashActivity.kt @@ -12,7 +12,7 @@ import android.widget.Toast import androidx.annotation.NonNull import androidx.annotation.Nullable import androidx.appcompat.app.AppCompatActivity -import org.autojs.autojs.AutoJs +import org.autojs.autojs.inrt.autojs.AutoJs import org.autojs.autojs.inrt.launch.GlobalProjectLauncher import org.autojs.autojs6.R diff --git a/app/src/main/java/org/autojs/autojs/inrt/autojs/AutoJs.kt b/app/src/main/java/org/autojs/autojs/inrt/autojs/AutoJs.kt index a835fb6c..b53ced32 100644 --- a/app/src/main/java/org/autojs/autojs/inrt/autojs/AutoJs.kt +++ b/app/src/main/java/org/autojs/autojs/inrt/autojs/AutoJs.kt @@ -1,98 +1,28 @@ package org.autojs.autojs.inrt.autojs -import android.annotation.SuppressLint import android.app.Application import android.content.Context -import org.autojs.autojs.app.GlobalAppContext import org.autojs.autojs.inrt.LogActivity import org.autojs.autojs.inrt.SettingsActivity -import org.autojs.autojs.core.accessibility.AccessibilityTool -import org.autojs.autojs.core.accessibility.AccessibilityService -import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.api.AppUtils -import org.autojs.autojs.runtime.exception.ScriptException -import org.autojs.autojs.runtime.exception.ScriptInterruptedException -import org.autojs.autojs.script.JavaScriptSource -import org.autojs.autojs6.R - +import org.autojs.autojs.AutoJs as AutoJsApp /** * Created by Stardust on 2017/4/2. */ -class AutoJs private constructor(application: Application) : org.autojs.autojs.AutoJs(application) { +class AutoJs(application: Application) : AutoJsApp(application) { - init { - scriptEngineService.registerGlobalScriptExecutionListener(ScriptExecutionGlobalListener()) - scriptEngineManager.registerEngine(JavaScriptSource.ENGINE) { - val engine = XJavaScriptEngine(application) - engine.runtime = createRuntime() - engine - } - } + override fun createAppUtils(context: Context) = AppUtils(context, context.packageName + ".fileprovider") - override fun createAppUtils(context: Context): AppUtils { - return AppUtils(context, context.packageName + ".fileprovider") - } - - override fun ensureAccessibilityServiceEnabled() { - if (AccessibilityService.instance != null) { - return - } - var errorMessage: String? = null - if (isAccessibilityServiceEnabled()) { - errorMessage = GlobalAppContext.get().getString(R.string.text_a11y_service_enabled_but_not_running) - } else if (!getAccessibilityServiceTool().service.enableIfNeededAndWaitFor(2000)) { - errorMessage = GlobalAppContext.get().getString(R.string.error_no_accessibility_permission) - } - if (errorMessage != null) { - getAccessibilityServiceTool().launchSettings() - throw ScriptException(errorMessage) - } - } - - override fun waitForAccessibilityServiceEnabled(timeout: Long) { - if (AccessibilityService.instance != null) { - return - } - var errorMessage: String? = null - if (isAccessibilityServiceEnabled()) { - errorMessage = GlobalAppContext.get().getString(R.string.text_a11y_service_enabled_but_not_running) - } else if (!getAccessibilityServiceTool().service.enableIfNeededAndWaitFor(2000)) { - errorMessage = GlobalAppContext.get().getString(R.string.error_no_accessibility_permission) - } - if (errorMessage != null) { - getAccessibilityServiceTool().launchSettings() - if (!AccessibilityService.waitForEnabled(timeout)) { - throw ScriptInterruptedException() - } - } - } - - override fun createRuntime(): ScriptRuntime { - val runtime = super.createRuntime() - runtime.putProperty("class.settings", SettingsActivity::class.java) - runtime.putProperty("class.console", LogActivity::class.java) - return runtime - } - - private fun getAccessibilityServiceTool(): AccessibilityTool { - return AccessibilityTool(application) - } - - private fun isAccessibilityServiceEnabled(): Boolean { - return getAccessibilityServiceTool().service.isEnabled() + override fun createRuntime() = super.createRuntime().apply { + putProperty("class.settings", SettingsActivity::class.java) + putProperty("class.console", LogActivity::class.java) } companion object { - @SuppressLint("StaticFieldLeak") - @JvmStatic - lateinit var instance: AutoJs - private set + val instance + get() = AutoJsApp.instance - @Synchronized - fun initInstance(application: Application) { - instance = AutoJs(application) - } } } diff --git a/app/src/main/java/org/autojs/autojs/inrt/autojs/GlobalKeyObserver.kt b/app/src/main/java/org/autojs/autojs/inrt/autojs/GlobalKeyObserver.kt deleted file mode 100644 index bc3af708..00000000 --- a/app/src/main/java/org/autojs/autojs/inrt/autojs/GlobalKeyObserver.kt +++ /dev/null @@ -1,93 +0,0 @@ -package org.autojs.autojs.inrt.autojs - -import android.util.Log -import android.view.KeyEvent - -import org.autojs.autojs.app.GlobalAppContext -import org.autojs.autojs.inrt.Pref -import org.autojs.autojs.core.accessibility.AccessibilityService -import org.autojs.autojs.core.accessibility.OnKeyListener -import org.autojs.autojs.core.inputevent.InputEventObserver -import org.autojs.autojs.core.inputevent.ShellKeyObserver - - -/** - * Created by Stardust on 2017/8/14. - */ -class GlobalKeyObserver internal constructor() : OnKeyListener, ShellKeyObserver.KeyListener { - private var mVolumeDownFromShell: Boolean = false - private var mVolumeDownFromAccessibility: Boolean = false - private var mVolumeUpFromShell: Boolean = false - private var mVolumeUpFromAccessibility: Boolean = false - - init { - AccessibilityService.stickOnKeyObserver - .addListener(this) - val observer = ShellKeyObserver() - observer.setKeyListener(this) - InputEventObserver.getGlobal(GlobalAppContext.get()).addListener(observer) - } - - fun onVolumeUp() { - Log.d(LOG_TAG, "onVolumeUp at " + System.currentTimeMillis()) - if (Pref.shouldStopAllScriptsWhenVolumeUp()) { - AutoJs.instance.scriptEngineService.stopAllAndToast() - } - } - - override fun onKeyEvent(keyCode: Int, event: KeyEvent) { - if (event.action != KeyEvent.ACTION_UP) - return - if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { - if (mVolumeDownFromShell) { - mVolumeDownFromShell = false - return - } - mVolumeUpFromAccessibility = true - onVolumeDown() - } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { - if (mVolumeUpFromShell) { - mVolumeUpFromShell = false - return - } - mVolumeUpFromAccessibility = true - onVolumeUp() - } - } - - fun onVolumeDown() { - - } - - - override fun onKeyDown(keyName: String) { - - } - - override fun onKeyUp(keyName: String) { - if ("KEY_VOLUMEUP" == keyName) { - if (mVolumeUpFromAccessibility) { - mVolumeUpFromAccessibility = false - return - } - mVolumeUpFromShell = true - onVolumeUp() - } else if ("KEY_VOLUMEDOWN" == keyName) { - if (mVolumeDownFromAccessibility) { - mVolumeDownFromAccessibility = false - return - } - mVolumeDownFromShell = true - onVolumeDown() - } - } - - companion object { - private const val LOG_TAG = "GlobalKeyObserver" - private val sSingleton = GlobalKeyObserver() - - fun init() { - //do nothing - } - } -} diff --git a/app/src/main/java/org/autojs/autojs/inrt/autojs/LoopBasedJavaScriptEngineWithDecryption.kt b/app/src/main/java/org/autojs/autojs/inrt/autojs/LoopBasedJavaScriptEngineWithDecryption.kt new file mode 100644 index 00000000..27ff0825 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/inrt/autojs/LoopBasedJavaScriptEngineWithDecryption.kt @@ -0,0 +1,33 @@ +package org.autojs.autojs.inrt.autojs + +import android.content.Context +import org.autojs.autojs.engine.LoopBasedJavaScriptEngine +import org.autojs.autojs.engine.encryption.ScriptEncryption +import org.autojs.autojs.pio.PFiles +import org.autojs.autojs.script.EncryptedScriptFileHeader +import org.autojs.autojs.script.EncryptedScriptFileHeader.BLOCK_SIZE +import org.autojs.autojs.script.JavaScriptFileSource +import org.autojs.autojs.script.ScriptSource +import org.autojs.autojs.script.StringScriptSource + +class LoopBasedJavaScriptEngineWithDecryption(context: Context) : LoopBasedJavaScriptEngine(context) { + + override fun execute(source: ScriptSource, callback: ExecuteCallback?) { + if (source is JavaScriptFileSource) { + try { + val file = source.file + val bytes = PFiles.readBytes(file.path) + if (EncryptedScriptFileHeader.isValidFile(bytes)) { + super.execute(StringScriptSource(file.name, String(ScriptEncryption.decrypt(bytes, BLOCK_SIZE))), callback) + } else { + super.execute(source, callback) + } + } catch (e: Throwable) { + e.printStackTrace() + } + } else { + super.execute(source, callback) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/inrt/autojs/ScriptExecutionGlobalListener.kt b/app/src/main/java/org/autojs/autojs/inrt/autojs/ScriptExecutionGlobalListener.kt deleted file mode 100644 index b6ed525d..00000000 --- a/app/src/main/java/org/autojs/autojs/inrt/autojs/ScriptExecutionGlobalListener.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.autojs.autojs.inrt.autojs - -import org.autojs.autojs.app.GlobalAppContext -import org.autojs.autojs.execution.ScriptExecution -import org.autojs.autojs.execution.ScriptExecutionListener -import org.autojs.autojs6.R - -/** - * Created by Stardust on 2017/5/3. - */ -class ScriptExecutionGlobalListener : ScriptExecutionListener { - - override fun onStart(execution: ScriptExecution) { - execution.engine.setTag(ENGINE_TAG_START_TIME, System.currentTimeMillis()) - } - - override fun onSuccess(execution: ScriptExecution, result: Any?) { - onFinish(execution) - } - - private fun onFinish(execution: ScriptExecution) { - val millis = execution.engine.getTag(ENGINE_TAG_START_TIME) as Long? ?: return - val seconds = (System.currentTimeMillis() - millis) / 1000.0 - AutoJs.instance.scriptEngineService.globalConsole - .verbose(GlobalAppContext.get().getString(R.string.text_execution_finished), execution.source.toString(), seconds) - } - - override fun onException(execution: ScriptExecution, e: Throwable) { - onFinish(execution) - } - - companion object { - private const val ENGINE_TAG_START_TIME = "start_time" - } - -} diff --git a/app/src/main/java/org/autojs/autojs/inrt/autojs/XJavaScriptEngine.kt b/app/src/main/java/org/autojs/autojs/inrt/autojs/XJavaScriptEngine.kt deleted file mode 100644 index 9dcb0402..00000000 --- a/app/src/main/java/org/autojs/autojs/inrt/autojs/XJavaScriptEngine.kt +++ /dev/null @@ -1,44 +0,0 @@ -package org.autojs.autojs.inrt.autojs - -import android.content.Context -import org.autojs.autojs.engine.LoopBasedJavaScriptEngine -import org.autojs.autojs.engine.encryption.ScriptEncryption -import org.autojs.autojs.pio.PFiles -import org.autojs.autojs.script.EncryptedScriptFileHeader -import org.autojs.autojs.script.JavaScriptFileSource -import org.autojs.autojs.script.ScriptSource -import org.autojs.autojs.script.StringScriptSource -import java.io.File -import java.security.GeneralSecurityException - -class XJavaScriptEngine(context: Context) : LoopBasedJavaScriptEngine(context) { - - - override fun execute(source: ScriptSource, callback: ExecuteCallback?) { - if (source is JavaScriptFileSource) { - try { - if (execute(source.file)) { - return - } - } catch (e: Throwable) { - e.printStackTrace() - return - } - } - super.execute(source, callback) - } - - private fun execute(file: File): Boolean { - val bytes = PFiles.readBytes(file.path) - if (!EncryptedScriptFileHeader.isValidFile(bytes)) { - return false - } - try { - super.execute(StringScriptSource(file.name, String(ScriptEncryption.decrypt(bytes, EncryptedScriptFileHeader.BLOCK_SIZE)))) - } catch (e: GeneralSecurityException) { - e.printStackTrace() - } - return true - } - -} \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/inrt/launch/AssetsProjectLauncher.kt b/app/src/main/java/org/autojs/autojs/inrt/launch/AssetsProjectLauncher.kt index 44d71563..9241d165 100644 --- a/app/src/main/java/org/autojs/autojs/inrt/launch/AssetsProjectLauncher.kt +++ b/app/src/main/java/org/autojs/autojs/inrt/launch/AssetsProjectLauncher.kt @@ -8,7 +8,7 @@ import android.os.Looper import android.text.TextUtils import org.autojs.autojs.inrt.LogActivity import org.autojs.autojs.inrt.Pref -import org.autojs.autojs.AutoJs +import org.autojs.autojs.inrt.autojs.AutoJs import org.autojs.autojs.engine.encryption.ScriptEncryption import org.autojs.autojs.execution.ExecutionConfig import org.autojs.autojs.execution.ScriptExecution diff --git a/app/src/main/java/org/autojs/autojs/model/script/Scripts.kt b/app/src/main/java/org/autojs/autojs/model/script/Scripts.kt index d023537c..77e1c56a 100644 --- a/app/src/main/java/org/autojs/autojs/model/script/Scripts.kt +++ b/app/src/main/java/org/autojs/autojs/model/script/Scripts.kt @@ -36,7 +36,7 @@ object Scripts { const val EXTRA_EXCEPTION_LINE_NUMBER = "lineNumber" const val EXTRA_EXCEPTION_COLUMN_NUMBER = "columnNumber" - @JvmStatic + @JvmField val FILE_FILTER = FileFilter { file -> file.isDirectory || file.name.endsWith(FileUtils.TYPE.JAVASCRIPT.extension) || diff --git a/app/src/main/java/org/autojs/autojs/permission/DisplayOverOtherAppsPermission.kt b/app/src/main/java/org/autojs/autojs/permission/DisplayOverOtherAppsPermission.kt index a565470e..f4119632 100644 --- a/app/src/main/java/org/autojs/autojs/permission/DisplayOverOtherAppsPermission.kt +++ b/app/src/main/java/org/autojs/autojs/permission/DisplayOverOtherAppsPermission.kt @@ -34,7 +34,8 @@ class DisplayOverOtherAppsPermission(override val context: Context) : Permission fun config() { try { SettingsCompat.manageDrawOverlays(context) - } catch (ex: Exception) { + } catch (e: Exception) { + e.printStackTrace() FloatingWindowPermissionUtil.goToAppDetailSettings(context, context.packageName) } } diff --git a/app/src/main/java/org/autojs/autojs/permission/ManageAllFilesPermission.kt b/app/src/main/java/org/autojs/autojs/permission/ManageAllFilesPermission.kt index 3e40247e..80eb4bf0 100644 --- a/app/src/main/java/org/autojs/autojs/permission/ManageAllFilesPermission.kt +++ b/app/src/main/java/org/autojs/autojs/permission/ManageAllFilesPermission.kt @@ -75,7 +75,7 @@ class ManageAllFilesPermission(override val context: Context) : PermissionItemHe .onNegative { dialog, _ -> dialog.dismiss() } .onPositive { dialog, _ -> request() - MainActivity.setShouldRecreateMainActivity(true) + MainActivity.shouldRecreateMainActivity = true dialog.dismiss() } .cancelable(false) diff --git a/app/src/main/java/org/autojs/autojs/pref/Language.kt b/app/src/main/java/org/autojs/autojs/pref/Language.kt index 335288c0..7d35eae8 100644 --- a/app/src/main/java/org/autojs/autojs/pref/Language.kt +++ b/app/src/main/java/org/autojs/autojs/pref/Language.kt @@ -9,10 +9,9 @@ import java.util.Locale enum class Language(val locale: Locale, @KeyRes private val keyRes: Int, private val entryNameRes: Int) { - AUTO(LocaleUtils.getSystemLocale(), R.string.key_app_language_auto, R.string.entry_app_language_auto), - ZH(Locale.forLanguageTag("zh"), R.string.key_app_language_zh, R.string.entry_app_language_zh), - ZH_HK(Locale.forLanguageTag("zh-hk"), R.string.key_app_language_zh_hk, R.string.entry_app_language_zh_hk), - ZH_TW(Locale.forLanguageTag("zh-tw"), R.string.key_app_language_zh_tw, R.string.entry_app_language_zh_tw), + ZH_HANS(Locale.forLanguageTag("zh-Hans"), R.string.key_app_language_zh_hans, R.string.entry_app_language_zh_hans), + ZH_HANT_HK(Locale.forLanguageTag("zh-Hant-HK"), R.string.key_app_language_zh_hant_hk, R.string.entry_app_language_zh_hant_hk), + ZH_HANT_TW(Locale.forLanguageTag("zh-Hant-TW"), R.string.key_app_language_zh_hant_tw, R.string.entry_app_language_zh_hant_tw), EN(Locale.forLanguageTag("en"), R.string.key_app_language_en, R.string.entry_app_language_en), FR(Locale.forLanguageTag("fr"), R.string.key_app_language_fr, R.string.entry_app_language_fr), ES(Locale.forLanguageTag("es"), R.string.key_app_language_es, R.string.entry_app_language_es), @@ -20,6 +19,7 @@ enum class Language(val locale: Locale, @KeyRes private val keyRes: Int, private KO(Locale.forLanguageTag("ko"), R.string.key_app_language_ko, R.string.entry_app_language_ko), RU(Locale.forLanguageTag("ru"), R.string.key_app_language_ru, R.string.entry_app_language_ru), AR(Locale.forLanguageTag("ar"), R.string.key_app_language_ar, R.string.entry_app_language_ar), + AUTO(LocaleUtils.getSystemLocale(), R.string.key_app_language_auto, R.string.entry_app_language_auto), ; fun getEntryName(context: Context) = context.getString(entryNameRes) @@ -31,9 +31,39 @@ enum class Language(val locale: Locale, @KeyRes private val keyRes: Int, private companion object { @JvmStatic - fun getPrefLanguage() = Language.values().find { + fun getPrefLanguage() = getPrefLanguageOrNull() ?: AUTO + + @JvmStatic + fun getPrefLanguageOrNull() = Language.values().find { it.getKey() == Pref.getString(R.string.key_app_language, null) - } ?: AUTO + } + + fun setPrefLanguage(locale: Locale) { + val candidates = Language.values().filter { it != AUTO } + val splitLocale = locale.toLanguageTag().split("-") + var maxLettersLen = 3 + do { + candidates.find { + if (maxLettersLen > splitLocale.size) { + return@find false + } + val splitCandidate = it.locale.toLanguageTag().split("-") + if (maxLettersLen > splitCandidate.size) { + return@find false + } + return@find splitCandidate.subList(0, maxLettersLen).joinToString("-") + .startsWith(splitLocale.subList(0, maxLettersLen).joinToString("-"), true) + }?.let { + Pref.putString(R.string.key_app_language, it.getKey()).also { return } + } + } while (--maxLettersLen > 0) + + Pref.putString(R.string.key_app_language, null) + } + + fun setPrefLanguageAuto() { + Pref.putString(R.string.key_app_language, AUTO.getKey()) + } } diff --git a/app/src/main/java/org/autojs/autojs/pref/Pref.kt b/app/src/main/java/org/autojs/autojs/pref/Pref.kt index f3aece9f..1f6f6bd3 100644 --- a/app/src/main/java/org/autojs/autojs/pref/Pref.kt +++ b/app/src/main/java/org/autojs/autojs/pref/Pref.kt @@ -95,13 +95,6 @@ object Pref { resources.getBoolean(R.bool.pref_auto_check_for_updates), ) - @JvmStatic - val isDocumentationLauncherIconShouldShow: Boolean - get() { - val shouldShow = key(R.string.key_documentation_launcher_icon_show) - return getString(R.string.key_documentation_launcher_icon, shouldShow) == shouldShow - } - private val lastUpdatesCheckedTimestamp: Long get() = getTimestamp(R.string.key_last_updates_checked) diff --git a/app/src/main/java/org/autojs/autojs/project/ProjectConfig.java b/app/src/main/java/org/autojs/autojs/project/ProjectConfig.java index b6ff326c..a36dfdcf 100644 --- a/app/src/main/java/org/autojs/autojs/project/ProjectConfig.java +++ b/app/src/main/java/org/autojs/autojs/project/ProjectConfig.java @@ -24,7 +24,7 @@ public class ProjectConfig { public static final String CONFIG_FILE_NAME = "project.json"; - private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final Gson sGson = new GsonBuilder().setPrettyPrinting().create(); @SerializedName("name") private String mName; @@ -64,7 +64,7 @@ public class ProjectConfig { if (json == null) { return null; } - ProjectConfig config = GSON.fromJson(json, ProjectConfig.class); + ProjectConfig config = sGson.fromJson(json, ProjectConfig.class); if (!isValid(config)) { return null; } @@ -209,7 +209,7 @@ public class ProjectConfig { } public String toJson() { - return GSON.toJson(this); + return sGson.toJson(this); } public String getIcon() { diff --git a/app/src/main/java/org/autojs/autojs/rhino/TokenStream.java b/app/src/main/java/org/autojs/autojs/rhino/TokenStream.java index c340297d..0e1731c4 100644 --- a/app/src/main/java/org/autojs/autojs/rhino/TokenStream.java +++ b/app/src/main/java/org/autojs/autojs/rhino/TokenStream.java @@ -1161,7 +1161,7 @@ public class TokenStream { } // is it a string? - if (c == '"' || c == '\'') { + if (c == '"' || c == '\'' || c == '`') { // We attempt to accumulate a string the fast way, by // building it directly out of the reader. But if there // are any escaped characters in the string, we revert to @@ -1646,7 +1646,7 @@ public class TokenStream { this.string = getStringFromBuffer(); return Token.XML; } - case '\'', '"' -> { + case '\'', '"', '`' -> { addToString(c); if (!readQuotedString(c)) return Token.ERROR; diff --git a/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.java b/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.java index c0edd6de..c833a640 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.java +++ b/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.java @@ -7,7 +7,6 @@ import android.os.Build; import android.os.Looper; import android.util.Log; -import org.autojs.autojs.core.permission.Permissions; import org.autojs.autojs.AutoJs; import org.autojs.autojs.annotation.ScriptInterface; import org.autojs.autojs.annotation.ScriptVariable; @@ -22,6 +21,7 @@ import org.autojs.autojs.core.image.Colors; import org.autojs.autojs.core.image.ImageWrapper; import org.autojs.autojs.core.image.capture.ScreenCaptureRequester; import org.autojs.autojs.core.looper.Loopers; +import org.autojs.autojs.core.permission.Permissions; import org.autojs.autojs.core.web.WebSocket; import org.autojs.autojs.engine.ScriptEngineService; import org.autojs.autojs.lang.ThreadCompat; @@ -32,6 +32,7 @@ import org.autojs.autojs.rhino.TopLevelScope; import org.autojs.autojs.rhino.continuation.Continuation; import org.autojs.autojs.runtime.api.AbstractShell; import org.autojs.autojs.runtime.api.AppUtils; +import org.autojs.autojs.runtime.api.Barcode; import org.autojs.autojs.runtime.api.Device; import org.autojs.autojs.runtime.api.Dialogs; import org.autojs.autojs.runtime.api.Engines; @@ -50,6 +51,7 @@ import org.autojs.autojs.runtime.api.Sensors; import org.autojs.autojs.runtime.api.Threads; import org.autojs.autojs.runtime.api.Timers; import org.autojs.autojs.runtime.api.UI; +import org.autojs.autojs.runtime.api.WrappedShizuku; import org.autojs.autojs.runtime.exception.ScriptEnvironmentException; import org.autojs.autojs.runtime.exception.ScriptException; import org.autojs.autojs.runtime.exception.ScriptInterruptedException; @@ -85,6 +87,8 @@ public class ScriptRuntime { private static final String TAG = "ScriptRuntime"; + public boolean isExiting; + public static void popException(String message) { try { throw new Exception(message); @@ -244,10 +248,13 @@ public class ScriptRuntime { private final Images images; @ScriptVariable - public final ScriptToast toast; + public final OcrMLKit ocrMLKit; @ScriptVariable - public final OcrMLKit ocrMLKit; + public final Barcode barcode; + + @ScriptVariable + public final WrappedShizuku shizuku; @ScriptVariable public final OcrPaddle ocrPaddle; @@ -288,7 +295,8 @@ public class ScriptRuntime { ocrMLKit = new OcrMLKit(); ocrPaddle = new OcrPaddle(); - toast = new ScriptToast(context, this); + barcode = new Barcode(); + shizuku = WrappedShizuku.INSTANCE; } public void init() { @@ -531,6 +539,7 @@ public class ScriptRuntime { @SuppressWarnings("ResultOfMethodCallIgnored") public void onExit() { Log.d(TAG, "on exit"); + this.isExiting = true; ignoresException(() -> { if (console.getConfigurator().isExitOnClose()) { @@ -555,6 +564,7 @@ public class ScriptRuntime { ignoresException(floaty::closeAll); ignoresException(() -> events.emit("exit"), "exception on exit: %s"); + ignoresException(() -> ScriptToast.clear(this)); ignoresException(threads::shutDownAll); ignoresException(events::recycle); diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/AbstractShell.java b/app/src/main/java/org/autojs/autojs/runtime/api/AbstractShell.java index e44d2ac6..68f9049b 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/AbstractShell.java +++ b/app/src/main/java/org/autojs/autojs/runtime/api/AbstractShell.java @@ -5,6 +5,10 @@ import android.text.TextUtils; import androidx.annotation.NonNull; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.SerializedName; + import org.autojs.autojs.engine.RootAutomatorEngine; /** @@ -13,26 +17,42 @@ import org.autojs.autojs.engine.RootAutomatorEngine; public abstract class AbstractShell { public static class Result { + + private static final Gson sGson = new GsonBuilder().setPrettyPrinting().create(); + + @SerializedName("code") public int code = -1; - public String error; - public String result; + + @SerializedName("result") + public String result = ""; + + @SerializedName("error") + public String error = ""; @NonNull @Override public String toString() { return "ShellResult{" + "code=" + code + - ", error='" + error + '\'' + - ", result='" + result + '\'' + + ", error=\"" + error + '"' + + ", result=\"" + result + '"' + '}'; } + + public String toJson() { + return sGson.toJson(this); + } + + public static Result fromJson(String json) { + return sGson.fromJson(json, Result.class); + } + } - protected static final String COMMAND_SU = "su"; - protected static final String COMMAND_SH = "sh"; - protected static final String COMMAND_EXIT = "exit\n"; - protected static final String COMMAND_LINE_END = "\n"; - + public static final String COMMAND_SU = "su"; + public static final String COMMAND_SH = "sh"; + public static final String COMMAND_LINE_END = "\n"; + public static final String COMMAND_EXIT = "exit" + COMMAND_LINE_END; private int mTouchDevice = -1; private ScreenMetrics mScreenMetrics; @@ -91,7 +111,6 @@ public abstract class AbstractShell { mScreenMetrics = screenMetrics; } - public void Touch(int x, int y) { TouchX(x); TouchY(y); diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/AppUtils.kt b/app/src/main/java/org/autojs/autojs/runtime/api/AppUtils.kt index 055fb93c..33c8c55f 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/AppUtils.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/AppUtils.kt @@ -184,11 +184,9 @@ class AppUtils { companion object { - @JvmStatic - val activityShortFormPrefix = "class." + const val activityShortFormPrefix = "class." - @JvmStatic - val broadcastShortFormPrefix = "broadcast." + const val broadcastShortFormPrefix = "broadcast." enum class ActivityShortForm(val shortName: String) { @@ -237,23 +235,12 @@ class AppUtils { @JvmStatic fun isActivityShortForm(s: String) = ActivityShortForm.values().any { it.shortName.contentEquals(s) } - @JvmStatic - fun showLauncherIcon(context: Context, cls: Class<*>) { - context.packageManager.setComponentEnabledSetting(ComponentName(context, cls), COMPONENT_ENABLED_STATE_ENABLED, DONT_KILL_APP) - } - - @JvmStatic - fun hideLauncherIcon(context: Context, cls: Class<*>) { - context.packageManager.setComponentEnabledSetting(ComponentName(context, cls), COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP) - } - fun getInstalledApplications(context: Context): List = context.packageManager.let { when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> { it.getInstalledApplications(ApplicationInfoFlags.of(GET_META_DATA.toLong())) } else -> { - @Suppress("DEPRECATION") it.getInstalledApplications(GET_META_DATA) } } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/Barcode.kt b/app/src/main/java/org/autojs/autojs/runtime/api/Barcode.kt new file mode 100644 index 00000000..2c2466f1 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/runtime/api/Barcode.kt @@ -0,0 +1,72 @@ +package org.autojs.autojs.runtime.api + +import android.util.Log +import com.google.mlkit.vision.barcode.BarcodeScannerOptions +import com.google.mlkit.vision.barcode.BarcodeScanning +import com.google.mlkit.vision.common.InputImage +import org.autojs.autojs.core.image.ImageWrapper +import com.google.mlkit.vision.barcode.common.Barcode as MLKitBarcode + +/** + * Created by SuperMonster003 on Oct 10, 2023. + */ +class Barcode { + + @JvmOverloads + fun detect(image: ImageWrapper?, formats: IntArray = intArrayOf(), enableAllPotentialBarcodes: Boolean = false): Array { + image?.takeUnless { image.isRecycled } ?: return emptyArray() + + val options = BarcodeScannerOptions.Builder() + .setBarcodeFormats(MLKitBarcode.FORMAT_ALL_FORMATS, *formats) + .apply { if (enableAllPotentialBarcodes) enableAllPotentialBarcodes() } + .build() + + val scanner = BarcodeScanning.getClient(options) + val inputImage = InputImage.fromBitmap(image.bitmap, 0) + + var results: Array? = null + + val resultScan = scanner.process(inputImage) + .addOnSuccessListener { barcodes: MutableList -> + results = barcodes.map { WrappedBarcode(it) }.toTypedArray() + lockNotify() + } + .addOnFailureListener { e -> + e.printStackTrace() + lockNotify() + } + .addOnCanceledListener { lockNotify() } + .addOnCompleteListener { lockNotify() } + + while (!resultScan.isComplete) { + synchronized(lock) { + try { + lock.wait(50) + } catch (_: InterruptedException) { + // Ignored. + } + } + } + + image.shoot() + + if (!resultScan.isSuccessful) { + Log.w(TAG, "Barcode scanning is not successful") + } + return results ?: emptyArray() + } + + private fun lockNotify() = synchronized(lock) { lock.notify() } + + companion object { + + private val lock = Object() + + private val TAG: String = Companion::class.java.simpleName + + const val TYPE_NAME_UNKNOWN = "TYPE_NAME_UNKNOWN" + const val FORMAT_NAME_UNKNOWN = "FORMAT_NAME_UNKNOWN" + + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/IWrappedBarcode.kt b/app/src/main/java/org/autojs/autojs/runtime/api/IWrappedBarcode.kt new file mode 100644 index 00000000..d10a63bb --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/runtime/api/IWrappedBarcode.kt @@ -0,0 +1,15 @@ +package org.autojs.autojs.runtime.api + +import com.google.mlkit.vision.barcode.common.internal.BarcodeSource + +interface IWrappedBarcode : BarcodeSource { + + fun getFormatName(): String + + fun getValueTypeName(): String + + fun getType(): Int + + fun getTypeName(): String + +} diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/Images.java b/app/src/main/java/org/autojs/autojs/runtime/api/Images.java index 03309418..9a8bb558 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/Images.java +++ b/app/src/main/java/org/autojs/autojs/runtime/api/Images.java @@ -18,6 +18,7 @@ import android.view.Gravity; import androidx.annotation.NonNull; +import org.autojs.autojs.annotation.ScriptInterface; import org.autojs.autojs.annotation.ScriptVariable; import org.autojs.autojs.concurrent.VolatileDispose; import org.autojs.autojs.core.image.ColorFinder; @@ -371,6 +372,7 @@ public class Images { return new Mat(mat, roi); } + @ScriptInterface public void initOpenCvIfNeeded() { if (mOpenCvInitialized || OpenCVHelper.isInitialized()) { return; @@ -388,7 +390,6 @@ public class Images { }); result.blockedGet(); } - } private void initSuccessfully() { @@ -396,4 +397,8 @@ public class Images { Log.i(TAG, "opencv: initialized"); } + public ScreenCapturer getScreenCapturer() { + return mScreenCapturer; + } + } \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/OcrMLKit.kt b/app/src/main/java/org/autojs/autojs/runtime/api/OcrMLKit.kt index f9cf02f0..50e48180 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/OcrMLKit.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/OcrMLKit.kt @@ -69,6 +69,7 @@ class OcrMLKit { } fun recognizeText(image: ImageWrapper?): Array { + image?.takeUnless { image.isRecycled } ?: return emptyArray() initIfNeeded() val words = detect(image).sorted() val output = mutableListOf() diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/ProcessShell.java b/app/src/main/java/org/autojs/autojs/runtime/api/ProcessShell.java index 7231ad16..a23d1f6c 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/ProcessShell.java +++ b/app/src/main/java/org/autojs/autojs/runtime/api/ProcessShell.java @@ -55,8 +55,8 @@ public class ProcessShell extends AbstractShell { public void exec(String command) { try { mCommandOutputStream.writeBytes(command); - if (!command.endsWith(AbstractShell.COMMAND_LINE_END)) { - mCommandOutputStream.writeBytes(AbstractShell.COMMAND_LINE_END); + if (!command.endsWith(COMMAND_LINE_END)) { + mCommandOutputStream.writeBytes(COMMAND_LINE_END); } mCommandOutputStream.flush(); } catch (IOException e) { @@ -92,7 +92,7 @@ public class ProcessShell extends AbstractShell { @Override public void exitAndWaitFor() { - exec(AbstractShell.COMMAND_EXIT); + exec(COMMAND_EXIT); waitFor(); exit(); } @@ -118,7 +118,7 @@ public class ProcessShell extends AbstractShell { try { String line; while ((line = reader.readLine()) != null) { - sb.append(line).append("\n"); + sb.append(line).append(COMMAND_LINE_END); } } catch (IOException e) { throw new UncheckedIOException(e); @@ -151,7 +151,7 @@ public class ProcessShell extends AbstractShell { } public static Result exec(String command, boolean isRoot) { - String[] commands = command.split("\n"); + String[] commands = command.split(COMMAND_LINE_END); return exec(commands, isRoot); } @@ -162,7 +162,7 @@ public class ProcessShell extends AbstractShell { for (String command : commands) { shell.exec(command); } - shell.exec(AbstractShell.COMMAND_EXIT); + shell.exec(COMMAND_EXIT); Result result = new Result(); result.code = shell.waitFor(); shell.readAll(); @@ -178,22 +178,35 @@ public class ProcessShell extends AbstractShell { } public static Result execCommand(String[] commands, boolean isRoot) { + try { + Process process = isRoot ? getRootProcess() : getShellProcess(); + return execCommand(commands, process); + } catch (Exception e) { + Result result = new Result(); + String message = e.getMessage(); + result.code = 1; + result.result = ""; + result.error = message != null ? message : ""; + return result; + } + } + + public static Result execCommand(String[] commands, Process process) { Result commandResult = new Result(); - if (commands == null || commands.length == 0) + if (commands == null || commands.length == 0) { throw new IllegalArgumentException(str(R.string.error_empty_shell_command)); - Process process = null; + } DataOutputStream os = null; try { - process = Runtime.getRuntime().exec(isRoot ? AbstractShell.COMMAND_SU : AbstractShell.COMMAND_SH); os = new DataOutputStream(process.getOutputStream()); for (String command : commands) { if (command != null) { os.write(command.getBytes()); - os.writeBytes(AbstractShell.COMMAND_LINE_END); + os.writeBytes(COMMAND_LINE_END); os.flush(); } } - os.writeBytes(AbstractShell.COMMAND_EXIT); + os.writeBytes(COMMAND_EXIT); os.flush(); Log.d(TAG, "pid = " + ProcessUtils.getProcessPid(process)); commandResult.code = process.waitFor(); @@ -232,18 +245,26 @@ public class ProcessShell extends AbstractShell { return commandResult; } + public static Process getShellProcess() throws IOException { + return Runtime.getRuntime().exec(COMMAND_SH); + } + + public static Process getRootProcess() throws IOException { + return Runtime.getRuntime().exec(COMMAND_SU); + } + private static String readAll(InputStream inputStream) throws IOException { String line; StringBuilder builder = new StringBuilder(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); while ((line = reader.readLine()) != null) { - builder.append(line).append('\n'); + builder.append(line).append(COMMAND_LINE_END); } return builder.toString(); } public static Result execCommand(String command, boolean withRoot) { - String[] commands = command.split("\n"); + String[] commands = command.split(COMMAND_LINE_END); return execCommand(commands, withRoot); } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/ScriptToast.java b/app/src/main/java/org/autojs/autojs/runtime/api/ScriptToast.java deleted file mode 100644 index e5755735..00000000 --- a/app/src/main/java/org/autojs/autojs/runtime/api/ScriptToast.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.autojs.autojs.runtime.api; - -import android.content.Context; -import android.os.Handler; -import android.util.Log; -import android.widget.Toast; - -import org.autojs.autojs.runtime.ScriptRuntime; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Created by SuperMonster003 on Aug 3, 2023. - */ -public class ScriptToast { - - private static final String TAG = ScriptToast.class.getSimpleName(); - private final Context mContext; - private final ScriptRuntime mScriptRuntime; - private final Handler mUiHandler; - - private static final ConcurrentHashMap pool = new ConcurrentHashMap<>(); - - public ScriptToast(Context context, ScriptRuntime runtime) { - mContext = context; - mScriptRuntime = runtime; - mUiHandler = mScriptRuntime.uiHandler; - } - - // @Caution by SuperMonster003 on Oct 11, 2022. - // ! android.widget.ScriptToast.makeText() doesn't work well on Android API Level 28 (Android 9) [P]. - // ! There hasn't been a solution for this so far. - // ! Tested devices: - // ! 1. SONY XPERIA XZ1 Compact (G8441) - // ! 2. Android Studio AVD (Android 9.0 x86) - public void makeToast(String msg, boolean isLong, boolean isForcible) { - synchronized (ScriptToast.class) { - if (isForcible) { - dismissAll(); - } - Toast toast = Toast.makeText(mContext, msg, isLong ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT); - Log.d(TAG + " new toast", toast.toString()); - toast.show(); - Log.d(TAG + " before put", pool.toString()); - pool.put(toast, mScriptRuntime); - Log.d(TAG + " after put", pool.toString()); - addCallback(toast); - } - } - - private void addCallback(Toast toast) { - // FIXME by SuperMonster003 on Aug 3, 2023. - // ! A more graceful way is needed. - // @Hint by SuperMonster003 on Aug 3, 2023. - // ! It is proved that Toast.Callback for Android API Level 30+ - // ! was not a good replacement. - mUiHandler.postDelayed(() -> dismiss(toast), getAccumulatedDuration()); - } - - private long getAccumulatedDuration() { - var sum = 200L; - for (Map.Entry entry : pool.entrySet()) { - Toast toast = entry.getKey(); - sum += toast.getDuration() == Toast.LENGTH_SHORT ? 2_000L : 3_500L; - } - return sum; - } - - private void dismiss(Toast aim) { - Log.d(TAG + " before dismiss", pool.toString()); - for (Map.Entry entry : pool.entrySet()) { - Toast toast = entry.getKey(); - ScriptRuntime scriptRuntime = entry.getValue(); - if (scriptRuntime == mScriptRuntime && toast == aim) { - toast.cancel(); - pool.remove(toast); - } - } - Log.d(TAG + " after dismiss", pool.toString()); - } - - public void dismissAll() { - Log.d(TAG + " before disAll", pool.toString()); - for (Map.Entry entry : pool.entrySet()) { - Toast toast = entry.getKey(); - ScriptRuntime scriptRuntime = entry.getValue(); - if (scriptRuntime == mScriptRuntime) { - toast.cancel(); - pool.remove(toast); - } - } - Log.d(TAG + " after disAll", pool.toString()); - } - -} diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/ScriptToast.kt b/app/src/main/java/org/autojs/autojs/runtime/api/ScriptToast.kt new file mode 100644 index 00000000..a02114bf --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/runtime/api/ScriptToast.kt @@ -0,0 +1,43 @@ +package org.autojs.autojs.runtime.api + +import android.widget.Toast +import org.autojs.autojs.runtime.ScriptRuntime +import java.util.concurrent.ConcurrentHashMap + +/** + * Created by SuperMonster003 on Aug 3, 2023. + * Modified by SuperMonster003 as of Oct 24, 2023. + * Transformed by SuperMonster003 on Oct 24, 2023. + */ +object ScriptToast { + + @JvmField + val pool = ConcurrentHashMap() + + @JvmStatic + fun add(t: Any?, scriptRuntime: ScriptRuntime) { + if (t is Toast) { + pool[t] = scriptRuntime + } + } + + @JvmStatic + fun dismissAll(scriptRuntime: ScriptRuntime) { + for (entry in pool.entries) { + if (entry.value === scriptRuntime) { + entry.key.cancel() + pool.remove(entry.key, scriptRuntime) + } + } + } + + @JvmStatic + fun clear(scriptRuntime: ScriptRuntime) { + for (entry in pool.entries) { + if (entry.value === scriptRuntime) { + pool.remove(entry.key, scriptRuntime) + } + } + } + +} diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/WrappedBarcode.kt b/app/src/main/java/org/autojs/autojs/runtime/api/WrappedBarcode.kt new file mode 100644 index 00000000..edbfd126 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/runtime/api/WrappedBarcode.kt @@ -0,0 +1,78 @@ +package org.autojs.autojs.runtime.api + +import android.graphics.Point +import android.graphics.Rect +import org.autojs.autojs.runtime.api.Barcode.Companion.FORMAT_NAME_UNKNOWN +import org.autojs.autojs.runtime.api.Barcode.Companion.TYPE_NAME_UNKNOWN +import java.lang.reflect.Field +import java.lang.reflect.Modifier +import com.google.mlkit.vision.barcode.common.Barcode as MLKitBarcode + + +class WrappedBarcode(val barcode: MLKitBarcode) : IWrappedBarcode { + + override fun getFormat(): Int = barcode.format + + override fun getFormatName(): String { + val declaredFields: Array = MLKitBarcode::class.java.declaredFields + for (field in declaredFields) { + if (Modifier.isStatic(field.modifiers)) { + if (field.type == Int::class.java && field.name.startsWith("FORMAT_")) { + if (field.getInt(barcode) == barcode.format) { + return field.name + } + } + } + } + return FORMAT_NAME_UNKNOWN + } + + override fun getValueType(): Int = barcode.valueType + + override fun getType(): Int = valueType + + override fun getValueTypeName(): String = getTypeName() + + override fun getTypeName(): String { + val declaredFields: Array = MLKitBarcode::class.java.declaredFields + for (field in declaredFields) { + if (Modifier.isStatic(field.modifiers)) { + if (field.type == Int::class.java && field.name.startsWith("TYPE_")) { + if (field.getInt(barcode) == barcode.valueType) { + return field.name + } + } + } + } + return TYPE_NAME_UNKNOWN + } + + override fun getBoundingBox(): Rect? = barcode.boundingBox + + override fun getCalendarEvent(): MLKitBarcode.CalendarEvent? = barcode.calendarEvent + + override fun getContactInfo(): MLKitBarcode.ContactInfo? = barcode.contactInfo + + override fun getDriverLicense(): MLKitBarcode.DriverLicense? = barcode.driverLicense + + override fun getEmail(): MLKitBarcode.Email? = barcode.email + + override fun getGeoPoint(): MLKitBarcode.GeoPoint? = barcode.geoPoint + + override fun getPhone(): MLKitBarcode.Phone? = barcode.phone + + override fun getSms(): MLKitBarcode.Sms? = barcode.sms + + override fun getUrl(): MLKitBarcode.UrlBookmark? = barcode.url + + override fun getWifi(): MLKitBarcode.WiFi? = barcode.wifi + + override fun getDisplayValue(): String? = barcode.displayValue + + override fun getRawValue(): String? = barcode.rawValue + + override fun getRawBytes(): ByteArray? = barcode.rawBytes + + override fun getCornerPoints(): Array? = barcode.cornerPoints + +} diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt b/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt new file mode 100644 index 00000000..94ed803c --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt @@ -0,0 +1,146 @@ +package org.autojs.autojs.runtime.api + +import android.content.ComponentName +import android.content.ServiceConnection +import android.content.pm.PackageManager +import android.os.IBinder +import android.util.Log +import org.autojs.autojs.App +import org.autojs.autojs.annotation.ScriptInterface +import org.autojs.autojs.core.shizuku.IUserService +import org.autojs.autojs.core.shizuku.UserService +import org.autojs.autojs6.BuildConfig +import rikka.shizuku.Shizuku +import org.autojs.autojs.runtime.api.AbstractShell.Result as ShellResult + +/** + * Created by SuperMonster003 on Oct 19, 2023. + */ +object WrappedShizuku { + + @JvmField + var service: IUserService? = null + + private val TAG: String = WrappedShizuku::class.java.simpleName + + private val mRequestCode = "shizuku-request-code".hashCode() + + private val mUserServiceConnection: ServiceConnection = object : ServiceConnection { + override fun onServiceConnected(componentName: ComponentName, binder: IBinder?) { + Log.d(TAG, "onServiceConnected: ${componentName.className}") + if (binder?.pingBinder() == true) { + service = IUserService.Stub.asInterface(binder) + } else { + Log.w(TAG, "invalid binder for $componentName received") + } + } + + override fun onServiceDisconnected(componentName: ComponentName) { + // ... ... + } + } + + private val mUserServiceArgs = Shizuku.UserServiceArgs(ComponentName(BuildConfig.APPLICATION_ID, UserService::class.java.name)) + .daemon(false) + .processNameSuffix("service-for-${BuildConfig.APPLICATION_ID.split(".").lastOrNull() ?: "autojs"}") + .debuggable(BuildConfig.DEBUG) + .version(BuildConfig.VERSION_CODE) + + private val mBinderReceivedListener = { + // if (Shizuku.isPreV11()) { + // binding.text1.setText("Shizuku pre-v11 is not supported") + // } else { + // binding.text1.setText("Binder received") + // } + } + + private val mBinderDeadListener = { + // binding.text1.setText("Binder dead") + } + + private val mRequestPermissionResultListener: (requestCode: Int, grantResult: Int) -> Unit = { requestCode: Int, grantResult: Int -> + if (grantResult == PackageManager.PERMISSION_GRANTED && requestCode == mRequestCode) { + bindUserService() + } + } + + internal fun onCreate() { + Log.d(TAG, "${App::class.java.simpleName} onCreate | Process=${App.getProcessNameCompat()}") + Shizuku.addBinderReceivedListenerSticky(mBinderReceivedListener) + Shizuku.addBinderDeadListener(mBinderDeadListener) + Shizuku.addRequestPermissionResultListener(mRequestPermissionResultListener) + } + + private fun bindUserService() { + val res = StringBuilder() + try { + if (Shizuku.getVersion() < 10) { + res.append("requires Shizuku API 10") + } else { + Shizuku.bindUserService(mUserServiceArgs, mUserServiceConnection) + } + } catch (tr: Throwable) { + tr.printStackTrace() + res.append(tr) + } + // binding.text3.setText(res.toString().trim { it <= ' ' }) + } + + private fun unbindUserService() { + val res = StringBuilder() + try { + if (Shizuku.getVersion() < 10) { + res.append("requires Shizuku API 10") + } else { + Shizuku.unbindUserService(mUserServiceArgs, mUserServiceConnection, true) + } + } catch (tr: Throwable) { + tr.printStackTrace() + res.append(tr) + } + // binding.text3.setText(res.toString().trim { it <= ' ' }) + } + + internal fun checkShizukuPermission() = try { + when { + Shizuku.isPreV11() -> false + Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED -> true.also { bindUserService() } + Shizuku.shouldShowRequestPermissionRationale() -> false + else -> false.also { Shizuku.requestPermission(mRequestCode) } + } + } catch (e: Throwable) { + false.also { e.printStackTrace() } + } + + @ScriptInterface + fun execCommand(cmd: String): ShellResult { + ensureService() + return try { + ShellResult.fromJson(service!!.execCommand(cmd)) + } catch (e: Exception) { + ShellResult().apply { + code = 1 + error = e.message ?: "" + result = "" + }.also { e.printStackTrace() } + } + } + + @ScriptInterface + fun execCommand(cmdList: Array): ShellResult { + return execCommand(cmdList.joinToString("\n")) + } + + @ScriptInterface + fun ensureService() { + service ?: throw IllegalStateException("Shizuku service is not available") + } + + internal fun onDestroy() { + unbindUserService() + Shizuku.removeBinderReceivedListener(mBinderReceivedListener) + Shizuku.removeBinderDeadListener(mBinderDeadListener) + Shizuku.removeRequestPermissionResultListener(mRequestPermissionResultListener) + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/script/JavaScriptSource.java b/app/src/main/java/org/autojs/autojs/script/JavaScriptSource.java index 9a4c5071..59154f4f 100644 --- a/app/src/main/java/org/autojs/autojs/script/JavaScriptSource.java +++ b/app/src/main/java/org/autojs/autojs/script/JavaScriptSource.java @@ -5,6 +5,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import org.autojs.autojs.pref.Language; import org.autojs.autojs.rhino.TokenStream; import org.autojs.autojs.tool.MapBuilder; import org.mozilla.javascript.Token; @@ -22,19 +23,23 @@ public abstract class JavaScriptSource extends ScriptSource { public static final String EXECUTION_MODE_UI_PREFIX = "\"ui\";"; - public static final int EXECUTION_MODE_NORMAL = 0; - public static final int EXECUTION_MODE_UI = 0x00000001; - public static final int EXECUTION_MODE_AUTO = 0x00000002; + public static final int EXECUTION_MODE_RAW = -0x1; + public static final int EXECUTION_MODE_NORMAL = 0x0; + public static final int EXECUTION_MODE_UI = 0x1; + public static final int EXECUTION_MODE_AUTO = 0x2; + public static final int EXECUTION_MODE_MODULE_CHEERIO = 0x10; private static final String LOG_TAG = "JavaScriptSource"; private static final Map EXECUTION_MODES = new MapBuilder() .put("ui", EXECUTION_MODE_UI) .put("auto", EXECUTION_MODE_AUTO) + .put("cheerio", EXECUTION_MODE_MODULE_CHEERIO) .build(); + private static final int PARSING_MAX_TOKEN = 300; - private int mExecutionMode = -1; + private int mExecutionMode = EXECUTION_MODE_RAW; public JavaScriptSource(String name) { super(name); @@ -62,7 +67,7 @@ public abstract class JavaScriptSource extends ScriptSource { } public int getExecutionMode() { - if (mExecutionMode == -1) { + if (mExecutionMode == EXECUTION_MODE_RAW) { mExecutionMode = parseExecutionMode(); } return mExecutionMode; @@ -79,28 +84,27 @@ public abstract class JavaScriptSource extends ScriptSource { if (token == Token.EOL || token == Token.COMMENT) { continue; } - if (token == Token.STRING && ts.getTokenLength() > 2) { - String tokenString = script.substring(ts.getTokenBeg() + 1, ts.getTokenEnd() - 1); - if (ts.getToken() != Token.SEMI) { - break; - } - Log.d(LOG_TAG, "string = " + tokenString); - return parseExecutionMode(tokenString.split(" ")); + if (token != Token.STRING || ts.getTokenLength() < 3) { + break; } - break; + String tokenString = script.substring(ts.getTokenBeg() + 1, ts.getTokenEnd() - 1); + if (ts.getToken() != Token.SEMI) { + break; + } + Log.d(LOG_TAG, "string = " + tokenString); + return parseExecutionMode(tokenString.split("\\s*[,;|]\\s*|\\s+")); } } catch (Exception e) { e.printStackTrace(); - return EXECUTION_MODE_NORMAL; } return EXECUTION_MODE_NORMAL; - } private int parseExecutionMode(String[] modeStrings) { - int mode = 0; + int mode = EXECUTION_MODE_NORMAL; for (String modeString : modeStrings) { - Integer i = EXECUTION_MODES.get(modeString); + String niceModeString = modeString.toLowerCase(Language.getPrefLanguage().getLocale()); + Integer i = EXECUTION_MODES.get(niceModeString); if (i != null) { mode |= i; } diff --git a/app/src/main/java/org/autojs/autojs/theme/ThemeColorManager.kt b/app/src/main/java/org/autojs/autojs/theme/ThemeColorManager.kt index d54c51d8..0d05aac0 100644 --- a/app/src/main/java/org/autojs/autojs/theme/ThemeColorManager.kt +++ b/app/src/main/java/org/autojs/autojs/theme/ThemeColorManager.kt @@ -14,7 +14,7 @@ import java.util.Vector */ object ThemeColorManager { - @JvmStatic + @JvmField var defaultThemeColor = ThemeColor(ColorUtils.fromResources(R.color.theme_color_default)) @JvmStatic diff --git a/app/src/main/java/org/autojs/autojs/tool/UiHandler.java b/app/src/main/java/org/autojs/autojs/tool/UiHandler.java deleted file mode 100644 index 3e4b503b..00000000 --- a/app/src/main/java/org/autojs/autojs/tool/UiHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.autojs.autojs.tool; - -import android.content.Context; -import android.os.Handler; -import android.os.Looper; - -import org.autojs.autojs.util.ViewUtils; - -/** - * Created by Stardust on 2017/5/2. - */ -public class UiHandler extends Handler { - - private final Context mContext; - - public UiHandler(Context context) { - super(Looper.getMainLooper()); - mContext = context; - } - - public Context getContext() { - return mContext; - } - - public void toast(final String message) { - post(() -> ViewUtils.showToast(mContext, message)); - } - - public void toast(final int resId) { - post(() -> ViewUtils.showToast(mContext, resId)); - } - -} diff --git a/app/src/main/java/org/autojs/autojs/tool/UiHandler.kt b/app/src/main/java/org/autojs/autojs/tool/UiHandler.kt new file mode 100644 index 00000000..b5ae1cdd --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/tool/UiHandler.kt @@ -0,0 +1,46 @@ +package org.autojs.autojs.tool + +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.widget.Toast +import android.widget.Toast.LENGTH_LONG +import android.widget.Toast.LENGTH_SHORT +import org.autojs.autojs.AutoJs +import org.autojs.autojs.annotation.ScriptInterface +import org.autojs.autojs.app.GlobalAppContext +import org.autojs.autojs.runtime.api.ScriptToast + +/** + * Created by Stardust on 2017/5/2. + * Transformed by SuperMonster003 on Oct 25, 2023. + */ +class UiHandler(val context: Context) : Handler(Looper.getMainLooper()) { + + @ScriptInterface + @JvmOverloads + fun toast(message: String?, isLong: Boolean = false) { + post { + message?.let { + val rawToast = Toast.makeText(context, it, if (isLong) LENGTH_LONG else LENGTH_SHORT) + when (Looper.getMainLooper() == Looper.myLooper()) { + true -> addAndShow(rawToast) + else -> GlobalAppContext.post { addAndShow(rawToast) } + } + } + } + } + + @ScriptInterface + @JvmOverloads + fun toast(resId: Int, isLong: Boolean = false) = toast(context.getString(resId), isLong) + + @ScriptInterface + fun dismissAllToasts() = ScriptToast.dismissAll(AutoJs.instance.runtime) + + private fun addAndShow(rawToast: Toast) { + rawToast.show() + ScriptToast.add(rawToast, AutoJs.instance.runtime) + } + +} diff --git a/app/src/main/java/org/autojs/autojs/ui/BaseActivity.kt b/app/src/main/java/org/autojs/autojs/ui/BaseActivity.kt index 600641bd..a9df0633 100644 --- a/app/src/main/java/org/autojs/autojs/ui/BaseActivity.kt +++ b/app/src/main/java/org/autojs/autojs/ui/BaseActivity.kt @@ -3,15 +3,13 @@ package org.autojs.autojs.ui import android.content.Context -import android.content.res.Configuration +import android.os.Build import android.os.Bundle import android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.app.AppCompatDelegate -import com.zeugmasolutions.localehelper.LocaleHelper -import com.zeugmasolutions.localehelper.LocaleHelperActivityDelegate -import com.zeugmasolutions.localehelper.LocaleHelperActivityDelegateImpl +import org.autojs.autojs.pref.Language import org.autojs.autojs.theme.ThemeColorManager +import org.autojs.autojs.util.LocaleUtils import org.autojs.autojs.util.ViewUtils /** @@ -20,8 +18,6 @@ import org.autojs.autojs.util.ViewUtils */ abstract class BaseActivity : AppCompatActivity() { - private val localeDelegate: LocaleHelperActivityDelegate = LocaleHelperActivityDelegateImpl() - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -38,15 +34,16 @@ abstract class BaseActivity : AppCompatActivity() { } ViewUtils.makeBarsAdaptToNightMode(this) - localeDelegate.onCreate(this) + + setLocaleForAutoLanguageIfNeeded(this) } - override fun getDelegate(): AppCompatDelegate { - return localeDelegate.getAppCompatDelegate(super.getDelegate()) - } - - override fun attachBaseContext(newBase: Context) { - super.attachBaseContext(localeDelegate.attachBaseContext(newBase)) + private fun setLocaleForAutoLanguageIfNeeded(context: Context) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + if (Language.getPrefLanguage().isAuto()) { + LocaleUtils.setFollowSystem(context) + } + } } override fun onStart() { @@ -58,21 +55,9 @@ abstract class BaseActivity : AppCompatActivity() { override fun onResume() { super.onResume() - localeDelegate.onResumed(this) + LocaleUtils.syncPrefWithCurrentStateIfNeeded(this) } - override fun onPause() { - super.onPause() - localeDelegate.onPaused() - } - - override fun createConfigurationContext(overrideConfiguration: Configuration): Context { - val context = super.createConfigurationContext(overrideConfiguration) - return LocaleHelper.onAttach(context) - } - - override fun getApplicationContext() = localeDelegate.getApplicationContext(super.getApplicationContext()) - fun setToolbarAsBack(titleRes: Int) = ViewUtils.setToolbarAsBack(this, titleRes) fun setToolbarAsBack(title: String?) = ViewUtils.setToolbarAsBack(this, title) diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java b/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java index a99993c2..946b6abe 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java @@ -183,6 +183,8 @@ public class EditorMenu { dialog.dismiss(); }) .onNegative((ignored, which) -> { + // TODO by SuperMonster003 on Oct 20, 2023. + // ! Check by execution mode in class org.autojs.autojs.script.JavaScriptSource . if (mEditor.getText().startsWith(JavaScriptSource.EXECUTION_MODE_UI_PREFIX)) { mEditor.insert(1, item.getImportText() + ";\n"); } else { diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.kt b/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.kt index 8d29a5b5..6b990e14 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.kt +++ b/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.kt @@ -89,6 +89,10 @@ import java.io.File // FIXME by SuperMonster003 on May 13, 2023. // ! Failed many times to migrate this view with annotation to view binding. // ! And this is the last view with annotation in the whole project so far. +// FIXME by SuperMonster003 on Oct 18, 2023. +// ! Gradle property "android.nonFinalResIds" +// ! can't be enabled (by default since Android Gradle Plugin version 8.0), +// ! as final resource ID used in current class. open class EditorView : FrameLayout, OnHintClickListener, ClickCallback, ToolbarFragment.OnMenuItemClickListener { @JvmField diff --git a/app/src/main/java/org/autojs/autojs/ui/filechooser/FileChooserDialogBuilder.java b/app/src/main/java/org/autojs/autojs/ui/filechooser/FileChooserDialogBuilder.java index 051641b0..9edf4fea 100644 --- a/app/src/main/java/org/autojs/autojs/ui/filechooser/FileChooserDialogBuilder.java +++ b/app/src/main/java/org/autojs/autojs/ui/filechooser/FileChooserDialogBuilder.java @@ -85,7 +85,7 @@ public class FileChooserDialogBuilder extends MaterialDialog.Builder { } public FileChooserDialogBuilder justScriptFile() { - mFileFilter = Scripts.getFILE_FILTER(); + mFileFilter = Scripts.FILE_FILTER; return this; } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt b/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt index 9791c873..e48c44b2 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt +++ b/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt @@ -12,14 +12,12 @@ import android.view.Gravity import android.view.Menu import android.view.MenuItem import android.view.View -import android.view.WindowManager import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions import androidx.appcompat.app.ActionBarDrawerToggle import androidx.drawerlayout.widget.DrawerLayout import androidx.fragment.app.Fragment import androidx.viewpager.widget.ViewPager.SimpleOnPageChangeListener import com.google.android.material.floatingactionbutton.FloatingActionButton -import org.autojs.autojs.App import org.autojs.autojs.AutoJs import org.autojs.autojs.app.FragmentPagerAdapterBuilder import org.autojs.autojs.app.FragmentPagerAdapterBuilder.StoredFragmentPagerAdapter @@ -36,11 +34,9 @@ import org.autojs.autojs.permission.DisplayOverOtherAppsPermission import org.autojs.autojs.permission.ManageAllFilesPermission import org.autojs.autojs.permission.PostNotificationPermission import org.autojs.autojs.pref.Pref -import org.autojs.autojs.runtime.api.AppUtils.Companion.hideLauncherIcon -import org.autojs.autojs.runtime.api.AppUtils.Companion.showLauncherIcon +import org.autojs.autojs.runtime.api.WrappedShizuku import org.autojs.autojs.theme.ThemeColorManager.addViewBackground import org.autojs.autojs.ui.BaseActivity -import org.autojs.autojs.ui.doc.DocumentationActivity import org.autojs.autojs.ui.doc.DocumentationFragment import org.autojs.autojs.ui.enhancedfloaty.FloatyService import org.autojs.autojs.ui.explorer.ExplorerView @@ -55,14 +51,12 @@ import org.autojs.autojs.ui.settings.PreferencesActivity import org.autojs.autojs.ui.widget.DrawerAutoClose import org.autojs.autojs.ui.widget.SearchViewItem import org.autojs.autojs.util.ForegroundServiceUtils -import org.autojs.autojs.util.StringUtils -import org.autojs.autojs.util.UpdateUtils.autoCheckForUpdatesIfNeededWithSnackbar +import org.autojs.autojs.util.UpdateUtils import org.autojs.autojs.util.ViewUtils import org.autojs.autojs.util.WorkingDirectoryUtils import org.autojs.autojs6.R import org.autojs.autojs6.databinding.ActivityMainBinding import org.greenrobot.eventbus.EventBus -import rikka.shizuku.Shizuku /** * Modified by SuperMonster003 as of Dec 1, 2021. @@ -93,45 +87,6 @@ class MainActivity : BaseActivity(), DelegateHost, HostActivity { } } - private val shizukuBinderReceivedListener = { - // if (Shizuku.isPreV11()) { - // binding.text1.setText("Shizuku pre-v11 is not supported") - // } else { - // binding.text1.setText("Binder received") - // } - } - private val shizukuBinderDeadListener = { - // binding.text1.setText("Binder dead") - } - private val shizukuRequestPermissionResultListener: (requestCode: Int, grantResult: Int) -> Unit = { /* requestCode: */ _: Int, /* grantResult */ _: Int -> - // if (grantResult == PackageManager.PERMISSION_GRANTED) { - // switch (requestCode) { - // case REQUEST_CODE_BUTTON1: { - // getUsers(); - // break; - // } - // case REQUEST_CODE_BUTTON4: { - // getSystemProperty(); - // break; - // } - // case REQUEST_CODE_BUTTON7: { - // bindUserService(); - // break; - // } - // case REQUEST_CODE_BUTTON8: { - // unbindUserService(); - // break; - // } - // case REQUEST_CODE_BUTTON9: { - // peekUserService(); - // break; - // } - // } - // } else { - // binding.text1.setText("User denied permission"); - // } - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -150,34 +105,30 @@ class MainActivity : BaseActivity(), DelegateHost, HostActivity { @Suppress("DEPRECATION") ViewUtils.appendSystemUiVisibility(this, View.SYSTEM_UI_FLAG_LAYOUT_STABLE) + ViewUtils.registerOnSharedPreferenceChangeListener(this) - Pref.registerOnSharedPreferenceChangeListener { _, key -> - if (key == StringUtils.key(R.string.key_keep_screen_on_when_in_foreground)) { - configKeepScreenOnWhenInForeground() - } - } - + WrappedShizuku.onCreate() ExplorerView.clearViewStates() setUpToolbar() setUpTabViewPager() registerBackPressHandlers() addViewBackground(binding.appBar) - - Log.d("Shizuku", "${App::class.java.simpleName} onCreate | Process=${App.getProcessNameCompat()}") - Shizuku.addBinderReceivedListenerSticky(this.shizukuBinderReceivedListener) - Shizuku.addBinderDeadListener(shizukuBinderDeadListener) - Shizuku.addRequestPermissionResultListener(shizukuRequestPermissionResultListener) } override fun onPostResume() { recreateIfNeeded() - autoCheckForUpdatesIfNeededWithSnackbar(this, android.R.id.content) + UpdateUtils.autoCheckForUpdatesIfNeededWithSnackbar(this) super.onPostResume() } + override fun onStart() { + super.onStart() + WrappedShizuku.checkShizukuPermission() + } + private fun recreateIfNeeded() { - if (sShouldRecreateMainActivity) { - setShouldRecreateMainActivity(false) + if (shouldRecreateMainActivity) { + shouldRecreateMainActivity = false recreate() Explorers.workspace().refreshAll() } @@ -290,7 +241,7 @@ class MainActivity : BaseActivity(), DelegateHost, HostActivity { override fun getOnActivityResultDelegateMediator() = mActivityResultMediator - @Suppress("OVERRIDE_DEPRECATION") + @Suppress("OVERRIDE_DEPRECATION", "DEPRECATION") override fun onBackPressed() { val fragment = mPagerAdapter.getStoredFragment(mViewPager.currentItem) if (fragment is BackPressedHandler) { @@ -384,52 +335,22 @@ class MainActivity : BaseActivity(), DelegateHost, HostActivity { override fun onDestroy() { super.onDestroy() EventBus.getDefault().unregister(this) - - Shizuku.removeBinderReceivedListener(this.shizukuBinderReceivedListener) - Shizuku.removeBinderDeadListener(shizukuBinderDeadListener) - Shizuku.removeRequestPermissionResultListener(shizukuRequestPermissionResultListener) + WrappedShizuku.onDestroy() } override fun onResume() { super.onResume() - configKeepScreenOnWhenInForeground() - configDocumentationLauncherIcon() - } - - private fun configKeepScreenOnWhenInForeground() { - WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON.let { flags -> - if (ViewUtils.isKeepScreenOnWhenInForegroundEnabled) { - window.addFlags(flags) - } else { - window.clearFlags(flags) - } - } - } - - private fun configDocumentationLauncherIcon() { - DocumentationActivity::class.java.let { clazz -> - if (Pref.isDocumentationLauncherIconShouldShow) { - showLauncherIcon(this, clazz) - } else { - hideLauncherIcon(this, clazz) - } - } + ViewUtils.configKeepScreenOnWhenInForeground(this) } companion object { private val TAG = MainActivity::class.java.simpleName - private var sShouldRecreateMainActivity = false - - fun setShouldRecreateMainActivity(b: Boolean) { - sShouldRecreateMainActivity = b - } + var shouldRecreateMainActivity = false @JvmStatic - fun launch(context: Context) { - context.startActivity(getIntent(context).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) - } + fun launch(context: Context) = context.startActivity(getIntent(context).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) @JvmStatic fun getIntent(context: Context?) = Intent(context, MainActivity::class.java) diff --git a/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java b/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java index 0cd5a7d6..5779ff94 100644 --- a/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java @@ -1,5 +1,7 @@ package org.autojs.autojs.ui.project; +import static org.autojs.autojs.apkbuilder.ApkBuilderPluginHelper.TEMPLATE_APK_PATH; + import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; @@ -11,6 +13,7 @@ import android.view.View; import android.widget.EditText; import android.widget.ImageView; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.cardview.widget.CardView; @@ -21,6 +24,7 @@ import org.autojs.autojs.apkbuilder.ApkBuilder; import org.autojs.autojs.apkbuilder.ApkBuilderPluginHelper; import org.autojs.autojs.external.fileprovider.AppFileProvider; import org.autojs.autojs.model.script.ScriptFile; +import org.autojs.autojs.pref.Language; import org.autojs.autojs.project.ProjectConfig; import org.autojs.autojs.ui.BaseActivity; import org.autojs.autojs.ui.filechooser.FileChooserDialogBuilder; @@ -107,11 +111,15 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa private boolean checkApkTemplateInAssets() { try { - if (Arrays.asList(getAssets().list("")).contains("template.apk")) { + String[] files = getAssets().list(""); + if (files != null && Arrays.asList(files).contains(TEMPLATE_APK_PATH)) { return true; } } catch (IOException e) { - Log.e(LOG_TAG, e.getMessage()); + String msg = e.getMessage(); + if (msg != null) { + Log.e(LOG_TAG, msg); + } } return false; } @@ -149,10 +157,19 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa } mOutputPath.setText(dir); mAppName.setText(file.getSimplifiedName()); - mPackageName.setText(getString(R.string.format_default_package_name, System.currentTimeMillis())); + mPackageName.setText(getString(R.string.format_default_package_name, getPackageNameSuffix(file))); setSource(file); } + private static String getPackageNameSuffix(ScriptFile file) { + String name = file.getSimplifiedName() + .replaceAll("[^\\w$]+", "_"); + if (name.matches("^\\d.*")) { + name = "app_" + name; + } + return name.toLowerCase(Language.getPrefLanguage().getLocale()); + } + @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); @@ -277,7 +294,9 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa } private ApkBuilder callApkBuilder(File tmpDir, File outApk, ApkBuilder.AppConfig appConfig) throws Exception { - InputStream templateApk = mIsApkTemplateInAssets ? getAssets().open("template.apk") : ApkBuilderPluginHelper.openTemplateApk(BuildActivity.this); + InputStream templateApk = mIsApkTemplateInAssets + ? getAssets().open(TEMPLATE_APK_PATH) + : ApkBuilderPluginHelper.openTemplateApk(BuildActivity.this); return new ApkBuilder(templateApk, outApk, tmpDir.getPath()) .setProgressCallback(BuildActivity.this) .prepare() @@ -319,24 +338,23 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa } @Override - public void onPrepare(ApkBuilder builder) { + public void onPrepare(@NonNull ApkBuilder builder) { mProgressDialog.setContent(R.string.apk_builder_prepare); } @Override - public void onBuild(ApkBuilder builder) { + public void onBuild(@NonNull ApkBuilder builder) { mProgressDialog.setContent(R.string.apk_builder_build); - } @Override - public void onSign(ApkBuilder builder) { + public void onSign(@NonNull ApkBuilder builder) { mProgressDialog.setContent(R.string.apk_builder_package); } @Override - public void onClean(ApkBuilder builder) { + public void onClean(@NonNull ApkBuilder builder) { mProgressDialog.setContent(R.string.apk_builder_clean); } diff --git a/app/src/main/java/org/autojs/autojs/ui/settings/DocumentationLauncherIconPreference.kt b/app/src/main/java/org/autojs/autojs/ui/settings/DocumentationLauncherIconPreference.kt deleted file mode 100644 index 5d682726..00000000 --- a/app/src/main/java/org/autojs/autojs/ui/settings/DocumentationLauncherIconPreference.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.autojs.autojs.ui.settings - -import android.content.Context -import android.util.AttributeSet -import com.afollestad.materialdialogs.MaterialDialog -import org.autojs.autojs.runtime.api.AppUtils -import org.autojs.autojs.theme.preference.MaterialListPreference -import org.autojs.autojs.ui.doc.DocumentationActivity -import org.autojs.autojs6.R - -class DocumentationLauncherIconPreference : MaterialListPreference { - - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) - - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) - - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) - - constructor(context: Context) : super(context) - - override fun onChangeConfirmed(dialog: MaterialDialog) { - super.onChangeConfirmed(dialog) - - when (dialog.items?.get(dialog.selectedIndex)?.toString()) { - prefContext.getString(R.string.entry_documentation_launcher_icon_show) -> { - AppUtils.showLauncherIcon(prefContext, DocumentationActivity::class.java) - } - prefContext.getString(R.string.entry_documentation_launcher_icon_hide) -> { - AppUtils.hideLauncherIcon(prefContext, DocumentationActivity::class.java) - } - else -> Unit - } - } - - -} \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/ui/settings/LauncherShortcutsPreference.kt b/app/src/main/java/org/autojs/autojs/ui/settings/LauncherShortcutsPreference.kt new file mode 100644 index 00000000..ee74bdf5 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/ui/settings/LauncherShortcutsPreference.kt @@ -0,0 +1,90 @@ +package org.autojs.autojs.ui.settings + +import android.content.Context +import android.util.AttributeSet +import android.widget.LinearLayout +import androidx.core.content.pm.ShortcutManagerCompat +import com.afollestad.materialdialogs.MaterialDialog +import org.autojs.autojs.theme.preference.MaterialPreference +import org.autojs.autojs.util.ShortcutUtils +import org.autojs.autojs6.R + +/** + * Created by SuperMonster003 on Sep 25, 2022. + */ +class LauncherShortcutsPreference : MaterialPreference { + + private val mDialog = MaterialDialog.Builder(prefContext) + .customView(R.layout.select_launcher_shortcut, true) + .build() + .also { dialog -> + val view = dialog.customView as LinearLayout + + view.findViewById(R.id.launcher_shortcut_settings).setOnClickListener { + dialog.dismiss() + ShortcutUtils.requestPinShortcut( + prefContext, + R.string.id_launcher_shortcut_settings, + "org.autojs.autojs.ui.settings.PreferencesActivity", + R.string.text_app_shortcut_settings_long_label, + R.string.text_app_shortcut_settings_short_label, + R.mipmap.ic_app_shortcut_settings_adaptive, + ) + } + + view.findViewById(R.id.launcher_shortcut_docs).setOnClickListener { + dialog.dismiss() + ShortcutUtils.requestPinShortcut( + prefContext, + R.string.id_launcher_shortcut_docs, + "org.autojs.autojs.ui.doc.DocumentationActivity", + R.string.text_app_shortcut_docs_long_label, + R.string.text_app_shortcut_docs_short_label, + R.mipmap.ic_app_shortcut_docs_adaptive, + ) + } + + view.findViewById(R.id.launcher_shortcut_log).setOnClickListener { + dialog.dismiss() + ShortcutUtils.requestPinShortcut( + prefContext, + R.string.id_launcher_shortcut_log, + "org.autojs.autojs.ui.log.LogActivity", + R.string.text_app_shortcut_log_long_label, + R.string.text_app_shortcut_log_short_label, + R.mipmap.ic_app_shortcut_log_adaptive, + ) + } + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + + constructor(context: Context) : super(context) + + override fun onClick() { + if (ShortcutManagerCompat.isRequestPinShortcutSupported(prefContext)) { + showShortcutsSelectionDialog() + } else { + showPinShortcutNotSupportedDialog() + } + super.onClick() + } + + private fun showShortcutsSelectionDialog() { + if (!mDialog.isShowing) mDialog.show() + } + + private fun showPinShortcutNotSupportedDialog() { + MaterialDialog.Builder(prefContext) + .title(R.string.text_prompt) + .content(R.string.text_pin_shortcut_not_unsupported) + .positiveText(R.string.dialog_button_dismiss) + .build() + .show() + } + +} diff --git a/app/src/main/java/org/autojs/autojs/ui/settings/WorkingDirectoryPreference.kt b/app/src/main/java/org/autojs/autojs/ui/settings/WorkingDirectoryPreference.kt index 15b3453c..2ae97086 100644 --- a/app/src/main/java/org/autojs/autojs/ui/settings/WorkingDirectoryPreference.kt +++ b/app/src/main/java/org/autojs/autojs/ui/settings/WorkingDirectoryPreference.kt @@ -141,7 +141,7 @@ class WorkingDirectoryPreference : MaterialPreference { transfer(mPrefFullPath, inputPath) } WorkingDirectoryUtils.path = inputPath - MainActivity.setShouldRecreateMainActivity(true) + MainActivity.shouldRecreateMainActivity = true } dialog.dismiss() onFinish() diff --git a/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutCreateActivity.java b/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutCreateActivity.java index e6ced86e..1f063314 100644 --- a/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutCreateActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutCreateActivity.java @@ -106,7 +106,7 @@ public class ShortcutCreateActivity extends AppCompatActivity { private void createShortcutByShortcutManager() { Icon icon; if (mIsDefaultIcon) { - icon = Icon.createWithResource(this, R.drawable.ic_file_type_js); + icon = Icon.createWithResource(this, R.drawable.ic_file_type_js_dark_green); } else { Bitmap bitmap = BitmapUtils.drawableToBitmap(mIcon.getDrawable()); icon = Icon.createWithBitmap(bitmap); @@ -125,7 +125,6 @@ public class ShortcutCreateActivity extends AppCompatActivity { } - @SuppressWarnings("ResultOfMethodCallIgnored") @SuppressLint({"CheckResult", "MissingSuperCall"}) @Override diff --git a/app/src/main/java/org/autojs/autojs/ui/widget/NestedWebView.java b/app/src/main/java/org/autojs/autojs/ui/widget/NestedWebView.java index 9ec798f1..2823d1e0 100644 --- a/app/src/main/java/org/autojs/autojs/ui/widget/NestedWebView.java +++ b/app/src/main/java/org/autojs/autojs/ui/widget/NestedWebView.java @@ -23,15 +23,16 @@ import android.webkit.WebView; import androidx.core.view.NestedScrollingChild; import androidx.core.view.NestedScrollingChildHelper; -import androidx.core.view.ViewCompat; import org.autojs.autojs.ui.pager.ViewPager; public class NestedWebView extends WebView implements NestedScrollingChild { - private int mLastY; - private final int[] mScrollOffset = new int[2]; - private final int[] mScrollConsumed = new int[2]; - private int mNestedOffsetY; + + // private int mLastY; + // private final int[] mScrollOffset = new int[2]; + // private final int[] mScrollConsumed = new int[2]; + // private int mNestedOffsetY; + private final NestedScrollingChildHelper mChildHelper; public NestedWebView(Context context) { diff --git a/app/src/main/java/org/autojs/autojs/util/App.kt b/app/src/main/java/org/autojs/autojs/util/App.kt index 193fbffc..a2b7ad33 100644 --- a/app/src/main/java/org/autojs/autojs/util/App.kt +++ b/app/src/main/java/org/autojs/autojs/util/App.kt @@ -89,7 +89,7 @@ enum class App(private val appNameResId: Int, val packageName: String, alias: St } @ScriptInterface - fun getAppNameZh() = getAppName(Language.ZH) + fun getAppNameZh() = getAppName(Language.ZH_HANS) @ScriptInterface fun getAppNameEn() = getAppName(Language.EN) diff --git a/app/src/main/java/org/autojs/autojs/util/LocaleUtils.kt b/app/src/main/java/org/autojs/autojs/util/LocaleUtils.kt index 2036f5cc..f7bc6453 100644 --- a/app/src/main/java/org/autojs/autojs/util/LocaleUtils.kt +++ b/app/src/main/java/org/autojs/autojs/util/LocaleUtils.kt @@ -1,51 +1,61 @@ package org.autojs.autojs.util -import android.app.Activity +import android.app.LocaleManager +import android.content.Context import android.content.res.Configuration import android.content.res.Resources -import com.zeugmasolutions.localehelper.LocaleHelper -import com.zeugmasolutions.localehelper.LocaleHelperActivityDelegate -import com.zeugmasolutions.localehelper.LocaleHelperActivityDelegateImpl +import android.os.Build +import android.os.LocaleList +import androidx.appcompat.app.AppCompatDelegate +import androidx.core.os.LocaleListCompat import org.autojs.autojs.app.GlobalAppContext +import org.autojs.autojs.pref.Language import org.autojs.autojs6.R import java.util.Locale object LocaleUtils { - private val localeDelegate: LocaleHelperActivityDelegate = LocaleHelperActivityDelegateImpl() - private val localeHelper = LocaleHelper - - private val globalAppContext = GlobalAppContext.get() - @JvmStatic - fun setLocale(activity: Activity, locale: Locale?) { - locale?.let { localeDelegate.setLocale(activity, it) } - ?: throw IllegalArgumentException(globalAppContext.getString(R.string.error_cannot_be_null, "Locale")) - } - - @JvmStatic - fun setFollowSystem(activity: Activity) { - val systemLocale = localeHelper.systemLocale - val currentLocale = localeHelper.getLocale(activity) - localeDelegate.apply { - if (currentLocale !== systemLocale) { - setLocale(activity, systemLocale) - } - clearLocaleSelection(activity) + fun setLocale(context: Context, locale: Locale?) { + locale ?: throw IllegalArgumentException(context.getString(R.string.error_cannot_be_null, "Locale")) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + context.getSystemService(LocaleManager::class.java).applicationLocales = LocaleList(locale) + } else { + AppCompatDelegate.setApplicationLocales(LocaleListCompat.create(locale)) } } @JvmStatic - fun getSystemLocale() = localeHelper.getLocale(globalAppContext) + fun setFollowSystem(context: Context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + context.getSystemService(LocaleManager::class.java).applicationLocales = LocaleList.getEmptyLocaleList() + } else { + setLocale(context, getSystemLocale()) + } + } + + @JvmStatic + fun getSystemLocale(): Locale = Resources.getSystem().configuration.locales[0] ?: Locale.getDefault() @JvmStatic fun getResources(desiredLocale: Locale?): Resources { - return globalAppContext.let { context -> + return GlobalAppContext.get().let { context -> context.resources.configuration.let { Configuration(it) }.run { - setLocale(desiredLocale ?: localeHelper.systemLocale) + setLocale(desiredLocale ?: getSystemLocale()) context.createConfigurationContext(this).resources } } } + fun syncPrefWithCurrentStateIfNeeded(context: Context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + val appLocales = context.getSystemService(LocaleManager::class.java).applicationLocales + if (appLocales.isEmpty) { + Language.setPrefLanguageAuto() + } else { + Language.setPrefLanguage(appLocales[appLocales.size() - 1]) + } + } + } + } \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/util/SdkVersionUtils.java b/app/src/main/java/org/autojs/autojs/util/SdkVersionUtils.java index 398e971f..648115d9 100644 --- a/app/src/main/java/org/autojs/autojs/util/SdkVersionUtils.java +++ b/app/src/main/java/org/autojs/autojs/util/SdkVersionUtils.java @@ -40,7 +40,8 @@ public class SdkVersionUtils { /* api: 30 */ "11", /* api: 31 */ "12", /* api: 32 */ "12.1", - /* api: 33 */ "13" + /* api: 33 */ "13", + /* api: 34 */ "14" }; public static String sdkIntToString(int i) { diff --git a/app/src/main/java/org/autojs/autojs/util/ShortcutUtils.kt b/app/src/main/java/org/autojs/autojs/util/ShortcutUtils.kt new file mode 100644 index 00000000..0812a1c8 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/util/ShortcutUtils.kt @@ -0,0 +1,52 @@ +package org.autojs.autojs.util + +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.graphics.drawable.Icon +import androidx.core.content.pm.ShortcutInfoCompat +import androidx.core.content.pm.ShortcutManagerCompat +import androidx.core.graphics.drawable.IconCompat + +/** + * Created by SuperMonster003 on Oct 11, 2022. + */ +object ShortcutUtils { + + @JvmStatic + fun requestPinShortcut(context: Context, id: Int, className: String, longLabelResId: Int, shortLabelResId: Int, iconResId: Int) { + requestPinShortcut(context, context.getString(id), className, context.getString(longLabelResId), context.getString(shortLabelResId), Icon.createWithResource(context, iconResId)) + } + + @JvmStatic + fun requestPinShortcut(context: Context, id: String, className: String, longLabel: CharSequence, shortLabel: CharSequence, icon: Icon) { + requestPinShortcut(context, id, Intent("android.intent.action.VIEW").setClassName(context, className), longLabel, shortLabel, icon) + } + + @JvmStatic + fun requestPinShortcut(context: Context, id: String, intent: Intent, longLabel: CharSequence, shortLabel: CharSequence, icon: Icon) { + // The shortcut must be enabled. + // The "id" for ShortcutInfoCompat.Builder must contain stable, constant strings. + val pinShortcutInfo = ShortcutInfoCompat.Builder(context, id) + .setIntent(intent) + .setLongLabel(longLabel) + .setShortLabel(shortLabel) + .setIcon(IconCompat.createFromIcon(context, icon)) + .setAlwaysBadged() + .build() + + // Create the PendingIntent object only if your app needs to be notified + // that the user allowed the shortcut to be pinned. Note that, if the + // pinning operation fails, your app isn't notified. We assume here that the + // app has implemented a method called createShortcutResultIntent() that + // returns a broadcast intent. + val pinnedShortcutCallbackIntent = ShortcutManagerCompat.createShortcutResultIntent(context, pinShortcutInfo) + + // Configure the intent so that your app's broadcast receiver gets + // the callback successfully.For details, see PendingIntent.getBroadcast(). + val successCallback = PendingIntent.getBroadcast(context, 0, pinnedShortcutCallbackIntent, PendingIntent.FLAG_IMMUTABLE) + + ShortcutManagerCompat.requestPinShortcut(context, pinShortcutInfo, successCallback.intentSender) + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/util/UpdateUtils.kt b/app/src/main/java/org/autojs/autojs/util/UpdateUtils.kt index da83bea0..0266ac12 100644 --- a/app/src/main/java/org/autojs/autojs/util/UpdateUtils.kt +++ b/app/src/main/java/org/autojs/autojs/util/UpdateUtils.kt @@ -174,7 +174,8 @@ object UpdateUtils { } @JvmStatic - fun autoCheckForUpdatesIfNeededWithSnackbar(activity: AppCompatActivity, snackbarViewIdRes: Int) { + @JvmOverloads + fun autoCheckForUpdatesIfNeededWithSnackbar(activity: AppCompatActivity, snackbarViewIdRes: Int = android.R.id.content) { if (isAutoCheckForUpdatesEnabled) { val checker = IntervalChecker() if (checker.isBeyondNoNewer && checker.isBeyondPostponed && checker.isBeyondAutoChecked) { diff --git a/app/src/main/java/org/autojs/autojs/util/ViewUtils.kt b/app/src/main/java/org/autojs/autojs/util/ViewUtils.kt index 3312873b..94f6d9b1 100644 --- a/app/src/main/java/org/autojs/autojs/util/ViewUtils.kt +++ b/app/src/main/java/org/autojs/autojs/util/ViewUtils.kt @@ -16,6 +16,7 @@ import android.util.DisplayMetrics import android.util.TypedValue import android.view.View import android.view.Window +import android.view.WindowManager import android.widget.Toast import androidx.annotation.IdRes import androidx.appcompat.app.AppCompatActivity @@ -290,6 +291,24 @@ object ViewUtils { isKeepScreenOnWhenInForegroundEnabled = true } + fun registerOnSharedPreferenceChangeListener(activity: Activity) { + Pref.registerOnSharedPreferenceChangeListener { _, key -> + if (key == key(R.string.key_keep_screen_on_when_in_foreground)) { + configKeepScreenOnWhenInForeground(activity) + } + } + } + + fun configKeepScreenOnWhenInForeground(activity: Activity) { + WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON.let { flags -> + if (isKeepScreenOnWhenInForegroundEnabled) { + activity.window.addFlags(flags) + } else { + activity.window.clearFlags(flags) + } + } + } + class AutoNightMode { companion object { diff --git a/app/src/main/java/pxb/android/axml/AxmlWriter.java b/app/src/main/java/pxb/android/axml/AxmlWriter.java index aa10b4d8..4f85ff03 100644 --- a/app/src/main/java/pxb/android/axml/AxmlWriter.java +++ b/app/src/main/java/pxb/android/axml/AxmlWriter.java @@ -1,12 +1,12 @@ /* * Copyright (c) 2009-2013 Panxiaobo - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -95,20 +95,18 @@ public class AxmlWriter extends AxmlVisitor { for (NodeImpl first : firsts) { size += first.prepare(this); } - { - int a = 0; - for (Map.Entry e : nses.entrySet()) { - Ns ns = e.getValue(); - if (ns == null) { - ns = new Ns(null, new StringItem(e.getKey()), 0); - e.setValue(ns); - } - if (ns.prefix == null) { - ns.prefix = new StringItem(String.format(Language.getPrefLanguage().getLocale(), "axml_auto_%02d", a++)); - } - ns.prefix = update(ns.prefix); - ns.uri = update(ns.uri); + int a = 0; + for (Map.Entry e : nses.entrySet()) { + Ns ns = e.getValue(); + if (ns == null) { + ns = new Ns(null, new StringItem(e.getKey()), 0); + e.setValue(ns); } + if (ns.prefix == null) { + ns.prefix = new StringItem(String.format(Language.getPrefLanguage().getLocale(), "axml_auto_%02d", a++)); + } + ns.prefix = update(ns.prefix); + ns.uri = update(ns.uri); } size += nses.size() * 24 * 2; diff --git a/app/src/main/res/drawable-xhdpi/ic_file_type_js_dark_green.png b/app/src/main/res/drawable-xhdpi/ic_file_type_js_dark_green.png new file mode 100644 index 00000000..5b66f866 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_file_type_js_dark_green.png differ diff --git a/app/src/main/res/drawable/ic_app_shortcut_docs_black.png b/app/src/main/res/drawable/ic_app_shortcut_docs_black.png new file mode 100644 index 00000000..557b3896 Binary files /dev/null and b/app/src/main/res/drawable/ic_app_shortcut_docs_black.png differ diff --git a/app/src/main/res/drawable/ic_app_shortcut_docs_green.png b/app/src/main/res/drawable/ic_app_shortcut_docs_green.png new file mode 100644 index 00000000..6f4fefc4 Binary files /dev/null and b/app/src/main/res/drawable/ic_app_shortcut_docs_green.png differ diff --git a/app/src/main/res/drawable/ic_app_shortcut_docs_white.png b/app/src/main/res/drawable/ic_app_shortcut_docs_white.png new file mode 100644 index 00000000..d8882af6 Binary files /dev/null and b/app/src/main/res/drawable/ic_app_shortcut_docs_white.png differ diff --git a/app/src/main/res/drawable/ic_app_shortcut_log_black.png b/app/src/main/res/drawable/ic_app_shortcut_log_black.png new file mode 100644 index 00000000..ac928bf7 Binary files /dev/null and b/app/src/main/res/drawable/ic_app_shortcut_log_black.png differ diff --git a/app/src/main/res/drawable/ic_app_shortcut_log_green.png b/app/src/main/res/drawable/ic_app_shortcut_log_green.png new file mode 100644 index 00000000..4cbbdea0 Binary files /dev/null and b/app/src/main/res/drawable/ic_app_shortcut_log_green.png differ diff --git a/app/src/main/res/drawable/ic_app_shortcut_log_white.png b/app/src/main/res/drawable/ic_app_shortcut_log_white.png new file mode 100644 index 00000000..9138ed22 Binary files /dev/null and b/app/src/main/res/drawable/ic_app_shortcut_log_white.png differ diff --git a/app/src/main/res/drawable/ic_app_shortcut_settings_black.png b/app/src/main/res/drawable/ic_app_shortcut_settings_black.png new file mode 100644 index 00000000..a98ecaa5 Binary files /dev/null and b/app/src/main/res/drawable/ic_app_shortcut_settings_black.png differ diff --git a/app/src/main/res/drawable/ic_app_shortcut_settings_green.png b/app/src/main/res/drawable/ic_app_shortcut_settings_green.png new file mode 100644 index 00000000..67fc7127 Binary files /dev/null and b/app/src/main/res/drawable/ic_app_shortcut_settings_green.png differ diff --git a/app/src/main/res/drawable/ic_app_shortcut_settings_white.png b/app/src/main/res/drawable/ic_app_shortcut_settings_white.png new file mode 100644 index 00000000..e09fe5e8 Binary files /dev/null and b/app/src/main/res/drawable/ic_app_shortcut_settings_white.png differ diff --git a/app/src/main/res/drawable/ic_node_js_black.xml b/app/src/main/res/drawable/ic_node_js_black.xml index 1b68b433..5891639d 100644 --- a/app/src/main/res/drawable/ic_node_js_black.xml +++ b/app/src/main/res/drawable/ic_node_js_black.xml @@ -6,7 +6,7 @@ android:viewportWidth="128"> + android:layout_height="match_parent" /> \ No newline at end of file diff --git a/app/src/main/res/layout/select_launcher_shortcut.xml b/app/src/main/res/layout/select_launcher_shortcut.xml new file mode 100644 index 00000000..dfb01d2e --- /dev/null +++ b/app/src/main/res/layout/select_launcher_shortcut.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/widget_script_shortcut.xml b/app/src/main/res/layout/widget_script_shortcut.xml index 4edf106e..c68e102c 100644 --- a/app/src/main/res/layout/widget_script_shortcut.xml +++ b/app/src/main/res/layout/widget_script_shortcut.xml @@ -1,25 +1,27 @@ + android:id="@+id/widget" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + android:id="@+id/icon" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:src="@drawable/ic_node_js_black" /> + android:id="@+id/name" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="3dp" + android:gravity="center" + android:layout_gravity="top" + android:maxLines="2" + android:ellipsize="middle" + android:textColor="@android:color/white" + android:textSize="12sp" /> \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_docs_adaptive.xml b/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_docs_adaptive.xml new file mode 100644 index 00000000..e117395b --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_docs_adaptive.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_docs_adaptive_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_docs_adaptive_round.xml new file mode 100644 index 00000000..e117395b --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_docs_adaptive_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_log_adaptive.xml b/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_log_adaptive.xml new file mode 100644 index 00000000..b8fc04b0 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_log_adaptive.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_log_adaptive_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_log_adaptive_round.xml new file mode 100644 index 00000000..b8fc04b0 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_log_adaptive_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_settings_adaptive.xml b/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_settings_adaptive.xml new file mode 100644 index 00000000..c73710c3 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_settings_adaptive.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_settings_adaptive_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_settings_adaptive_round.xml new file mode 100644 index 00000000..c73710c3 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_app_shortcut_settings_adaptive_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_app_shortcut_docs_adaptive.png b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_docs_adaptive.png new file mode 100644 index 00000000..aa8f9daa Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_docs_adaptive.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_app_shortcut_docs_adaptive_foreground.png b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_docs_adaptive_foreground.png new file mode 100644 index 00000000..d53fb977 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_docs_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_app_shortcut_docs_adaptive_round.png b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_docs_adaptive_round.png new file mode 100644 index 00000000..4e753a22 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_docs_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_app_shortcut_log_adaptive.png b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_log_adaptive.png new file mode 100644 index 00000000..c575b701 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_log_adaptive.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_app_shortcut_log_adaptive_foreground.png b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_log_adaptive_foreground.png new file mode 100644 index 00000000..391656ea Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_log_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_app_shortcut_log_adaptive_round.png b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_log_adaptive_round.png new file mode 100644 index 00000000..1b843dca Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_log_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_app_shortcut_settings_adaptive.png b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_settings_adaptive.png new file mode 100644 index 00000000..badb1f32 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_settings_adaptive.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_app_shortcut_settings_adaptive_foreground.png b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_settings_adaptive_foreground.png new file mode 100644 index 00000000..50b0543e Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_settings_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_app_shortcut_settings_adaptive_round.png b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_settings_adaptive_round.png new file mode 100644 index 00000000..f4d8047d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_app_shortcut_settings_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_app_shortcut_docs_adaptive.png b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_docs_adaptive.png new file mode 100644 index 00000000..8298815c Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_docs_adaptive.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_app_shortcut_docs_adaptive_foreground.png b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_docs_adaptive_foreground.png new file mode 100644 index 00000000..03b01ab8 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_docs_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_app_shortcut_docs_adaptive_round.png b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_docs_adaptive_round.png new file mode 100644 index 00000000..1175f872 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_docs_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_app_shortcut_log_adaptive.png b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_log_adaptive.png new file mode 100644 index 00000000..f61962aa Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_log_adaptive.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_app_shortcut_log_adaptive_foreground.png b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_log_adaptive_foreground.png new file mode 100644 index 00000000..d9d78f4a Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_log_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_app_shortcut_log_adaptive_round.png b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_log_adaptive_round.png new file mode 100644 index 00000000..8fc8b7e4 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_log_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_app_shortcut_settings_adaptive.png b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_settings_adaptive.png new file mode 100644 index 00000000..0d090fbf Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_settings_adaptive.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_app_shortcut_settings_adaptive_foreground.png b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_settings_adaptive_foreground.png new file mode 100644 index 00000000..f9759739 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_settings_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_app_shortcut_settings_adaptive_round.png b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_settings_adaptive_round.png new file mode 100644 index 00000000..2b0a1ac8 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_app_shortcut_settings_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_docs_adaptive.png b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_docs_adaptive.png new file mode 100644 index 00000000..5a9ac74d Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_docs_adaptive.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_docs_adaptive_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_docs_adaptive_foreground.png new file mode 100644 index 00000000..801a204c Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_docs_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_docs_adaptive_round.png b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_docs_adaptive_round.png new file mode 100644 index 00000000..3a2815af Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_docs_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_log_adaptive.png b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_log_adaptive.png new file mode 100644 index 00000000..0a223840 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_log_adaptive.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_log_adaptive_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_log_adaptive_foreground.png new file mode 100644 index 00000000..ae4b283e Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_log_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_log_adaptive_round.png b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_log_adaptive_round.png new file mode 100644 index 00000000..13a1a6a5 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_log_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_settings_adaptive.png b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_settings_adaptive.png new file mode 100644 index 00000000..aeb6ee95 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_settings_adaptive.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_settings_adaptive_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_settings_adaptive_foreground.png new file mode 100644 index 00000000..ac7ee8cb Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_settings_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_settings_adaptive_round.png b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_settings_adaptive_round.png new file mode 100644 index 00000000..9297b5c9 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_app_shortcut_settings_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_docs_adaptive.png b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_docs_adaptive.png new file mode 100644 index 00000000..498ec312 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_docs_adaptive.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_docs_adaptive_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_docs_adaptive_foreground.png new file mode 100644 index 00000000..12772fcb Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_docs_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_docs_adaptive_round.png b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_docs_adaptive_round.png new file mode 100644 index 00000000..701b4a50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_docs_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_log_adaptive.png b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_log_adaptive.png new file mode 100644 index 00000000..1965312b Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_log_adaptive.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_log_adaptive_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_log_adaptive_foreground.png new file mode 100644 index 00000000..5f789ed7 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_log_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_log_adaptive_round.png b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_log_adaptive_round.png new file mode 100644 index 00000000..7a7bffdb Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_log_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_settings_adaptive.png b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_settings_adaptive.png new file mode 100644 index 00000000..682ef97e Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_settings_adaptive.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_settings_adaptive_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_settings_adaptive_foreground.png new file mode 100644 index 00000000..e1cd5392 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_settings_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_settings_adaptive_round.png b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_settings_adaptive_round.png new file mode 100644 index 00000000..ea9cdcb9 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_app_shortcut_settings_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_docs_adaptive.png b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_docs_adaptive.png new file mode 100644 index 00000000..a900aa13 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_docs_adaptive.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_docs_adaptive_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_docs_adaptive_foreground.png new file mode 100644 index 00000000..42036d94 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_docs_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_docs_adaptive_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_docs_adaptive_round.png new file mode 100644 index 00000000..c0c12ee8 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_docs_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_log_adaptive.png b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_log_adaptive.png new file mode 100644 index 00000000..911b0525 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_log_adaptive.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_log_adaptive_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_log_adaptive_foreground.png new file mode 100644 index 00000000..1ab27704 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_log_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_log_adaptive_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_log_adaptive_round.png new file mode 100644 index 00000000..6c494303 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_log_adaptive_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_settings_adaptive.png b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_settings_adaptive.png new file mode 100644 index 00000000..dbd910a4 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_settings_adaptive.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_settings_adaptive_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_settings_adaptive_foreground.png new file mode 100644 index 00000000..69f28885 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_settings_adaptive_foreground.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_settings_adaptive_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_settings_adaptive_round.png new file mode 100644 index 00000000..68abfe37 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_app_shortcut_settings_adaptive_round.png differ diff --git a/app/src/main/res/resources.properties b/app/src/main/res/resources.properties new file mode 100644 index 00000000..d5a3ddc9 --- /dev/null +++ b/app/src/main/res/resources.properties @@ -0,0 +1 @@ +unqualifiedResLocale=en-US \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 2d53f707..97cf370c 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -26,7 +26,6 @@ قم بتغيير مسار الدليل الذي يحتوي على البرامج النصية يحصل AutoJs6 على التحديثات وتنزيلها من GitHub.\n\nملاحظة: لا يوفر التحديث دعمًا متعدد اللغات حتى الآن. يوفر درجة توافق اسم فئة Java لإصدارات 4.x من خلال إعادة تعيين اسم الفئة.\nعند تشغيل هذا الخيار ، سيكون هناك درجة متفاوتة من تأخير بدء التشغيل (عشرات إلى مئات المللي ثانية) في كل مرة يبدأ فيها البرنامج النصي.\nيوصى بإيقاف تشغيل الخيار في جميع الأوقات إذا لم يكن مطلوبًا على وجه التحديد. - تسهل أيقونة مشغل الوثائق الوصول إلى المستندات ويمكن تبديلها مثل تطبيق مستقل. المستندات المحلية: باستخدام ملفات AutoJs6 المضمنة كمصادر توثيق ، لا يلزم الاتصال بالشبكة. يتغير المحتوى مع تحديث AutoJs6.\nالمستندات عبر الإنترنت: استخدام صفحات GitHub كمصادر توثيق تتطلب اتصالاً بالشبكة. المحتوى دائما محدث.\n\nملاحظة: لزيادة تجربة قراءة المستندات عبر الإنترنت إلى الحد الأقصى ، يوصى باستخدام جهاز عرض بشاشة عريضة مثل شاشة سطح المكتب.\nملاحظة: اعتبارًا من الإصدار 6.2.0 ، لا تزال الوثائق في المراحل الأولية من التطوير ، ومعظم المحتوى لم تتم كتابته أو تحديثه بعد. يجب استيفاء الشروط التالية لدعم النسق الداكن على صفحات المستند:\n1. تم تمكين الوضع الليلي AutoJs6\n2.عرض ويب نظام Android (أو متصفحات مثل Google Chrome):\n- Android API المستوى 29 (Android 10) [Q] وما فوق: الإصدار> = 76\n- مستوى واجهة برمجة تطبيقات Android 28 (Android 9) [P] وما دون: الإصدار> = 105 يمكن أن يؤدي توسيع كائنات JavaScript المضمنة إلى زيادة مرونة التعليمات البرمجية وتمكين وظائف أكثر ثراءً ، ولكن يمكن أن يتسبب في حدوث تعارضات وحتى حدوث تعطل.\nتحتوي جميع البرامج النصية على امتدادات مضمنة يتم تمكينها افتراضيًا عند تشغيل الخيار.\nغالبًا ما تكون الامتدادات المضمنة غير آمنة ، ولا يوصى بها ما لم يتم فهم مبادئ ومخاطر الإضافات المضمنة بوضوح.\nعند إيقاف تشغيل الخيار ، لا يزال من الممكن تمكين الامتدادات المضمنة من خلال الكائن العام للمكونات الإضافية ، كما هو موضح في وثائق المشروع. @@ -59,12 +58,11 @@ النظام تحديث استخدم الافتراضي - AutoJs6 توثيق + AutoJs6 توثيق + توثيق لا يمكن معالجة الملف لم يتم حفظ المحتوى ، هل أنت متأكد من الخروج؟ اتبع النظام - إخفاء الرمز من المشغل - إظهار الرمز في المشغل مستندات محلية مستندات عبر الإنترنت تغيير حجم النص @@ -345,7 +343,6 @@ لا تسأل مرة أخرى عن هذا الإصدار لا تظهر مرة أخرى وثائق - رمز مشغل الوثائق مصدر الوثائق فعله تحميل @@ -460,6 +457,8 @@ فحص التصميم ... تراخيص المصادر المفتوحة سجل + AutoJs6 سجل + سجل تسجيل الدخول تسجيل الدخول نجح تسجيل الدخول @@ -623,6 +622,8 @@ تعيين كدليل العمل ضبط نقطة توقف إعدادات + AutoJs6 إعدادات + إعدادات النص لا يمكن أن يكون فارغًا عرض في حدود التصميم عرض في التسلسل الهرمي للتخطيط @@ -679,19 +680,24 @@ إعدادات النظام الآمنة ، التي تحتوي على تفضيلات النظام التي يمكن أن تقرأها التطبيقات ولكن لا يُسمح لها بالكتابة.\nهذه هي لتفضيلات يجب على المستخدم تعديلها بشكل صريح من خلال واجهة المستخدم لتطبيق النظام.\nمع إذن إعدادات النظام الآمن ، يمكن للتطبيقات العادية تعديل الإعدادات الآمنة مباشرة (مثل خدمة إمكانية الوصول). كتابة إعدادات النظام تقصير - 仅最新的 %d 个条目将被发送 - 当前日志总条目数 %d 超出可发送限制 - 日志条目发送失败 - 无可发送的日志条目 - 无可导出的日志条目 - 无可复制的日志条目 - 复制失败 - 已复制到剪贴板 (仅最新的 %d 个条目) - 日志条目导出失败 - 关闭 - 查看文件 - 已导出 - 已导出 %d 个条目 + سيتم إرسال أحدث %d من العناصر فقط + عدد إدخالات السجل %d يتجاوز حد الإرسال + فشل في إرسال إدخالات السجل + لا توجد إدخالات سجل لإرسالها + لا توجد إدخالات سجل للتصدير + لا توجد إدخالات سجل لنسخها + فشل النسخ + تم النسخ بالفعل إلى الحافظة (فقط أحدث %d عنصر) + فشل تصدير إدخالات السجل + رفض + استعراض الملف + تصدير + تم تصدير %d من العناصر + تم تعطيل هذا الاختصار + اختصارات المشغل + يمكن للاختصارات تنفيذ إجراءات محددة في AutoJs6. يمكن للمستخدمين عرض هذه الاختصارات في مشغل مدعوم وبدء بعض المهام أو تشغيل نشاط بسرعة، مثل قراءة وثائق تطبيق AutoJs6، وتشغيل صفحة إعدادات AutoJs6، وما إلى ذلك. + أضف اختصارات إلى المشغل + تثبيت الاختصارات على المشغل غير مدعوم المجموع: عنصر واحد diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 10cd67c6..6edc608d 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -24,7 +24,6 @@ Change the path of the directory containing scripts AutoJs6 gets and downloads updates from GitHub.\n\nNote: The update does not provide multilingual support yet. Provides a degree of Java class name compatibility for 4.x versions through class name remapping.\nWith this option turned on, there will be a varying degree of startup delay (tens to hundreds of milliseconds) each time the script is started.\nIt is recommended to keep the option off at all times if not specifically required. - A documentation launcher icon makes it easier to access the docs and can be switched like a stand-alone application. Local docs: Using AutoJs6 build-in files as documentation sources, no network connection required. The content changes as AutoJs6 is updated.\nOnline docs: Using GitHub pages as documentation sources, requiring network connection. The content is always up to date.\n\nNote: To maximize the reading experience of online documents, it is recommended to use a widescreen display device such as a desktop monitor.\nNote: As of version 6.2.0, the documentation is still in the preliminary stages of development, and most of the content has not yet been written or updated. The following conditions must be met for dark theme support on document pages:\n1. AutoJs6 has night mode enabled\n2. Android System WebView (or browsers like Google Chrome):\n- Android API Level 29 (Android 10) [Q] and above: version >= 76\n- Android API Level 28 (Android 9) [P] and below: version >= 105 Extending JavaScript built-in objects can increase code flexibility and enable richer functionality, but can cause conflicts and even breakage.\nAll scripts have built-in extensions enabled by default when the option is turned on.\nBuilt-in extensions are often insecure, and are not recommended unless the principles and risks of built-in extensions are clearly understood.\nWhen the option is turned off, built-in extensions can still be enabled through the plugins global object, as described in the project documentation. @@ -57,12 +56,11 @@ System Update Use default - AutoJs6 Docs + AutoJs6 Docs + Docs Can\'t process file The content has not been saved, are you sure to exit? Follow system - Hide icon from launcher - Show icon in launcher Local docs Online docs Change text size @@ -343,7 +341,6 @@ Don’t ask again for this version Don\'t show again Documents - Documentation launcher icon Documentation source Done Download @@ -458,6 +455,8 @@ Inspecting layout... Open Sources Licenses Log + AutoJs6 Log + Log Logging in Login Login succeeded @@ -621,6 +620,8 @@ Set as working dir Set a breakpoint Settings + AutoJs6 Settings + Settings Text can\'t be empty View in layout bounds View in layout hierarchy @@ -677,19 +678,24 @@ Secure system settings, containing system preferences that applications can read but are not allowed to write.\nThese are for preferences that the user must explicitly modify through the UI of a system app.\nWith secure system settings permission, normal applications can directly modify the secure settings (such as accessibility service). Write system settings Default - 仅最新的 %d 个条目将被发送 - 当前日志总条目数 %d 超出可发送限制 - 日志条目发送失败 - 无可发送的日志条目 - 无可导出的日志条目 - 无可复制的日志条目 - 复制失败 - 已复制到剪贴板 (仅最新的 %d 个条目) - 日志条目导出失败 - 关闭 - 查看文件 - 已导出 - 已导出 %d 个条目 + Only latest %d items will be sent + Number of log entries %d exceeds the limit for sending + Failed to send log entries + No log entries to send + No log entries to export + No log entries to copy + Failed to copy + Already copied to clipboard (only latest %d items) + Failed to export log entries + Dismiss + View File + Exported + %d items exported + This shortcut is disabled + Launcher shortcuts + Shortcuts can perform specific actions in AutoJs6. Users can display these shortcuts in a supported launcher and quickly start some tasks or launch an activity, such as reading AutoJs6 application documentation, launching AutoJs6 settings page, and so on. + Add shortcuts to launcher + Pinning shortcuts to launcher is not supported Total: %d item diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 9ec5b935..82d67e2c 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -26,7 +26,6 @@ Cambiar la ruta del directorio que contiene los scripts AutoJs6 obtiene y descarga las actualizaciones de GitHub.\n\nNota: La actualización aún no ofrece soporte multilingüe. Proporciona un grado de compatibilidad de nombres de clase Java para las versiones 4.x a través de la reasignación de nombres de clase.\nCon esta opción activada, habrá un grado variable de retraso en el inicio (de decenas a cientos de milisegundos) cada vez que se inicie el script.\nSe recomienda mantener la opción desactivada en todo momento si no se requiere específicamente. - Un icono lanzador de documentación facilita el acceso a los documentos y puede conmutarse como una aplicación independiente. Documentos locales: Utiliza los archivos incorporados de AutoJs6 como fuentes de documentación, sin necesidad de conexión a la red. El contenido cambia a medida que se actualiza AutoJs6.\nDocumentación en línea: Utilizando las páginas de GitHub como fuentes de documentación, se requiere conexión a la red. El contenido está siempre actualizado.\n\nNota: Para maximizar la experiencia de lectura de los documentos en línea, se recomienda utilizar un dispositivo de pantalla ancha, como un monitor de escritorio.\nNota: A partir de la versión 6.2.0, la documentación se encuentra todavía en las fases preliminares de desarrollo, y la mayor parte del contenido aún no ha sido escrito o actualizado. Para que el tema oscuro sea compatible con las páginas de los documentos, deben cumplirse las siguientes condiciones\n1. AutoJs6 tiene activado el modo nocturno\n2. Sistema Android WebView (o navegadores como Google Chrome):\n- Android API Level 29 (Android 10) [Q] y superior: versión >= 76\n- Android API Level 28 (Android 9) [P] e inferiores: versión >= 105 La ampliación de los objetos incorporados de JavaScript puede aumentar la flexibilidad del código y permitir una funcionalidad más rica, pero puede causar conflictos e incluso roturas.\nTodos los scripts tienen las extensiones incorporadas habilitadas por defecto cuando la opción está activada.\nLas extensiones incorporadas suelen ser inseguras y no se recomiendan a menos que se comprendan claramente los principios y riesgos de las extensiones incorporadas.\nCuando la opción está desactivada, las extensiones incorporadas aún pueden ser habilitadas a través del objeto global plugins, como se describe en la documentación del proyecto. @@ -59,12 +58,11 @@ Sistema Actualizar Usar por defecto - AutoJs6 Docs + AutoJs6 Docs + Docs No se puede procesar el archivo El contenido no se ha guardado, ¿está seguro de salir? Siga el sistema - Ocultar icono del lanzador - Mostrar icono en el lanzador Documentos locales Documentos en línea Tamaño del texto @@ -345,7 +343,6 @@ No volver a pedir esta versión No volver a mostrar Documentos - Icono del lanzador de documentación Fuente de la documentación Hecho Descargar @@ -460,6 +457,8 @@ Inspeccionando el diseño... Licencias de fuentes abiertas Registrar + AutoJs6 Registrar + Registrar Iniciar sesión Inicio de sesión Inicio de sesión exitoso @@ -623,6 +622,8 @@ Como directorio de trabajo Establecer un punto de interrupción Configuración + AutoJs6 Configuración + Configuración El texto no puede estar vacío Vista en los límites del diseño Vista en la jerarquía del diseño @@ -679,27 +680,34 @@ Ajustes de seguridad del sistema, que contienen preferencias del sistema que las aplicaciones pueden leer pero no pueden escribir.\nSe trata de preferencias que el usuario debe modificar explícitamente a través de la interfaz de usuario de una aplicación del sistema.\nCon el permiso de configuración segura del sistema, las aplicaciones normales pueden modificar directamente la configuración segura (como el servicio de accesibilidad). Escribir la configuración del sistema Por defecto - 仅最新的 %d 个条目将被发送 - 当前日志总条目数 %d 超出可发送限制 - 日志条目发送失败 - 无可发送的日志条目 - 无可导出的日志条目 - 无可复制的日志条目 - 复制失败 - 已复制到剪贴板 (仅最新的 %d 个条目) - 日志条目导出失败 - 关闭 - 查看文件 - 已导出 - 已导出 %d 个条目 + Sólo se enviarán los últimos %d elementos + El número de entradas de registro %d supera el límite de envío + Error al enviar entradas de registro + No hay entradas de registro para enviar + No hay entradas de registro para exportar + No hay entradas de registro para copiar + Error al copiar + Ya se ha copiado en el portapapeles (sólo los últimos %d elementos) + Error al exportar entradas de registro + Descartar + Ver archivo + Exportado + %d elementos exportados + Este acceso directo está desactivado + Atajos del lanzador + Los accesos directos pueden realizar acciones específicas en AutoJs6. Los usuarios pueden mostrar estos accesos directos en un lanzador compatible e iniciar rápidamente algunas tareas o iniciar una actividad, como leer la documentación de la aplicación AutoJs6, iniciar la página de configuración de AutoJs6, etc. + Añadir accesos directos al lanzador + No es posible anclar accesos directos al lanzador. Total: %d artículo + Total: %d artículos Total: %d artículos %d script detenido + %d scripts detenidos %d scripts detenidos diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 7c58c816..da725652 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -26,7 +26,6 @@ Changer le chemin du répertoire contenant les scripts. AutoJs6 obtient et télécharge les mises à jour depuis GitHub.\n\nNote: La mise à jour ne fournit pas encore de support multilingue. Assure un certain degré de compatibilité des noms de classe Java pour les versions 4.x grâce au remappage des noms de classe.\nSi cette option est activée, il y aura un délai de démarrage plus ou moins long (de quelques dizaines à quelques centaines de millisecondes) à chaque fois que le script sera lancé.\nIl est recommandé de laisser l\'option désactivée à tout moment si elle n\'est pas spécifiquement requise. - Une icône de lancement de la documentation facilite l\'accès aux documents et peut être commutée comme une application autonome. Documentation locale: Utilisation des fichiers intégrés d\'AutoJs6 comme sources de documentation, aucune connexion réseau n\'est nécessaire. Le contenu change au fur et à mesure que AutoJs6 est mis à jour.\nDocumentation en ligne: Utilisation des pages GitHub comme sources de documentation, nécessitant une connexion réseau. Le contenu est toujours à jour.\n\nRemarque: pour optimiser l\'expérience de lecture des documents en ligne, il est recommandé d\'utiliser un dispositif d\'affichage grand écran tel qu\'un moniteur de bureau.\nRemarque: à partir de la version 6.2.0, la documentation est encore dans les phases préliminaires de développement, et la plupart du contenu n\'a pas encore été écrit ou mis à jour. Les conditions suivantes doivent être remplies pour la prise en charge du thème sombre sur les pages de la documentation :\n1. Le mode nuit d\'AutoJs6 est activé\n2. WebView du système Android (ou des navigateurs comme Google Chrome) :\n- Android API Level 29 (Android 10) [Q] et supérieur: version >= 76\n- Android API Niveau 28 (Android 9) [P] et inférieur: version >= 105 L\'extension des objets JavaScript intégrés peut augmenter la flexibilité du code et permettre des fonctionnalités plus riches, mais elle peut provoquer des conflits et même des pannes.\nTous les scripts ont des extensions intégrées activées par défaut lorsque l\'option est activée.\nLes extensions intégrées sont souvent peu sûres et ne sont pas recommandées, sauf si les principes et les risques des extensions intégrées sont clairement compris.\nLorsque l\'option est désactivée, les extensions intégrées peuvent toujours être activées via l\'objet global plugins, comme décrit dans la documentation du projet. @@ -59,12 +58,11 @@ Système Mise à jour Par défaut - AutoJs6 Docs + AutoJs6 Docs + Docs Can\'t process file Le contenu n\'a pas été enregistré, êtes-vous sûr de vouloir quitter? Suivre le système - Masquer l\'icône du lanceur - Afficher l\'icône dans le lanceur Documents locaux Documents en ligne Taille du texte @@ -345,7 +343,6 @@ Ne pas redemander cette version Ne pas montrer à nouveau Documents - Icône du lanceur de documentation Source de la documentation Done Téléchargement @@ -460,6 +457,8 @@ Inspecter la mise en page... Licences Open Sources Journal + AutoJs6 Journal + Journal Logging in Login Login réussi @@ -623,6 +622,8 @@ Comme répertoire de travail Définir un point d\'arrêt Réglages + AutoJs6 Réglages + Réglages Le texte ne peut pas être vide Afficher les bords de la disposition Afficher la hiérarchie de la disposition @@ -679,27 +680,34 @@ Paramètres de sécurité du système, contenant les préférences du système que les applications peuvent lire mais ne sont pas autorisées à écrire.\nIl s\'agit des préférences que l\'utilisateur doit explicitement modifier par le biais de l\'interface utilisateur d\'une application système.\nAvec l\'autorisation de paramètres de sécurité du système, les applications normales peuvent directement modifier les paramètres de sécurité (comme le service d\'accessibilité). Écrire les paramètres système Default - 仅最新的 %d 个条目将被发送 - 当前日志总条目数 %d 超出可发送限制 - 日志条目发送失败 - 无可发送的日志条目 - 无可导出的日志条目 - 无可复制的日志条目 - 复制失败 - 已复制到剪贴板 (仅最新的 %d 个条目) - 日志条目导出失败 - 关闭 - 查看文件 - 已导出 - 已导出 %d 个条目 + Seuls les derniers %d éléments seront envoyés + Le nombre d\'entrées de journal %d dépasse la limite d\'envoi + Échec de l\'envoi des entrées de journal + Aucune entrée de journal à envoyer + Aucune entrée de journal à exporter + Aucune entrée de journal à copier + Échec de la copie + Déjà copié dans le presse-papiers (seulement les derniers %d éléments) + Échec de l\'exportation des entrées de journal + Quitter + Voir le fichier + Exporté + %d items exported + Ce raccourci est désactivé + Raccourcis du lanceur + Les raccourcis permettent d\'effectuer des actions spécifiques dans AutoJs6. Les utilisateurs peuvent afficher ces raccourcis dans un lanceur pris en charge et démarrer rapidement certaines tâches ou lancer une activité, comme la lecture de la documentation de l\'application AutoJs6, le lancement de la page de configuration d\'AutoJs6, etc. + Ajouter des raccourcis au lanceur + L\'épinglage de raccourcis dans le lanceur n\'est pas pris en charge Total: %d article + Total: %d articles Total: %d articles %d script arrêté + %d scripts arrêtés %d scripts arrêtés diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index f6eddcb6..1f50d676 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -26,7 +26,6 @@ スクリプトを含むディレクトリのパスを変更する AutoJs6 は、GitHub からアップデートを取得し、ダウンロードします.\n\n注: このアップデートでは、まだ多言語サポートは提供されていません クラス名のリマッピングにより、4.x バージョンの Java クラス名の互換性をある程度確保します.\nこのオプションをオンにすると、スクリプトを起動するたびにさまざまな程度 (数十から数百ミリ秒) の起動遅延が発生するようになる.\n特に必要でない場合は、このオプションを常にオフにしておくことをお勧めします - ドキュメントランチャーアイコンは、ドキュメントへのアクセスを容易にし、スタンドアロンアプリケーションのように切り替えることができます ローカルドキュメント AutoJs6 に組み込まれたファイルをドキュメントソースとして使用するため、ネットワーク接続は必要ありません. AutoJs6 が更新されると内容も変わります.\nオンライン・ドキュメント. GitHub のページをドキュメントソースとして使用し、ネットワーク接続が必要です. コンテンツは常に最新の状態に保たれます.\n\n注: オンラインドキュメントを最大限に活用するために、デスクトップモニターなどのワイドスクリーンディスプレイを使用することをお勧めします.\n注意: バージョン 6.2.0 時点では、ドキュメントはまだ開発の初期段階にあり、ほとんどのコンテンツはまだ執筆・更新されていません ドキュメントページでダークテーマをサポートするには、以下の条件を満たす必要があります.\n1. AutoJs6 でナイトモードが有効になっている\n2. Android System WebView (または Google Chrome などのブラウザ) .\n- Android API Level 29 (Android 10) [Q] 以上: バージョン >= 76\n- Android API Level 28 (Android 9) [P] 以下: バージョン >= 105 JavaScript の組み込みオブジェクトを拡張すると、コードの柔軟性が増し、より豊かな機能を実現できますが、衝突や破損を引き起こす可能性もあります.\nこのオプションをオンにすると、すべてのスクリプトはデフォルトで組み込みの拡張機能を有効にします.\n組み込みの拡張機能は安全でないことが多いので、組み込みの拡張機能の原理とリスクが明確に理解されていない限り、推奨されません.\nこのオプションをオフにした場合でも、プロジェクトのドキュメントで説明されているように、plugins グローバルオブジェクトを使用して組み込み拡張機能を有効にすることができます @@ -59,12 +58,11 @@ システム 更新 デフォルトを使用 - AutoJs6 文書 + AutoJs6 文書 + 文書 ファイルを処理できません 内容が保存されていませんので、本当に終了しますか? システムに従ってください - ランチャーからアイコンを隠す - ランチャーにアイコンを表示する ローカルドキュメント オンラインドキュメント 文字サイズ @@ -345,7 +343,6 @@ このバージョンでは再表示を要求しない 再表示禁止 ドキュメント - ドキュメントのランチャーアイコン ドキュメントのソース 完了 ダウンロード @@ -460,6 +457,8 @@ レイアウトの検査中... オープンソースライセンス ログ + AutoJs6 ログ + ログ ログイン ログイン ログインに成功しました @@ -623,6 +622,8 @@ 作業ディレクトリに設定する ブレークポイントの設定 設定 + AutoJs6 設定 + 設定 「テキストを空にすることはできません レイアウト境界内のビュー レイアウト階層内の表示 @@ -679,19 +680,24 @@ アプリケーションが読み取ることはできるが、書き込むことはできないシステム環境設定を含む、安全なシステム設定です.\nこれは、ユーザーがシステムアプリのUIを通じて明示的に変更する必要がある環境設定のためのものです.\nセキュアなシステム設定を許可すると、通常のアプリケーションはセキュアな設定 (アクセシビリティサービスなど) を直接変更できるようになります システム設定の書き込み デフォルト - 仅最新的 %d 个条目将被发送 - 当前日志总条目数 %d 超出可发送限制 - 日志条目发送失败 - 无可发送的日志条目 - 无可导出的日志条目 - 无可复制的日志条目 - 复制失败 - 已复制到剪贴板 (仅最新的 %d 个条目) - 日志条目导出失败 - 关闭 - 查看文件 - 已导出 - 已导出 %d 个条目 + 最新の %d 個の項目のみが送信されます + ログ・エントリ数 %d が送信制限を超えました + ログ・エントリの送信に失敗しました + 送信するログ・エントリがありません + エクスポートするログ・エントリがありません + コピーするログ・エントリがありません + コピーに失敗しました + 既にクリップボードにコピーされました (最新の %d アイテムのみ) + ログ・エントリのエクスポートに失敗しました + 削除 + ファイルの表示 + エクスポートされました + エクスポートされた項目 %d + このショートカットは無効です + ランチャーショートカット + ショートカットは、AutoJs6 で特定のアクションを実行することができます。ユーザーは、サポートされているランチャーにこれらのショートカットを表示し、AutoJs6アプリケーションのドキュメントを読んだり、AutoJs6の設定ページを起動したりするなど、いくつかのタスクを素早く開始したり、アクティビティを起動したりすることができます + ランチャーへのショートカットの追加 + ショートカットをランチャーにピン留めすることはサポートされていません 合計: %d 件 diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index cf5383f3..767d2b75 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1,6 +1,7 @@ + @@ -26,7 +27,6 @@ 스크립트가 포함 된 디렉토리의 경로를 변경하십시오 AutoJs6 은 GitHub 에서 업데이트를 가져오고 다운로드합니다.\n\n참고: 업데이트는 아직 다국어 지원을 제공하지 않습니다. 클래스 이름 재매핑을 통해 4.x 버전에 대해 어느 정도의 Java 클래스 이름 호환성을 제공합니다.\n이 옵션을 켜면 스크립트가 시작될 때마다 다양한 정도의 시작 지연 (수십에서 수백 밀리초) 이 발생합니다.\n특별히 필요하지 않은 경우 옵션을 항상 해제하는 것이 좋습니다. - 문서 시작 관리자 아이콘을 사용하면 문서에 더 쉽게 액세스할 수 있으며 독립 실행형 응용 프로그램처럼 전환할 수 있습니다. 로컬 문서: AutoJs6 내장 파일을 문서 소스로 사용, 네트워크 연결이 필요하지 않습니다. 내용은 AutoJs6 이 업데이트됨에 따라 변경됩니다.\n온라인 문서: GitHub 페이지를 문서 소스로 사용, 네트워크 연결 필요. 콘텐츠는 항상 최신 상태입니다.\n\n참고: 온라인 문서의 읽기 환경을 최대화하려면 데스크탑 모니터와 같은 와이드 스크린 디스플레이 장치를 사용하는 것이 좋습니다.\n참고: 버전 6.2.0 현재 문서는 아직 개발 초기 단계이며 대부분의 콘텐츠가 아직 작성되거나 업데이트되지 않았습니다. 문서 페이지에서 어두운 테마를 지원하려면 다음 조건이 충족되어야 합니다.\n1. AutoJs6 에는 야간 모드가 활성화되어 있습니다.\n2. Android 시스템 WebView (또는 Google Chrome 과 같은 브라우저):\n- Android API 레벨 29 (Android 10) [Q] 이상: 버전 >= 76\n- Android API 레벨 28 (Android 9) [P] 이하: 버전 >= 105 JavaScript 내장 개체를 확장하면 코드 유연성이 향상되고 더 풍부한 기능을 사용할 수 있지만 충돌이 발생하고 파손될 수도 있습니다.\n옵션이 켜져 있을 때 모든 스크립트에는 기본적으로 활성화된 내장 확장이 있습니다.\n기본 제공 확장은 종종 안전하지 않으며 기본 제공 확장의 원칙과 위험을 명확하게 이해하지 않는 한 권장되지 않습니다.\n옵션이 꺼져 있어도 프로젝트 문서에 설명된 대로 플러그인 전역 개체를 통해 내장 확장을 계속 활성화할 수 있습니다. @@ -59,12 +59,11 @@ 시스템 업데이트 기본값을 사용하십시오 - AutoJs6 문서 + AutoJs6 문서 + 문서 파일을 처리 할 수 없습니다 콘텐츠가 저장되지 않았습니다. 나가시겠습니까? 시스템을 따르십시오 - 런처에서 아이콘 숨기기 - 런처에 아이콘 표시 현지 문서 온라인 문서 텍스트 크기 변경 @@ -345,7 +344,6 @@ 이 버전을 다시 요청하지 마십시오 다시 보여주지 마세요 서류 - 설명서 실행기 아이콘 문서 소스 완료 다운로드 @@ -460,6 +458,8 @@ 레이아웃 검사 ... 오픈 소스 라이센스 통나무 + AutoJs6 통나무 + 통나무 로그인 로그인 로그인이 성공했습니다 @@ -623,6 +623,8 @@ 작업 디렉토리로 중단 점을 설정하십시오 설정 + AutoJs6 설정 + 설정 텍스트는 비어질 수 없다 레이아웃 경계보기 레이아웃 계층 구조보기 @@ -679,27 +681,30 @@ 애플리케이션이 읽을 수 있지만 쓸 수없는 시스템 환경 설정을 포함하는 보안 시스템 설정.\n이들은 사용자가 시스템 앱의 UI를 통해 명시 적으로 수정 해야하는 선호도입니다.\n보안 시스템 설정 권한을 사용하면 일반 애플리케이션이 보안 설정 (예: 접근성 서비스)을 직접 수정할 수 있습니다. 시스템 설정을 작성하십시오 기본 - 仅最新的 %d 个条目将被发送 - 当前日志总条目数 %d 超出可发送限制 - 日志条目发送失败 - 无可发送的日志条目 - 无可导出的日志条目 - 无可复制的日志条目 - 复制失败 - 已复制到剪贴板 (仅最新的 %d 个条目) - 日志条目导出失败 - 关闭 - 查看文件 - 已导出 - 已导出 %d 个条目 + 최신 %d 항목만 전송됩니다 + 로그 항목 수 %d개가 전송 제한을 초과했습니다 + 로그 항목을 보내지 못했습니다 + 보낼 로그 항목이 없습니다 + 내보낼 로그 항목이 없습니다 + 복사할 로그 항목이 없습니다 + 복사하지 못했습니다 + 클립보드에 이미 복사되었습니다(최신 %d 항목만) + 로그 항목을 내보내지 못했습니다 + Dismiss + 파일 보기 + 내보낸 + 내보낸 %d 항목 + 이 바로 가기가 비활성화되었습니다 + 런처 바로 가기 + 바로가기는 AutoJs6 에서 특정 작업을 수행할 수 있습니다. 사용자는 지원되는 런처에 이러한 바로가기를 표시하고 AutoJs6 애플리케이션 문서 읽기, AutoJs6 설정 페이지 실행 등과 같은 일부 작업을 빠르게 시작하거나 활동을 실행할 수 있습니다. + 런처에 바로 가기 추가 + 런처에 바로가기를 고정하는 것은 지원되지 않습니다 - 총: %d 항목 총: %d 개 항목 - %d 스크립트가 중지되었습니다 %d 개의 스크립트가 중지되었습니다 diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index f1957707..6d0e70e5 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -26,7 +26,6 @@ Измените путь к директории, содержащей скрипты AutoJs6 получает и загружает обновления с GitHub.\n\nПримечание: обновление пока не обеспечивает многоязыковую поддержку. Обеспечивает определенную совместимость имен классов Java для версий 4.x путем переименования имен классов.\nПри включении этой опции при каждом запуске скрипта будет происходить задержка запуска (от десятков до сотен миллисекунд).\nРекомендуется всегда держать эту опцию выключенной, если в ней нет особой необходимости. - Значок запуска документации облегчает доступ к документам и может переключаться как отдельное приложение. Локальная документация: Использование встроенных файлов AutoJs6 в качестве источников документации, подключение к сети не требуется. Содержание меняется по мере обновления AutoJs6.\nОнлайн-документы: Использование страниц GitHub в качестве источников документации, требуется подключение к сети. Содержимое всегда обновляется.\n\nПримечание: Чтобы максимально улучшить качество чтения онлайн-документов, рекомендуется использовать широкоформатное устройство отображения, например настольный монитор.\nПримечание: Начиная с версии 6.2.0, документация находится на предварительной стадии разработки, и большая часть содержимого еще не была написана или обновлена. Для поддержки темной темы на страницах документов должны быть выполнены следующие условия:\n1. В AutoJs6 включен ночной режим\n2. Android System WebView (или браузеры типа Google Chrome):\n- Android API Level 29 (Android 10) [Q] и выше: версия >= 76\n- Android API Level 28 (Android 9) [P] и ниже: версия >= 105 Расширение встроенных объектов JavaScript может повысить гибкость кода и обеспечить более богатую функциональность, но может привести к конфликтам и даже поломкам.\nВсе сценарии имеют встроенные расширения, включенные по умолчанию, когда опция включена.\nВстроенные расширения часто небезопасны, и их не рекомендуется использовать, пока принципы и риски встроенных расширений не будут четко поняты.\nКогда опция выключена, встроенные расширения все еще можно включить через глобальный объект plugins, как описано в документации проекта. @@ -59,12 +58,11 @@ Система Обновить Использовать по умолчанию - AutoJs6 документы + AutoJs6 документы + документы Невозможно обработать файл Содержимое не было сохранено, вы уверены в выходе? Следовать за системой - Скрыть значок из пусковой установки - Показать значок в пусковой установке Локальные документы Онлайн-документы размер текста @@ -345,7 +343,6 @@ Не показывать снова эту версию Не показывать снова Документы - Значок пусковой установки документации Источник документации Готово Скачать @@ -460,6 +457,8 @@ Проверка макета... Лицензии на открытые источники Журнал + AutoJs6 Журнал + Журнал Вход в систему Вход Вход выполнен успешно @@ -623,6 +622,8 @@ Как рабочий каталог Установить точку останова Настройки + AutoJs6 Настройки + Настройки Текст не может быть пустым Вид в границах макета Вид в иерархии макета @@ -679,19 +680,24 @@ Настройки безопасности системы, содержащие системные предпочтения, которые приложения могут читать, но не имеют права записывать.\nОни предназначены для параметров, которые пользователь должен явно изменить через пользовательский интерфейс системного приложения.\nПри наличии разрешения на безопасные системные настройки обычные приложения могут напрямую изменять безопасные настройки (например, служба доступности). Запись системных настроек По умолчанию - 仅最新的 %d 个条目将被发送 - 当前日志总条目数 %d 超出可发送限制 - 日志条目发送失败 - 无可发送的日志条目 - 无可导出的日志条目 - 无可复制的日志条目 - 复制失败 - 已复制到剪贴板 (仅最新的 %d 个条目) - 日志条目导出失败 - 关闭 - 查看文件 - 已导出 - 已导出 %d 个条目 + Будут отправлены только последние %d элементов + Количество записей журнала %d превышает лимит для отправки + Не удалось отправить записи журнала + Нет записей журнала для отправки + Нет записей журнала для экспорта + Нет записей журнала для копирования + Не удалось скопировать + Уже скопировано в буфер обмена (только последние %d элементов) + Не удалось экспортировать записи журнала + Удалить + Просмотр файла + Экспортировано + Экспортировано %d элементов + Этот ярлык отключен + Ярлыки лаунчера + Ярлыки позволяют выполнять определенные действия в AutoJs6. Пользователи могут отображать эти ярлыки в поддерживаемой программе запуска и быстро запускать некоторые задачи или действия, например, читать документацию по приложению AutoJs6, запускать страницу настроек AutoJs6 и т.д. + Добавление ярлыков в пусковую установку + Закрепление ярлыков в пусковой установке не поддерживается Всего: %d элемент diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index ba7401d6..0f76b78d 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -26,7 +26,6 @@ 更改包含腳本的文件夾路徑 AutoJs6 從 GitHub 獲取並下載更新.\n\n注: 版本更新內容暫未提供多語言支持. 通過類名重映射, 提供一定程度上的 4.x 版本 Java 類名兼容.\n開啓選項後, 每次啓動腳本將出現不同程度的啓動延遲 (幾十到幾百毫秒不等).\n如無特別需求, 建議始終保持選項關閉. - 文檔啓動器圖標便於直接訪問文檔, 並可像獨立應用程序一樣進行切換. 本地文檔: AutoJs6 內置文件作為文檔來源, 無需網絡連接, 隨 AutoJs6 應用更新而發生內容變動.\n在線文檔: 使用 GitHub 網頁作為文檔來源, 需網絡連接, 可隨時保持文檔內容為最新.\n\n注: 為最大化在線文檔的閲讀體驗, 建議使用桌面顯示器等寬屏顯示設備閲讀.\n注: 截至 6.2.0 版本, 文檔尚處於初步編寫階段, 大部分內容尚未完成編寫或更新. 文檔頁面的深色主題支持需要滿足以下條件:\n1. AutoJs6 開啓夜間模式\n2. WebView (或 Google Chrome 等瀏覽器) 版本要求:\n- API 級別 29 (安卓 10) [Q] 及以上: 版本不低於 76\n- API 級別 28 (安卓 9) [P] 及以下: 版本不低於 105 擴展 JavaScript 內置對象可以增加代碼靈活性並實現更豐富的功能, 但可能造成衝突甚至破壞.\n選項開啓後所有腳本均默認啓用內置擴展.\n內置擴展往往是不安全的, 除非明確瞭解內置擴展的原理及風險, 否則不建議啓用.\n選項關閉後, 仍然可以通過 plugins 全局對象啓用內置擴展, 詳見項目文檔. @@ -59,12 +58,11 @@ @string/dialog_button_system_settings 立即更新 使用默認值 - AutoJs6 文檔 + AutoJs6 文檔 + 文檔 無法處理文件 內容尚未保存, 確定要退出嗎 跟隨系統 - 隱藏啓動器圖標 - 顯示啓動器圖標 本地文檔 在線文檔 更改字體大小 @@ -345,7 +343,6 @@ 此版本不再提示 不再提示 文檔 - 文檔啓動器圖標 文檔源 完成 下載 @@ -460,6 +457,8 @@ 佈局分析中... 開源許可信息 日誌 + AutoJs6 日誌 + 日誌 登錄中 登錄 登錄成功 @@ -623,6 +622,8 @@ 用作工作路徑 設置斷點 設置 + AutoJs6 設置 + 設置 文本不能為空 在佈局範圍中查看 在佈局層次中查看 @@ -679,19 +680,24 @@ 安全設置包含應用程序可讀但不可寫入的設置選項, 這些選項只能由 UI 或系統級別應用修改.\n被授予 \"修改安全設置權限\" 後, 普通應用可直接修改上述安全設置 (例如無障礙服務). 修改系統設置 默認 - 仅最新的 %d 个条目将被发送 - 当前日志总条目数 %d 超出可发送限制 - 日志条目发送失败 - 无可发送的日志条目 - 无可导出的日志条目 - 无可复制的日志条目 - 复制失败 - 已复制到剪贴板 (仅最新的 %d 个条目) - 日志条目导出失败 - 关闭 + 僅最新的 %d 個條目將被髮送 + 當前日誌總條目數 %d 超出可發送限制 + 日誌條目發送失敗 + 無可發送的日誌條目 + 無可導出的日誌條目 + 無可複製的日誌條目 + 複製失敗 + 已複製到剪貼板 (僅最新的 %d 個條目) + 日誌條目導出失敗 + 關閉 查看文件 - 已导出 - 已导出 %d 个条目 + 已導出 + 已導出 %d 個條目 + 此快捷方式已禁用 + 啓動器快捷方式 + 快捷方式可以在 AutoJs6 中執行特定操作, 用户可以在啓動器中顯示這些快捷方式, 並快速開始某些任務或啓動某個活動, 如閲讀 AutoJs6 應用文檔, 啓動 AutoJs6 設置頁面等. + 添加快捷方式到啓動器 + 將快捷方式固定到啓動器不被支持 共計: %d 項 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index da436771..5e9f0734 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -26,7 +26,6 @@ 更改包含指令碼的資料夾路徑 AutoJs6 從 GitHub 獲取並下載更新.\n\n注: 版本更新內容暫未提供多語言支援. 透過類名重對映, 提供一定程度上的 4.x 版本 Java 類名相容.\n開啟選項後, 每次啟動指令碼將出現不同程度的啟動延遲 (幾十到幾百毫秒不等).\n如無特別需求, 建議始終保持選項關閉. - 文件啟動器圖示便於直接訪問文件, 並可像獨立應用程式一樣進行切換. 本地文件: AutoJs6 內建檔案作為文件來源, 無需網路連線, 隨 AutoJs6 應用更新而發生內容變動.\n線上文件: 使用 GitHub 網頁作為文件來源, 需網路連線, 可隨時保持文件內容為最新.\n\n注: 為最大化線上文件的閱讀體驗, 建議使用桌面顯示器等寬屏顯示裝置閱讀.\n注: 截至 6.2.0 版本, 文件尚處於初步編寫階段, 大部分內容尚未完成編寫或更新. 文件頁面的深色主題支援需要滿足以下條件:\n1. AutoJs6 開啟夜間模式\n2. WebView (或 Google Chrome 等瀏覽器) 版本要求:\n- API 級別 29 (安卓 10) [Q] 及以上: 版本不低於 76\n- API 級別 28 (安卓 9) [P] 及以下: 版本不低於 105 擴充套件 JavaScript 內建物件可以增加程式碼靈活性並實現更豐富的功能, 但可能造成衝突甚至破壞.\n選項開啟後所有指令碼均預設啟用內建擴充套件.\n內建擴充套件往往是不安全的, 除非明確瞭解內建擴充套件的原理及風險, 否則不建議啟用.\n選項關閉後, 仍然可以透過 plugins 全域性物件啟用內建擴充套件, 詳見專案文件. @@ -59,12 +58,11 @@ @string/dialog_button_system_settings 立即更新 使用預設值 - AutoJs6 文件 + AutoJs6 文件 + 文件 無法處理檔案 內容尚未儲存, 確定要退出嗎 跟隨系統 - 隱藏啟動器圖示 - 顯示啟動器圖示 本地文件 線上文件 更改字型大小 @@ -345,7 +343,6 @@ 此版本不再提示 不再提示 文件 - 文件啟動器圖示 文件源 完成 下載 @@ -460,6 +457,8 @@ 佈局分析中... 開源許可資訊 日誌 + AutoJs6 日誌 + 日誌 登入中 登入 登入成功 @@ -623,6 +622,8 @@ 用作工作路徑 設定斷點 設定 + AutoJs6 設定 + 設定 文字不能為空 在佈局範圍中檢視 在佈局層次中檢視 @@ -679,19 +680,24 @@ 安全設定包含應用程式可讀但不可寫入的設定選項, 這些選項只能由 UI 或系統級別應用修改.\n被授予 \"修改安全設定許可權\" 後, 普通應用可直接修改上述安全設定 (例如無障礙服務). 修改系統設定 預設 - 仅最新的 %d 个条目将被发送 - 当前日志总条目数 %d 超出可发送限制 - 日志条目发送失败 - 无可发送的日志条目 - 无可导出的日志条目 - 无可复制的日志条目 - 复制失败 - 已复制到剪贴板 (仅最新的 %d 个条目) - 日志条目导出失败 - 关闭 - 查看文件 - 已导出 - 已导出 %d 个条目 + 僅最新的 %d 個條目將被髮送 + 當前日誌總條目數 %d 超出可傳送限制 + 日誌條目傳送失敗 + 無可傳送的日誌條目 + 無可導出的日誌條目 + 無可複製的日誌條目 + 複製失敗 + 已複製到剪貼簿 (僅最新的 %d 個條目) + 日誌條目匯出失敗 + 關閉 + 檢視檔案 + 已匯出 + 已匯出 %d 個條目 + 此快捷方式已禁用 + 啟動器快捷方式 + 快捷方式可以在 AutoJs6 中執行特定操作, 使用者可以在啟動器中顯示這些快捷方式, 並快速開始某些任務或啟動某個活動, 如閲讀 AutoJs6 應用文件, 啟動 AutoJs6 設定頁面等. + 新增快捷方式到啟動器 + 將快捷方式固定到啟動器不被支援 共計: %d 項 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index b211c184..c6298622 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -22,7 +22,6 @@ 更改包含脚本的文件夹路径 AutoJs6 从 GitHub 获取并下载更新.\n\n注: 版本更新内容暂未提供多语言支持. 通过类名重映射, 提供一定程度上的 4.x 版本 Java 类名兼容.\n开启选项后, 每次启动脚本将出现不同程度的启动延迟 (几十到几百毫秒不等).\n如无特别需求, 建议始终保持选项关闭. - 文档启动器图标便于直接访问文档, 并可像独立应用程序一样进行切换. 本地文档: AutoJs6 内置文件作为文档来源, 无需网络连接, 随 AutoJs6 应用更新而发生内容变动.\n在线文档: 使用 GitHub 网页作为文档来源, 需网络连接, 可随时保持文档内容为最新.\n\n注: 为最大化在线文档的阅读体验, 建议使用桌面显示器等宽屏显示设备阅读.\n注: 截至 6.2.0 版本, 文档尚处于初步编写阶段, 大部分内容尚未完成编写或更新. 文档页面的深色主题支持需要满足以下条件:\n1. AutoJs6 开启夜间模式\n2. WebView (或 Google Chrome 等浏览器) 版本要求:\n- API 级别 29 (安卓 10) [Q] 及以上: 版本不低于 76\n- API 级别 28 (安卓 9) [P] 及以下: 版本不低于 105 扩展 JavaScript 内置对象可以增加代码灵活性并实现更丰富的功能, 但可能造成冲突甚至破坏.\n选项开启后所有脚本均默认启用内置扩展.\n内置扩展往往是不安全的, 除非明确了解内置扩展的原理及风险, 否则不建议启用.\n选项关闭后, 仍然可以通过 plugins 全局对象启用内置扩展, 详见项目文档. @@ -55,12 +54,11 @@ @string/dialog_button_system_settings 立即更新 使用默认值 - AutoJs6 文档 + AutoJs6 文档 + 文档 无法处理文件 内容尚未保存, 确定要退出吗 跟随系统 - 隐藏启动器图标 - 显示启动器图标 本地文档 在线文档 更改字体大小 @@ -341,7 +339,6 @@ 此版本不再提示 不再提示 文档 - 文档启动器图标 文档源 完成 下载 @@ -456,6 +453,8 @@ 布局分析中... 开源许可信息 日志 + AutoJs6 日志 + 日志 登录中 登录 登录成功 @@ -619,6 +618,8 @@ 用作工作路径 设置断点 设置 + AutoJs6 设置 + 设置 文本不能为空 在布局范围中查看 在布局层次中查看 @@ -688,6 +689,11 @@ 查看文件 已导出 已导出 %d 个条目 + 此快捷方式已禁用 + 启动器快捷方式 + 快捷方式可以在 AutoJs6 中执行特定操作, 用户可以在启动器中显示这些快捷方式, 并快速开始某些任务或启动某个活动, 如阅读 AutoJs6 应用文档, 启动 AutoJs6 设置页面等. + 添加快捷方式到启动器 + 将快捷方式固定到启动器不被支持 共计: %d 项 diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 4c2dbbc5..345bb58d 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -20,21 +20,11 @@ @string/entry_documentation_source_online - - @string/key_documentation_launcher_icon_show - @string/key_documentation_launcher_icon_hide - - - - @string/entry_documentation_launcher_icon_show - @string/entry_documentation_launcher_icon_hide - - @string/key_app_language_auto - @string/key_app_language_zh - @string/key_app_language_zh_hk - @string/key_app_language_zh_tw + @string/key_app_language_zh_hans + @string/key_app_language_zh_hant_hk + @string/key_app_language_zh_hant_tw @string/key_app_language_en @string/key_app_language_fr @string/key_app_language_es @@ -46,9 +36,9 @@ @string/entry_app_language_auto - @string/entry_app_language_zh - @string/entry_app_language_zh_hk - @string/entry_app_language_zh_tw + @string/entry_app_language_zh_hans + @string/entry_app_language_zh_hant_hk + @string/entry_app_language_zh_hant_tw @string/entry_app_language_en @string/entry_app_language_fr @string/entry_app_language_es diff --git a/app/src/main/res/values/bools.xml b/app/src/main/res/values/bools.xml index 8313d9e7..e63d8ab2 100644 --- a/app/src/main/res/values/bools.xml +++ b/app/src/main/res/values/bools.xml @@ -1,5 +1,7 @@ + false + false false false true diff --git a/app/src/main/res/values/ic_app_shortcut_docs_adaptive_background.xml b/app/src/main/res/values/ic_app_shortcut_docs_adaptive_background.xml new file mode 100644 index 00000000..05325cd1 --- /dev/null +++ b/app/src/main/res/values/ic_app_shortcut_docs_adaptive_background.xml @@ -0,0 +1,4 @@ + + + #68AA1C + \ No newline at end of file diff --git a/app/src/main/res/values/ic_app_shortcut_log_adaptive_background.xml b/app/src/main/res/values/ic_app_shortcut_log_adaptive_background.xml new file mode 100644 index 00000000..1293898f --- /dev/null +++ b/app/src/main/res/values/ic_app_shortcut_log_adaptive_background.xml @@ -0,0 +1,4 @@ + + + #68AA1C + \ No newline at end of file diff --git a/app/src/main/res/values/ic_app_shortcut_settings_adaptive_background.xml b/app/src/main/res/values/ic_app_shortcut_settings_adaptive_background.xml new file mode 100644 index 00000000..642473af --- /dev/null +++ b/app/src/main/res/values/ic_app_shortcut_settings_adaptive_background.xml @@ -0,0 +1,4 @@ + + + #68AA1C + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 844da8b8..3494b34c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -60,7 +60,6 @@ Change the path of the directory containing scripts AutoJs6 gets and downloads updates from GitHub.\n\nNote: The update does not provide multilingual support yet. Provides a degree of Java class name compatibility for 4.x versions through class name remapping.\nWith this option turned on, there will be a varying degree of startup delay (tens to hundreds of milliseconds) each time the script is started.\nIt is recommended to keep the option off at all times if not specifically required. - description_documentation_launcher_icon_preference Local docs: Using AutoJs6 build-in files as documentation sources, no network connection required. The content changes as AutoJs6 is updated.\nOnline docs: Using GitHub pages as documentation sources, requiring network connection. The content is always up to date.\n\nNote: To maximize the reading experience of online documents, it is recommended to use a widescreen display device such as a desktop monitor.\nNote: As of version 6.2.0, the documentation is still in the preliminary stages of development, and most of the content has not yet been written or updated. The following conditions must be met for dark theme support on document pages:\n1. AutoJs6 has night mode enabled\n2. Android System WebView (or browsers like Google Chrome):\n- Android API Level 29 (Android 10) [Q] and above: version >= 76\n- Android API Level 28 (Android 9) [P] and below: version >= 105 Extending JavaScript built-in objects can increase code flexibility and enable richer functionality, but can cause conflicts and even breakage.\nAll scripts have built-in extensions enabled by default when the option is turned on.\nBuilt-in extensions are often insecure, and are not recommended unless the principles and risks of built-in extensions are clearly understood.\nWhen the option is turned off, built-in extensions can still be enabled through the plugins global object, as described in the project documentation. @@ -95,7 +94,8 @@ System Update Use default - AutoJs6 Docs + AutoJs6 Docs + Docs Can\'t process file The content has not been saved, are you sure to exit? hybbbb1996@gmail.com @@ -107,11 +107,9 @@ 日本語 한국어 Русский - 简体中文 - 繁體中文 (香港) - 繁體中文 (台灣) - Hide icon from launcher - Show icon in launcher + 简体中文 + 繁體中文 (香港) + 繁體中文 (台灣) Local docs Online docs Change text size @@ -217,7 +215,7 @@ AutoJs6 foreground service Build succeeded.\nFile path: %s Debug [ %s ] - com.example.script%d + org.autojs.autojs6.%s %.1fKB/%.1fKB %.2fMB/%.2fMB Chars: %d\nLines: %d\nSize: %s @@ -238,12 +236,13 @@ key_$_app_language_ja key_$_app_language_ko key_$_app_language_ru - key_$_app_language_zh - key_$_app_language_zh_hk - key_$_app_language_zh_tw + key_$_app_language_zh + key_$_app_language_zh_hk + key_$_app_language_zh_tw key_$_auto_check_for_updates key_$_auto_night_mode_enabled key_$_change_working_dir + key_$_launcher_shortcuts key_$_check_for_updates key_$_client_socket_normally_closed key_$_compatibility_with_classes_for_ver_4_x @@ -252,9 +251,6 @@ key_$_dialog_foreground_svc key_$_dialog_log_entries_exported key_$_dialog_manage_all_files_permission - key_$_documentation_launcher_icon - key_$_documentation_launcher_icon_hide - key_$_documentation_launcher_icon_show key_$_documentation_source key_$_documentation_source_local key_$_documentation_source_online @@ -531,7 +527,6 @@ Don’t ask again for this version Don\'t show again Documents - Documentation launcher icon Documentation source Done Download @@ -648,6 +643,8 @@ Inspecting layout... Open Sources Licenses Log + AutoJs6 Log + Log Logging in Login Login succeeded @@ -818,6 +815,8 @@ Set as working dir Set a breakpoint Settings + AutoJs6 Settings + Settings AutoJs6:\n&url_github_autojs6; Should never happen Text can\'t be empty @@ -887,19 +886,27 @@ EN Auto ZH_CN - 仅最新的 %d 个条目将被发送 - 当前日志总条目数 %d 超出可发送限制 - 日志条目发送失败 - 无可发送的日志条目 - 无可导出的日志条目 - 无可复制的日志条目 - 复制失败 - 已复制到剪贴板 (仅最新的 %d 个条目) - 日志条目导出失败 - 关闭 - 查看文件 - 已导出 - 已导出 %d 个条目 + Only latest %d items will be sent + Number of log entries %d exceeds the limit for sending + Failed to send log entries + No log entries to send + No log entries to export + No log entries to copy + Failed to copy + Already copied to clipboard (only latest %d items) + Failed to export log entries + Dismiss + View File + Exported + %d items exported + This shortcut is disabled + shortcut_$_settings + shortcut_$_docs + shortcut_$_log + Launcher shortcuts + Shortcuts can perform specific actions in AutoJs6. Users can display these shortcuts in a supported launcher and quickly start some tasks or launch an activity, such as reading AutoJs6 application documentation, launching AutoJs6 settings page, and so on. + Add shortcuts to launcher + Pinning shortcuts to launcher is not supported Total: %d item diff --git a/app/src/main/res/xml-v25/app_shortcuts.xml b/app/src/main/res/xml-v25/app_shortcuts.xml new file mode 100644 index 00000000..3d2fb796 --- /dev/null +++ b/app/src/main/res/xml-v25/app_shortcuts.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml-v30/accessibility_service_config.xml b/app/src/main/res/xml-v30/accessibility_service_config.xml new file mode 100644 index 00000000..725ffba5 --- /dev/null +++ b/app/src/main/res/xml-v30/accessibility_service_config.xml @@ -0,0 +1,13 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/xml-v33/app_shortcuts.xml b/app/src/main/res/xml-v33/app_shortcuts.xml new file mode 100644 index 00000000..ff6cc9fb --- /dev/null +++ b/app/src/main/res/xml-v33/app_shortcuts.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/accessibility_service_config.xml b/app/src/main/res/xml/accessibility_service_config.xml index b0e4ec53..0f3aa736 100644 --- a/app/src/main/res/xml/accessibility_service_config.xml +++ b/app/src/main/res/xml/accessibility_service_config.xml @@ -1,4 +1,5 @@ + \ No newline at end of file diff --git a/app/src/main/res/xml/fragment_preferences.xml b/app/src/main/res/xml/fragment_preferences.xml index 9778bb1b..360d2bca 100644 --- a/app/src/main/res/xml/fragment_preferences.xml +++ b/app/src/main/res/xml/fragment_preferences.xml @@ -59,14 +59,12 @@ app:longClickPrompt="@string/description_documentation_source_preference" app:longClickPromptMore="@string/description_documentation_source_preference_more" /> - + app:key="@string/key_launcher_shortcuts" + app:title="@string/text_launcher_shortcuts" + app:summary="@string/summary_text_launcher_shortcuts" + app:longClickPrompt="@string/description_launcher_shortcuts" /> + app:summary="@string/summary_guard_mode" /> diff --git a/app/src/main/res/xml/locales_config.xml b/app/src/main/res/xml/locales_config.xml new file mode 100644 index 00000000..3b777caf --- /dev/null +++ b/app/src/main/res/xml/locales_config.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/script_widget_config.xml b/app/src/main/res/xml/script_widget_config.xml index d953bde9..4b77d600 100644 --- a/app/src/main/res/xml/script_widget_config.xml +++ b/app/src/main/res/xml/script_widget_config.xml @@ -2,7 +2,9 @@ \ No newline at end of file + android:resizeMode="horizontal|vertical" /> \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 25b8eff4..57c0b1a6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,7 +23,7 @@ allprojects { tasks { register("clean").configure { - // delete(rootProject.buildDir) + // @Legacy delete(rootProject.buildDir) delete(rootProject.layout.buildDirectory) } } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f6352a35..320e32d1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Oct 02 14:59:53 CST 2023 +#Thu Oct 05 15:05:58 CST 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-rc-3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/libs/com.zeugmasolutions.localehelper-1.5.1/localehelper-1.5.1-modified.aar b/libs/com.zeugmasolutions.localehelper-1.5.1/localehelper-1.5.1-modified.aar deleted file mode 100644 index f386bb5c..00000000 Binary files a/libs/com.zeugmasolutions.localehelper-1.5.1/localehelper-1.5.1-modified.aar and /dev/null differ diff --git a/libs/dev.rikka.shizuku-aidl-13.1.5/aidl-13.1.5.aar b/libs/dev.rikka.shizuku-aidl-13.1.5/aidl-13.1.5.aar new file mode 100644 index 00000000..47d5c32a Binary files /dev/null and b/libs/dev.rikka.shizuku-aidl-13.1.5/aidl-13.1.5.aar differ diff --git a/libs/com.zeugmasolutions.localehelper-1.5.1/build.gradle.kts b/libs/dev.rikka.shizuku-aidl-13.1.5/build.gradle.kts similarity index 69% rename from libs/com.zeugmasolutions.localehelper-1.5.1/build.gradle.kts rename to libs/dev.rikka.shizuku-aidl-13.1.5/build.gradle.kts index ee22b315..c97ba7c7 100644 --- a/libs/com.zeugmasolutions.localehelper-1.5.1/build.gradle.kts +++ b/libs/dev.rikka.shizuku-aidl-13.1.5/build.gradle.kts @@ -1,7 +1,4 @@ -// @Modified -// ! Current library (Locale Helper) was modified by SuperMonster003 on Jun 16, 2022. - -"localehelper-1.5.1-modified.aar" +"aidl-13.1.5.aar" .let { path -> rootProject.extra["configurationName"].toString().let { name -> configurations.maybeCreate(name) diff --git a/libs/dev.rikka.shizuku-api-13.1.5/api-13.1.5.aar b/libs/dev.rikka.shizuku-api-13.1.5/api-13.1.5.aar new file mode 100644 index 00000000..575a55f0 Binary files /dev/null and b/libs/dev.rikka.shizuku-api-13.1.5/api-13.1.5.aar differ diff --git a/libs/dev.rikka.shizuku-api-13.1.5/build.gradle.kts b/libs/dev.rikka.shizuku-api-13.1.5/build.gradle.kts new file mode 100644 index 00000000..455698c0 --- /dev/null +++ b/libs/dev.rikka.shizuku-api-13.1.5/build.gradle.kts @@ -0,0 +1,9 @@ +"api-13.1.5.aar" + .let { path -> + rootProject.extra["configurationName"].toString().let { name -> + configurations.maybeCreate(name) + file(path).takeIf { it.exists() }?.also { + artifacts.add(name, it) + } ?: throw Exception("File not found: \"$path\"") + } + } \ No newline at end of file diff --git a/libs/dev.rikka.shizuku-provider-13.1.5/build.gradle.kts b/libs/dev.rikka.shizuku-provider-13.1.5/build.gradle.kts new file mode 100644 index 00000000..12733494 --- /dev/null +++ b/libs/dev.rikka.shizuku-provider-13.1.5/build.gradle.kts @@ -0,0 +1,9 @@ +"provider-13.1.5.aar" + .let { path -> + rootProject.extra["configurationName"].toString().let { name -> + configurations.maybeCreate(name) + file(path).takeIf { it.exists() }?.also { + artifacts.add(name, it) + } ?: throw Exception("File not found: \"$path\"") + } + } \ No newline at end of file diff --git a/libs/dev.rikka.shizuku-provider-13.1.5/provider-13.1.5.aar b/libs/dev.rikka.shizuku-provider-13.1.5/provider-13.1.5.aar new file mode 100644 index 00000000..3726735f Binary files /dev/null and b/libs/dev.rikka.shizuku-provider-13.1.5/provider-13.1.5.aar differ diff --git a/libs/dev.rikka.shizuku-shared-13.1.5/build.gradle.kts b/libs/dev.rikka.shizuku-shared-13.1.5/build.gradle.kts new file mode 100644 index 00000000..817d338b --- /dev/null +++ b/libs/dev.rikka.shizuku-shared-13.1.5/build.gradle.kts @@ -0,0 +1,9 @@ +"shared-13.1.5.aar" + .let { path -> + rootProject.extra["configurationName"].toString().let { name -> + configurations.maybeCreate(name) + file(path).takeIf { it.exists() }?.also { + artifacts.add(name, it) + } ?: throw Exception("File not found: \"$path\"") + } + } \ No newline at end of file diff --git a/libs/dev.rikka.shizuku-shared-13.1.5/shared-13.1.5.aar b/libs/dev.rikka.shizuku-shared-13.1.5/shared-13.1.5.aar new file mode 100644 index 00000000..50d5d2a0 Binary files /dev/null and b/libs/dev.rikka.shizuku-shared-13.1.5/shared-13.1.5.aar differ diff --git a/libs/org.mozilla.rhino-1.7.15-snapshot.jar b/libs/org.mozilla.rhino-1.7.15-snapshot.jar index f96448a2..0429e485 100644 Binary files a/libs/org.mozilla.rhino-1.7.15-snapshot.jar and b/libs/org.mozilla.rhino-1.7.15-snapshot.jar differ diff --git a/libs/org.opencv-4.5.5/build.gradle.kts b/libs/org.opencv-4.8.0/build.gradle.kts similarity index 82% rename from libs/org.opencv-4.5.5/build.gradle.kts rename to libs/org.opencv-4.8.0/build.gradle.kts index cc0c2efa..066eeadc 100644 --- a/libs/org.opencv-4.5.5/build.gradle.kts +++ b/libs/org.opencv-4.8.0/build.gradle.kts @@ -1,7 +1,7 @@ // @Reference -// ! Current library (OpenCV) was referred to TonyJiangWJ/Auto.js (https://github.com/TonyJiangWJ/Auto.js) on Mar 18, 2022. +// ! Current library (OpenCV) was referred to TonyJiangWJ/Auto.js (https://github.com/TonyJiangWJ/Auto.js) on Oct 18, 2022. -"opencv-4.5.5.aar" +"opencv-4.8.0.aar" .let { path -> rootProject.extra["configurationName"].toString().let { name -> configurations.maybeCreate(name) diff --git a/libs/org.opencv-4.5.5/opencv-4.5.5.aar b/libs/org.opencv-4.8.0/opencv-4.8.0.aar similarity index 68% rename from libs/org.opencv-4.5.5/opencv-4.5.5.aar rename to libs/org.opencv-4.8.0/opencv-4.8.0.aar index 269b419f..86a2549b 100644 Binary files a/libs/org.opencv-4.5.5/opencv-4.5.5.aar and b/libs/org.opencv-4.8.0/opencv-4.8.0.aar differ diff --git a/libs/paddleocr/build.gradle b/libs/paddleocr/build.gradle index 2d12e877..d82c1fa4 100644 --- a/libs/paddleocr/build.gradle +++ b/libs/paddleocr/build.gradle @@ -21,7 +21,8 @@ def versionCmake = versions.cmake def zipArchives = [ // @Hint by TonyJiangWJ on Aug 7, 2023. // ! 下载 OpenCV 源码包 (默认为 4.2.0). - // ! 和 Auto.js 中的版本 (如 4.5.5) 不匹配会产生冲突, 可按需修改. + // ! 和 Auto.js 中的版本 (如 4.8.0) 不匹配会产生冲突, + // ! 可按需修改 version.properties 中对应内容. [ "src" : "https://github.com/opencv/opencv/releases/download" + "/${versionOpencv}/opencv-${versionOpencv}-android-sdk.zip", @@ -33,11 +34,11 @@ android { namespace = "com.baidu.paddleocr" ndkVersion versionNdk - compileSdk 33 + compileSdk 34 defaultConfig { /* minSdk 默认为 23,这里修改为与 AutoJs6 最低 SDK 版本一致的 24. */ minSdk 24 - targetSdk 33 + targetSdk 34 externalNativeBuild { cmake { @@ -76,9 +77,6 @@ ext { // @Hint by TonyJiangWJ on Aug 7, 2023. // ! 首次导入最好手动运行一下这个 task 下载依赖的包. tasks.register("downloadAndExtractArchives", DefaultTask) { - doFirst { - println "Downloading and extracting archives including libs and models" - } doLast { // Prepare cache folder for archives String cachePath = "cache" @@ -89,18 +87,74 @@ tasks.register("downloadAndExtractArchives", DefaultTask) { MessageDigest messageDigest = MessageDigest.getInstance("MD5") messageDigest.update(archive.src.bytes) String cacheName = new BigInteger(1, messageDigest.digest()).toString(32) - // Download the target archive if not exists - boolean copyFiles = !file("${archive.dest}").exists() - if (!file("${cachePath}/${cacheName}.zip").exists()) { - ant.get(src: archive.src, dest: file("${cachePath}/${cacheName}.zip")) - // force to copy files from the latest archive files - copyFiles = true + + def cacheSrc = archive.src + def cacheDest = file("${cachePath}/${cacheName}.zip") + def libDest = archive.dest + def versionNameFileName = "opencv-${versionOpencv}.version" + def versionNameFile = file(new File(libDest, versionNameFileName)) + + boolean copyFiles = false + + if (cacheDest.exists()) { + println("No need to download files as the cached archive exists") + if (versionNameFile.exists()) { + println("No need to extract cached archive as the version name file exists") + } else { + println("Cached archive needs to be extracted as the version name file doesn't exist") + copyFiles = true + } + } else { + if (versionNameFile.exists()) { + println("No need to download files as the version name file exists") + } else { + def title = "Downloading and extracting the archive file including libs and models..." + def srcInfo = "Source: ${cacheSrc}" + def destInfo = "Destination: ${cacheDest}" + def hintInfo = [ + "If the download gets stuck and won't finish,", + "try downloading the source file with tools like IDM (Internet Download Manager),", + "then renaming it into the destination path above.", + ] + + def maxLength = [ + [title, srcInfo, destInfo].max { it.length() }, + hintInfo.max { it.length() }, + ].max { it.length() }.length() + + def infoList = [ + "=".repeat(maxLength), + title, + "-".repeat(maxLength), + srcInfo, + destInfo, + "-".repeat(maxLength), + hintInfo.join("\n"), + "=".repeat(maxLength), + "", + ] + infoList.forEach { println(it) } + + ant.get(src: cacheSrc, dest: cacheDest) + + // Force to copy files from the latest archive files + copyFiles = true + } } // Extract the target archive if its dest path does not exists if (copyFiles) { + if (file(libDest).exists()) { + println("Delete old files in \"${file(libDest)}\"") + delete(libDest) + } copy { from zipTree("${cachePath}/${cacheName}.zip") - into "${archive.dest}" + into libDest + } + println("All libs and models extracted into \"${file(libDest)}\"") + if (!versionNameFile.exists()) { + versionNameFile.createNewFile() + println("Version name file \"${versionNameFileName}\" created") } } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 38558bf9..4c7f2ddc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,8 @@ @file:Suppress("SpellCheckingInspection") +import org.gradle.kotlin.dsl.support.uppercaseFirstChar + + enableFeaturePreview("STABLE_CONFIGURATION_CACHE") include( @@ -8,12 +11,15 @@ include( ":libs:android-job-simplified-1.4.3", ":libs:androidx.appcompat-1.0.2", ":libs:com.tencent.bugly.crashreport-4.0.4", - ":libs:com.zeugmasolutions.localehelper-1.5.1", ":libs:jackpal.androidterm-1.0.70", ":libs:jackpal.androidterm.emulatorview-1.0.42", ":libs:jackpal.androidterm.libtermexec-1.0", - ":libs:org.opencv-4.5.5", + ":libs:org.opencv-4.8.0", ":libs:paddleocr", + ":libs:dev.rikka.shizuku-shared-13.1.5", + ":libs:dev.rikka.shizuku-aidl-13.1.5", + ":libs:dev.rikka.shizuku-api-13.1.5", + ":libs:dev.rikka.shizuku-provider-13.1.5", ":libs:android-spackle-9.0.0", ":libs:android-assertion-9.0.0", @@ -22,6 +28,18 @@ include( pluginManagement { + val platformIdentifierForAS = "AndroidStudio" + val platformIdentifierForIdea = "IntelliJIdea" + + val unknownIdentifier = "unknown" + val unknownIdentifier1Up = unknownIdentifier[0].uppercase() + unknownIdentifier.substring(1) + val previewIdentifier = "preview" + val previewIdentifier1Up = previewIdentifier[0].uppercase() + previewIdentifier.substring(1) + val predictedIdentifier = "predicted" + val predictedSuffix = " [$predictedIdentifier]" + val fallbackIdentifier = "fallback" + val fallbackSuffix = " [$fallbackIdentifier]" + // @Hint by SuperMonster003 on May 3, 2023. // ! To download archives of Android Studio, // ! visit https://developer.android.com/studio/archive?hl=en @@ -39,6 +57,7 @@ pluginManagement { "as" to mapOf( "abbr" to mapOf( "Preview2023.2" to "I", /* Aug 25, 2023. */ + "2023.1" to "H", /* Oct 18, 2023. */ "Preview2023.1" to "H", /* May 13, 2023. */ "2022.3" to "G", /* Jul 3, 2023. */ "Preview2022.3" to "G", /* May 3, 2023. */ @@ -47,43 +66,47 @@ pluginManagement { "2022.1" to "E", /* May 3, 2023. */ ), "android" to mapOf( - "Preview2023.2" to "8.3.0-alpha04", /* Sep 16, 2023. */ - "Preview2023.1" to "8.2.0-beta03", /* Sep 11, 2023. */ + "Preview2023.2" to "8.3.0-alpha10", /* Oct 24, 2023. */ + "2023.1" to "8.2.0-rc01", /* Oct 18, 2023. */ + "Preview2023.1" to "8.2.0-beta06", /* Oct 11, 2023. */ "2022.3" to "8.1.2", /* Sep 29, 2023. */ "Preview2022.3" to "8.1.0-beta05", /* Jun 14 2023. */ "2022.2" to "8.0.2", /* May 26, 2023. */ "Preview2022.2" to "8.0.0-beta05", /* Mar 25, 2023. */ "2022.1" to "7.4.2", /* Mar 25, 2023. */ - "fallback" to "7.4.2", /* May 3, 2023. */ + fallbackIdentifier to "7.4.2", /* May 3, 2023. */ ), "kotlin" to mapOf( - "Preview2023.2" to "1.9.20-Beta", /* Sep 12, 2023. */ - "Preview2023.1" to "1.9.20-Beta", /* Sep 12, 2023. */ + "Preview2023.2" to "1.9.20-RC", /* Oct 12, 2023. */ + "2023.1" to "1.9.20-RC2", /* Oct 25, 2023. */ + "Preview2023.1" to "1.9.20-RC", /* Oct 12, 2023. */ "2022.3" to "1.9.0-RC", /* Jul 3, 2023. */ "Preview2022.3" to "1.8.0", /* May 13, 2023. */ "2022.2" to "1.8.20-RC2", /* Mar 23, 2023. */ "Preview2022.2" to "1.8.0", /* Mar 23, 2023. */ "2022.1" to "1.8.0-RC2", /* Dec 20, 2022. */ - "fallback" to "1.8.0", /* Aug 17, 2023. */ + fallbackIdentifier to "1.8.0", /* Aug 17, 2023. */ ) ), "idea" to mapOf( "android" to mapOf( - "2023.2" to "8.1.0", /* Sep 15, 2023. */ + "2023.2" to "8.1.2", /* Oct 18, 2023. */ "2023.1" to "7.4.2", /* May 26, 2023. */ "2022.3" to "7.4.0-beta02", /* Mar 25, 2023. */ - "fallback" to "7.4.0", /* May 3, 2023. */ + fallbackIdentifier to "7.4.0", /* May 3, 2023. */ ), "kotlin" to mapOf( - "2023.2" to "1.9.20-Beta", /* Sep 12, 2023. */ + "2023.2" to "1.9.20-RC", /* Oct 18, 2023. */ "2023.1" to "1.8.21", /* Apr 25, 2023. */ "2022.3" to "1.8.21", /* Apr 25, 2023. */ - "fallback" to "1.8.21", /* May 3, 2023. */ + fallbackIdentifier to "1.8.21", /* May 3, 2023. */ ), ), ) val kspPluginVersionMap = mapOf( + // "1.9.20-RC2" to "1.0.13", /* Oct 25, 2023. */ + "1.9.20-RC" to "1.0.13", /* Oct 12, 2023. */ "1.9.20-Beta2" to "1.0.13", /* Sep 29, 2023. */ "1.9.20-Beta" to "1.0.13", /* Sep 12, 2023. */ "1.9.10" to "1.0.13", /* Sep 11, 2023. */ @@ -93,44 +116,60 @@ pluginManagement { "1.8.20-RC2" to "1.0.9", /* Aug 16, 2023. */ "1.8.0" to "1.0.9", /* Aug 16, 2023. */ "1.8.0-RC2" to "1.0.8", /* Aug 16, 2023. */ - "fallback" to "1.8.0-1.0.9", /* Aug 16, 2023. */ + fallbackIdentifier to "1.8.0-1.0.9", /* Aug 16, 2023. */ ) val platformNicknameForAS = mapOf( - "I" to "Iguana", - "H" to "Hedgehog", - "G" to "Giraffe", - "F" to "Flamingo", - "E" to "Electric Eel", - "D" to "Dolphin", - "C" to "Chipmunk", - "B" to "Bumblebee", - "A" to "Arctic Fox", + "Z" to "Zebra", /* Predicted on Oct 18, 2023. */ + "Y" to "Yeti", /* Predicted on Oct 18, 2023. */ + "X" to "Xiphias", /* Predicted on Oct 18, 2023. */ + "W" to "Walrus", /* Predicted on Oct 18, 2023. */ + "V" to "Vicuna", /* Predicted on Oct 18, 2023. */ + "U" to "Unicorn", /* Predicted on Oct 18, 2023. */ + "T" to "Tiger", /* Predicted on Oct 18, 2023. */ + "S" to "Snail", /* Predicted on Oct 18, 2023. */ + "R" to "Rhino", /* Predicted on Oct 18, 2023. */ + "Q" to "Quail", /* Predicted on Oct 18, 2023. */ + "P" to "Penguin", /* Predicted on Oct 18, 2023. */ + "O" to "Ostrich", /* Predicted on Oct 18, 2023. */ + "N" to "Newt", /* Predicted on Oct 18, 2023. */ + "M" to "Monkey", /* Predicted on Oct 18, 2023. */ + "L" to "Lion", /* Predicted on Oct 18, 2023. */ + "K" to "Koala", /* Predicted on Oct 18, 2023. */ + "J" to "Jaguar", /* Predicted on Oct 18, 2023. */ + "I" to "Iguana", /* Aug 25, 2023. */ + "H" to "Hedgehog", /* Apr 25, 2023. */ + "G" to "Giraffe", /* Jan 17, 2023. */ + "F" to "Flamingo", /* Sep 20, 2022. */ + "E" to "Electric Eel", /* May 11, 2022. */ + "D" to "Dolphin", /* Jan 31, 2022. */ + "C" to "Chipmunk", /* Oct 13, 2021. */ + "B" to "Bumblebee", /* May 18, 2021. */ + "A" to "Arctic Fox", /* Jan 26, 2021. */ ) - val platform = System.getProperty("idea.paths.selector") - val platformIdentifierForAS = "AndroidStudio" - val platformIdentifierForIdea = "IntelliJIdea" + /* Null safety. */ + val platform = System.getProperty("idea.paths.selector") ?: platformIdentifierForAS val isPlatformAS = platform.startsWith(platformIdentifierForAS) val isPlatformIdea = platform.startsWith(platformIdentifierForIdea) - val platformVersion = when { - isPlatformAS -> platform.substring(platformIdentifierForAS.length) - isPlatformIdea -> platform.substring(platformIdentifierForIdea.length) - else -> "Unknown" - } - val platformType = when { isPlatformAS -> "as" isPlatformIdea -> "idea" - else -> throw Exception("Unknown platform: $platform") + else -> throw Exception("$unknownIdentifier1Up platform: $platform") } - val kotlinVersion = gradlePluginVersionMap[platformType]!!["kotlin"]!!.let { kotlinMap -> - kotlinMap[platformVersion] ?: kotlinMap["fallback"]!! + val platformVersion = when { + isPlatformAS -> platform.substring(platformIdentifierForAS.length) + isPlatformIdea -> platform.substring(platformIdentifierForIdea.length) + else -> "$unknownIdentifier1Up platform version" /* Should never happen. */ } + val abbrMap = gradlePluginVersionMap[platformType]!!["abbr"] ?: mapOf() + val androidMap = gradlePluginVersionMap[platformType]!!["android"]!! + val kotlinMap = gradlePluginVersionMap[platformType]!!["kotlin"]!! + var infoList = emptyArray() gradle.extra.apply { @@ -153,35 +192,54 @@ pluginManagement { dependencies /* Gather platform information. */ { when { isPlatformAS -> { - val platformNickAbbr = gradlePluginVersionMap["as"]!!["abbr"]!![platformVersion] - val platformNick = platformNickAbbr?.let { abbr -> platformNicknameForAS[abbr]?.let { " $it" } } ?: "" + var isPredicted = false + val platformNickAbbr = abbrMap[platformVersion] ?: abbrMap["$previewIdentifier1Up$platformVersion"]?.also { + isPredicted = true + } + val platformNick = platformNickAbbr?.let { abbr -> + platformNicknameForAS[abbr]?.let { + when (isPredicted) { + true -> " [ $it ($predictedIdentifier) ]" + else -> " $it" + } + } + } ?: "" - val previewIdentifier = "Preview" - val isPreview = platformVersion.contains(previewIdentifier, true) + val isPreview = platformVersion.contains(previewIdentifier1Up, true) val previewSuffix = if (isPreview) " ($previewIdentifier)" else "" - val niceVersion = if (isPreview) platformVersion.substring(previewIdentifier.length) else platformVersion + val niceVersion = if (isPreview) platformVersion.substring(previewIdentifier1Up.length) else platformVersion "Android Studio$platformNick$previewSuffix | $niceVersion" } isPlatformIdea -> "IntelliJ IDEA $platformVersion" - else -> "Unknown" + else -> unknownIdentifier1Up }.let { infoList += "Platform: $it" } } dependencies /* Android/Kotlin Gradle Plugin. */ { - val androidMap = gradlePluginVersionMap[platformType]!!["android"]!! - val kotlinMap = gradlePluginVersionMap[platformType]!!["kotlin"]!! - arrayOf( - arrayOf("com.android.tools.build:gradle", androidMap[platformVersion], androidMap["fallback"]), - arrayOf("org.jetbrains.kotlin:kotlin-gradle-plugin", kotlinMap[platformVersion], kotlinMap["fallback"]), - ).forEach { data -> - val classpath = data[0] - val version = data[1] - val versionFallback = data[2] + arrayOf( + /* classpath = */ "com.android.tools.build:gradle", + /* version = */ androidMap[platformVersion], + /* versionPredicted = */ androidMap["$previewIdentifier1Up$platformVersion"], + /* versionFallback = */ androidMap[fallbackIdentifier], + ), + arrayOf( + /* classpath = */ "org.jetbrains.kotlin:kotlin-gradle-plugin", + /* version = */ kotlinMap[platformVersion], + /* versionPredicted = */ kotlinMap["$previewIdentifier1Up$platformVersion"], + /* versionFallback = */ kotlinMap[fallbackIdentifier], + ), + ).forEach { + val (classpath, version, versionPredicted, versionFallback) = it - val classpathNotation = "$classpath:${version ?: versionFallback}" - val suffix = version?.let { "" } ?: " [fallback]" + var suffix = "" + val classpathNotation = "$classpath:" + ( + version ?: versionPredicted?.also { + suffix += predictedSuffix + } ?: versionFallback?.also { + suffix += fallbackSuffix + } ?: throw Exception("$unknownIdentifier1Up version for classpath $classpath")) infoList += "Classpath: \"$classpathNotation\"$suffix" classpath(classpathNotation) @@ -192,15 +250,31 @@ pluginManagement { plugins { arrayOf( - arrayOf("com.google.devtools.ksp", kspPluginVersionMap[kotlinVersion], kspPluginVersionMap["fallback"], false), + arrayOf( + /* id = */ "com.google.devtools.ksp", + /* kspVersionKey = */ kotlinMap[platformVersion], + /* kspVersionPredictedKey = */ kotlinMap["$previewIdentifier1Up$platformVersion"], + /* kspVersionFallbackKey = */ kotlinMap[fallbackIdentifier], + /* isApply = */ false, + ), ).forEach { data -> val id = data[0] as String - val kspVersion = data[1] as String? - val kspVersionFallback = data[2] as String - val isApply = data[3] as Boolean + val kspVersionKey = data[1] as String? + val kspVersionPredictedKey = data[2] as String? + val kspVersionFallbackKey = data[3] as String + val isApply = data[4] as Boolean - val pluginVersion = kspVersion?.let { "$kotlinVersion-$it" } ?: kspVersionFallback - val suffix = kspVersion?.let { "" } ?: " [fallback]" + var suffix = "" + + val pluginVersion = kspPluginVersionMap[kspVersionKey]?.let { + "$kspVersionKey-$it" + } ?: kspPluginVersionMap[kspVersionPredictedKey]?.let { + suffix += predictedSuffix + "$kspVersionPredictedKey-$it" + } ?: kspPluginVersionMap[kspVersionFallbackKey]?.let { + suffix += fallbackSuffix + "$kspVersionFallbackKey-$it" + } ?: throw Exception("$unknownIdentifier1Up version for plugin $id") infoList += "Plugin: \"$id:$pluginVersion\"$suffix" id(id) version pluginVersion apply isApply @@ -209,7 +283,7 @@ pluginManagement { extra /* Print information. */ { val title = "Version information for IDE platform and Gradle plugins" - val maxLength = infoList.maxOf { it.length } + val maxLength = infoList.plus(title).maxOf { it.length } arrayOf( "=".repeat(maxLength), diff --git a/version.properties b/version.properties index 2464bced..1380ff39 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Tue Oct 03 00:07:32 CST 2023 -BUILD_TIME=1696262852412 +#Wed Oct 25 13:19:15 CST 2023 +BUILD_TIME=1698211155142 CMAKE_VERSION=3.10.2 COMPILE_SDK_VERSION=34 JAVA_VERSION=22 @@ -7,8 +7,9 @@ JAVA_VERSION_MIN_SUGGESTED=19 JAVA_VERSION_MIN_SUPPORTED=17 MIN_SDK_VERSION=24 NDK_VERSION=21.1.6352462 -OPENCV_VERSION=4.5.5 +OPENCV_VERSION=4.8.0 TARGET_SDK_VERSION=34 -VERSION_BUILD=2130 -VERSION_NAME=6.3.4 Alpha2 +TARGET_SDK_VERSION_INRT=29 +VERSION_BUILD=2133 +VERSION_NAME=6.4.0 Alpha3 VSCODE_EXT_REQUIRED_VERSION=1.0.7