6.4.0 Pre - 新增 barcode/qrcode/shizuku 等模块; 适配高版本系统语言设置; 优化打包功能; 支持应用快捷方式; 修复屏幕旋转相关问题
18
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
|
||||
|
||||
@@ -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<TaskExecutionGraph> {
|
||||
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<Copy>("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<TaskExecutionGraph> {
|
||||
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<String>) {
|
||||
project.gradle.taskGraph.whenReady(object : Action<TaskExecutionGraph> {
|
||||
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)
|
||||
|
||||
@@ -74,7 +74,9 @@
|
||||
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"
|
||||
tools:ignore="SystemPermissionTypo"/>
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.DUMP"
|
||||
@@ -113,19 +115,22 @@
|
||||
|
||||
<uses-permission android:name="android.permission.READ_SMS"/>
|
||||
|
||||
<!-- Property "largeHeap" is not recommended to set to true. -->
|
||||
<!-- https://stackoverflow.com/questions/27396892/what-are-advantages-of-setting-largeheap-to-true -->
|
||||
<application
|
||||
android:name="org.autojs.autojs.App"
|
||||
android:allowBackup="false"
|
||||
android:extractNativeLibs="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@drawable/autojs6_material"
|
||||
android:icon="${icon}"
|
||||
android:label="${appName}"
|
||||
android:largeHeap="true"
|
||||
android:largeHeap="false"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:ignore="DataExtractionRules">
|
||||
tools:ignore="DataExtractionRules"
|
||||
tools:targetApi="tiramisu">
|
||||
|
||||
<meta-data
|
||||
android:name="CHANNEL"
|
||||
@@ -141,8 +146,14 @@
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="${intentCategory}"/>
|
||||
<category android:name="${intentCategory}"/>
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.shortcuts"
|
||||
android:resource="@xml/app_shortcuts"/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
@@ -165,6 +176,16 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${authorities}"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths"/>
|
||||
</provider>
|
||||
|
||||
<activity
|
||||
android:name="org.autojs.autojs.ui.edit.EditActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize|locale"
|
||||
@@ -179,6 +200,7 @@
|
||||
|
||||
<activity
|
||||
android:name="org.autojs.autojs.ui.settings.PreferencesActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme.Settings"/>
|
||||
|
||||
<activity
|
||||
@@ -197,13 +219,14 @@
|
||||
|
||||
<activity android:name="org.autojs.autojs.ui.project.ProjectConfigActivity"/>
|
||||
|
||||
<activity android:name="org.autojs.autojs.ui.log.LogActivity"/>
|
||||
<activity
|
||||
android:name="org.autojs.autojs.ui.log.LogActivity"
|
||||
android:exported="true"/>
|
||||
|
||||
<activity
|
||||
android:name="org.autojs.autojs.ui.doc.DocumentationActivity"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/ic_docs_app"
|
||||
android:label="@string/docs_app_name"
|
||||
android:label="@string/text_app_shortcut_docs_long_label"
|
||||
android:taskAffinity="org.autojs.autojs.ui.doc.DocumentationActivity"
|
||||
android:theme="@style/AppTheme.FullScreen">
|
||||
|
||||
@@ -562,14 +585,25 @@
|
||||
android:multiprocess="false"
|
||||
android:permission="android.permission.INTERACT_ACROSS_USERS_FULL"/>
|
||||
|
||||
<service
|
||||
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
|
||||
android:enabled="false"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="autoStoreLocales"
|
||||
android:value="true" />
|
||||
</service>
|
||||
|
||||
<activity
|
||||
android:name="org.autojs.autojs.inrt.SplashActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme.Splash">
|
||||
<intent-filter tools:ignore="ExtraText">
|
||||
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
|
||||
<category android:name="${intentCategoryInrt}"/>
|
||||
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="org.autojs.autojs.inrt.LogActivity"/>
|
||||
@@ -577,15 +611,12 @@
|
||||
<activity android:name="org.autojs.autojs.inrt.SettingsActivity"/>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${authorities}"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths"/>
|
||||
</provider>
|
||||
|
||||
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"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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
|
||||
* `依赖` 本地化 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
|
||||
@@ -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' ],
|
||||
|
||||
@@ -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}
|
||||
|
||||
146
app/src/main/assets/modules/__barcode__.js
Normal file
@@ -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;
|
||||
};
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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] });
|
||||
|
||||
121
app/src/main/assets/modules/__qrcode__.js
Normal file
@@ -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;
|
||||
};
|
||||
45
app/src/main/assets/modules/__shizuku__.js
Normal file
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
})(),
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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", "") ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<AsyncTask>()
|
||||
|
||||
private var mWaitWhenIdle: Boolean
|
||||
|
||||
private val allTasks = ConcurrentLinkedQueue<AsyncTask>()
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
* This method need to be annotated with {@link Keep} to prevent ProGuard from removing it.
|
||||
*
|
||||
* @param context Context created with createPackageContextAsUser
|
||||
* @see <a href="https://github.com/RikkaApps/Shizuku-API/blob/672f5efd4b33c2441dbf609772627e63417587ac/server-shared/src/main/java/rikka/shizuku/server/UserService.java#L66">code used to create the instance of this class</a>
|
||||
*/
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -86,8 +86,10 @@ data class ExecutionConfig(
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<ExecutionConfig> {
|
||||
|
||||
const val tag = "execution.config"
|
||||
|
||||
@JvmStatic
|
||||
val tag = "execution.config"
|
||||
fun getTag() = tag
|
||||
|
||||
@JvmStatic
|
||||
val default: ExecutionConfig
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<App>
|
||||
|
||||
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<Drawable>() {
|
||||
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
||||
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<Drawable>() {
|
||||
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
||||
drawableCallback.onLoaded(resource)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun load(view: View, uri: Uri, bitmapCallback: ImageLoader.BitmapCallback) {
|
||||
Glide.with(this@App)
|
||||
.asBitmap()
|
||||
.load(uri)
|
||||
.into(object : SimpleTarget<Bitmap>() {
|
||||
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
|
||||
bitmapCallback.onLoaded(resource)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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) ||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<ApplicationInfo> = 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)
|
||||
}
|
||||
}
|
||||
|
||||
72
app/src/main/java/org/autojs/autojs/runtime/api/Barcode.kt
Normal file
@@ -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<WrappedBarcode> {
|
||||
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<WrappedBarcode>? = null
|
||||
|
||||
val resultScan = scanner.process(inputImage)
|
||||
.addOnSuccessListener { barcodes: MutableList<MLKitBarcode> ->
|
||||
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"
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -69,6 +69,7 @@ class OcrMLKit {
|
||||
}
|
||||
|
||||
fun recognizeText(image: ImageWrapper?): Array<String> {
|
||||
image?.takeUnless { image.isRecycled } ?: return emptyArray()
|
||||
initIfNeeded()
|
||||
val words = detect(image).sorted()
|
||||
val output = mutableListOf<String>()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Toast, ScriptRuntime> 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<Toast, ScriptRuntime> 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<Toast, ScriptRuntime> 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<Toast, ScriptRuntime> 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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Toast, ScriptRuntime>()
|
||||
|
||||
@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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Field> = 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<Field> = 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<Point>? = barcode.cornerPoints
|
||||
|
||||
}
|
||||
@@ -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<String>): 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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<String, Integer> EXECUTION_MODES = new MapBuilder<String, Integer>()
|
||||
.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;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.Vector
|
||||
*/
|
||||
object ThemeColorManager {
|
||||
|
||||
@JvmStatic
|
||||
@JvmField
|
||||
var defaultThemeColor = ThemeColor(ColorUtils.fromResources(R.color.theme_color_default))
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
46
app/src/main/java/org/autojs/autojs/tool/UiHandler.kt
Normal file
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -85,7 +85,7 @@ public class FileChooserDialogBuilder extends MaterialDialog.Builder {
|
||||
}
|
||||
|
||||
public FileChooserDialogBuilder justScriptFile() {
|
||||
mFileFilter = Scripts.getFILE_FILTER();
|
||||
mFileFilter = Scripts.FILE_FILTER;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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<LinearLayout?>(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<LinearLayout?>(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<LinearLayout?>(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()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -141,7 +141,7 @@ class WorkingDirectoryPreference : MaterialPreference {
|
||||
transfer(mPrefFullPath, inputPath)
|
||||
}
|
||||
WorkingDirectoryUtils.path = inputPath
|
||||
MainActivity.setShouldRecreateMainActivity(true)
|
||||
MainActivity.shouldRecreateMainActivity = true
|
||||
}
|
||||
dialog.dismiss()
|
||||
onFinish()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
52
app/src/main/java/org/autojs/autojs/util/ShortcutUtils.kt
Normal file
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<String, Ns> 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<String, Ns> 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;
|
||||
|
||||
BIN
app/src/main/res/drawable-xhdpi/ic_file_type_js_dark_green.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
app/src/main/res/drawable/ic_app_shortcut_docs_black.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/main/res/drawable/ic_app_shortcut_docs_green.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
app/src/main/res/drawable/ic_app_shortcut_docs_white.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/main/res/drawable/ic_app_shortcut_log_black.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/drawable/ic_app_shortcut_log_green.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
app/src/main/res/drawable/ic_app_shortcut_log_white.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/res/drawable/ic_app_shortcut_settings_black.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
app/src/main/res/drawable/ic_app_shortcut_settings_green.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
app/src/main/res/drawable/ic_app_shortcut_settings_white.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
@@ -6,7 +6,7 @@
|
||||
android:viewportWidth="128">
|
||||
|
||||
<path
|
||||
android:fillColor="#46483E"
|
||||
android:fillColor="#DE46483E"
|
||||
android:pathData="M64,14c-27.6,0-50,22.4-50,50s22.4,50,50,50s50-22.4,50-50S91.6,14,64,14z"/>
|
||||
<path
|
||||
android:fillColor="#81CF08"
|
||||
|
||||
BIN
app/src/main/res/drawable/transparent.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
@@ -25,7 +25,6 @@
|
||||
<org.autojs.autojs.ui.explorer.ExplorerView
|
||||
android:id="@+id/script_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#fafafa" />
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||