diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index 12b1af80..711d92e1 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -23,6 +23,8 @@ "UiObject#isShifted 方法, 用于检测控件位置变化", "crash 全局方法, 用于测试崩溃报告页面", "structuredClone 全局方法, 用于深拷贝 JavaScript 对象 (参阅 [MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/structuredClone))", + "等价系列选择器 (UiSelector#id/text/...) 及包含系列选择器 (UiSelector#xxxContains) 支持正则表达式参数", + "选择器的正则表达式参数支持使用标志 (i, m, s, u)", "设置页面增加 \"Java 原始类型包装\" 设置选项 _[`issue #435`](http://issues.autojs6.com/435)_", "设置页面增加 \"定时任务调度引擎\" 设置选项, 支持 AlarmManager/WorkManager/JobScheduler _[`issue #457`](http://issues.autojs6.com/457)_ _[`issue #388`](http://issues.autojs6.com/388)_ _[`issue #163`](http://issues.autojs6.com/163)_ _[`issue #53`](http://issues.autojs6.com/53)_ _[`issue #21`](http://issues.autojs6.com/21)_", "设置页面增加 \"应用启动器图标\" 设置选项, 支持自适应图标/透明背景图标 _[`issue #405`](http://issues.autojs6.com/405)_", diff --git a/app/src/main/java/org/autojs/autojs/core/accessibility/UiSelector.kt b/app/src/main/java/org/autojs/autojs/core/accessibility/UiSelector.kt index 086e7127..de6b64dd 100644 --- a/app/src/main/java/org/autojs/autojs/core/accessibility/UiSelector.kt +++ b/app/src/main/java/org/autojs/autojs/core/accessibility/UiSelector.kt @@ -48,7 +48,6 @@ import org.autojs.autojs.runtime.exception.ScriptInterruptedException import org.autojs.autojs.util.App import org.autojs.autojs.util.RhinoUtils import org.autojs.autojs.util.RhinoUtils.isMainThread -import org.autojs.autojs.util.StringUtils.convertRegex import org.autojs.autojs.util.StringUtils.str import org.autojs.autojs6.R import org.mozilla.javascript.BaseFunction @@ -83,7 +82,10 @@ open class UiSelector : UiObjectActions, StringReadable { } @ScriptInterface - fun id(str: String) = also { addFilter(IdFilter.equals(str)) } + fun id(s: String) = also { addFilter(IdFilter.equals(s)) } + + @ScriptInterface + fun id(regex: NativeRegExp) = also { addFilter(IdFilter.equals(regex)) } @ScriptInterface fun idStartsWith(prefix: String) = also { addFilter(IdFilter.startsWith(prefix)) } @@ -92,28 +94,34 @@ open class UiSelector : UiObjectActions, StringReadable { fun idEndsWith(suffix: String) = also { addFilter(IdFilter.endsWith(suffix)) } @ScriptInterface - fun idContains(str: String) = also { addFilter(IdFilter.contains(str)) } + fun idContains(s: String) = also { addFilter(IdFilter.contains(s)) } @ScriptInterface - @Deprecated("Deprecated in Java", ReplaceWith("idMatch(regex)")) - fun idMatches(regex: String) = also { addFilter(IdFilter.matches(convertRegex(regex))) } + fun idContains(regex: NativeRegExp) = also { addFilter(IdFilter.contains(regex)) } + + @ScriptInterface + @Deprecated("Deprecated in Java", ReplaceWith("idMatch(s)")) + fun idMatches(s: String) = also { addFilter(IdFilter.matches(s)) } @ScriptInterface @Suppress("DEPRECATION") @Deprecated("Deprecated in Java", ReplaceWith("idMatch(regex)")) - fun idMatches(regex: NativeRegExp) = idMatches(regex.toString()) + fun idMatches(regex: NativeRegExp) = also { addFilter(IdFilter.matches(regex)) } @ScriptInterface - fun idMatch(regex: String) = also { addFilter(IdFilter.match(regex)) } + fun idMatch(s: String) = also { addFilter(IdFilter.match(s)) } @ScriptInterface - fun idMatch(regex: NativeRegExp) = idMatch(convertRegex(regex.toString())) + fun idMatch(regex: NativeRegExp) = also { addFilter(IdFilter.match(regex)) } @ScriptInterface fun idHex(str: String) = also { addFilter(IdHexFilter.equals(str)) } @ScriptInterface - fun text(str: String) = also { addFilter(TextFilter.equals(str)) } + fun text(s: String) = also { addFilter(TextFilter.equals(s)) } + + @ScriptInterface + fun text(regex: NativeRegExp) = also { addFilter(TextFilter.equals(regex)) } @ScriptInterface fun textStartsWith(prefix: String) = also { addFilter(TextFilter.startsWith(prefix)) } @@ -122,25 +130,31 @@ open class UiSelector : UiObjectActions, StringReadable { fun textEndsWith(suffix: String) = also { addFilter(TextFilter.endsWith(suffix)) } @ScriptInterface - fun textContains(str: String) = also { addFilter(TextFilter.contains(str)) } + fun textContains(s: String) = also { addFilter(TextFilter.contains(s)) } @ScriptInterface - @Deprecated("Deprecated in Java", ReplaceWith("textMatch(regex)")) - fun textMatches(regex: String) = also { addFilter(TextFilter.matches(convertRegex(regex))) } + fun textContains(regex: NativeRegExp) = also { addFilter(TextFilter.contains(regex)) } + + @ScriptInterface + @Deprecated("Deprecated in Java", ReplaceWith("textMatch(s)")) + fun textMatches(s: String) = also { addFilter(TextFilter.matches(s)) } @ScriptInterface @Suppress("DEPRECATION") @Deprecated("Deprecated in Java", ReplaceWith("textMatch(regex)")) - fun textMatches(regex: NativeRegExp) = textMatches(regex.toString()) + fun textMatches(regex: NativeRegExp) = also { addFilter(TextFilter.matches(regex)) } @ScriptInterface - fun textMatch(regex: String) = also { addFilter(TextFilter.match(regex)) } + fun textMatch(s: String) = also { addFilter(TextFilter.match(s)) } @ScriptInterface - fun textMatch(regex: NativeRegExp) = textMatch(convertRegex(regex.toString())) + fun textMatch(regex: NativeRegExp) = also { addFilter(TextFilter.match(regex)) } @ScriptInterface - fun desc(str: String) = also { addFilter(DescFilter.equals(str)) } + fun desc(s: String) = also { addFilter(DescFilter.equals(s)) } + + @ScriptInterface + fun desc(regex: NativeRegExp) = also { addFilter(DescFilter.equals(regex)) } @ScriptInterface fun descStartsWith(prefix: String) = also { addFilter(DescFilter.startsWith(prefix)) } @@ -149,25 +163,31 @@ open class UiSelector : UiObjectActions, StringReadable { fun descEndsWith(suffix: String) = also { addFilter(DescFilter.endsWith(suffix)) } @ScriptInterface - fun descContains(str: String) = also { addFilter(DescFilter.contains(str)) } + fun descContains(s: String) = also { addFilter(DescFilter.contains(s)) } + + @ScriptInterface + fun descContains(regex: NativeRegExp) = also { addFilter(DescFilter.contains(regex)) } @ScriptInterface - @Deprecated("Deprecated in Java", ReplaceWith("descMatch(regex)")) - fun descMatches(regex: String) = also { addFilter(DescFilter.matches(convertRegex(regex))) } + @Deprecated("Deprecated in Java", ReplaceWith("descMatch(s)")) + fun descMatches(s: String) = also { addFilter(DescFilter.matches(s)) } @ScriptInterface @Suppress("DEPRECATION") @Deprecated("Deprecated in Java", ReplaceWith("descMatch(regex)")) - fun descMatches(regex: NativeRegExp) = descMatches(regex.toString()) + fun descMatches(regex: NativeRegExp) = also { addFilter(DescFilter.matches(regex)) } @ScriptInterface - fun descMatch(regex: String) = also { addFilter(DescFilter.match(regex)) } + fun descMatch(s: String) = also { addFilter(DescFilter.match(s)) } @ScriptInterface - fun descMatch(regex: NativeRegExp) = descMatch(convertRegex(regex.toString())) + fun descMatch(regex: NativeRegExp) = also { addFilter(DescFilter.match(regex)) } @ScriptInterface - fun content(str: String) = also { addFilter(ContentFilter.equals(str)) } + fun content(s: String) = also { addFilter(ContentFilter.equals(s)) } + + @ScriptInterface + fun content(regex: NativeRegExp) = also { addFilter(ContentFilter.equals(regex)) } @ScriptInterface fun contentStartsWith(prefix: String) = also { addFilter(ContentFilter.startsWith(prefix)) } @@ -176,25 +196,31 @@ open class UiSelector : UiObjectActions, StringReadable { fun contentEndsWith(suffix: String) = also { addFilter(ContentFilter.endsWith(suffix)) } @ScriptInterface - fun contentContains(str: String) = also { addFilter(ContentFilter.contains(str)) } + fun contentContains(s: String) = also { addFilter(ContentFilter.contains(s)) } + + @ScriptInterface + fun contentContains(regex: NativeRegExp) = also { addFilter(ContentFilter.contains(regex)) } @ScriptInterface - @Deprecated("Deprecated in Java", ReplaceWith("contentMatch(regex)")) - fun contentMatches(regex: String) = also { addFilter(ContentFilter.matches(convertRegex(regex))) } + @Deprecated("Deprecated in Java", ReplaceWith("contentMatch(s)")) + fun contentMatches(s: String) = also { addFilter(ContentFilter.matches(s)) } @ScriptInterface @Suppress("DEPRECATION") @Deprecated("Deprecated in Java", ReplaceWith("contentMatch(regex)")) - fun contentMatches(regex: NativeRegExp) = contentMatches(regex.toString()) + fun contentMatches(regex: NativeRegExp) = also { addFilter(ContentFilter.matches(regex)) } @ScriptInterface - fun contentMatch(regex: String) = also { addFilter(ContentFilter.match(regex)) } + fun contentMatch(s: String) = also { addFilter(ContentFilter.match(s)) } @ScriptInterface - fun contentMatch(regex: NativeRegExp) = contentMatch(convertRegex(regex.toString())) + fun contentMatch(regex: NativeRegExp) = also { addFilter(ContentFilter.match(regex)) } @ScriptInterface - fun className(str: String) = also { addFilter(ClassNameFilter.equals(str)) } + fun className(s: String) = also { addFilter(ClassNameFilter.equals(s)) } + + @ScriptInterface + fun className(regex: NativeRegExp) = also { addFilter(ClassNameFilter.equals(regex)) } @ScriptInterface fun classNameStartsWith(prefix: String) = also { addFilter(ClassNameFilter.startsWith(prefix)) } @@ -203,25 +229,31 @@ open class UiSelector : UiObjectActions, StringReadable { fun classNameEndsWith(suffix: String) = also { addFilter(ClassNameFilter.endsWith(suffix)) } @ScriptInterface - fun classNameContains(str: String) = also { addFilter(ClassNameFilter.contains(str)) } + fun classNameContains(s: String) = also { addFilter(ClassNameFilter.contains(s)) } @ScriptInterface - @Deprecated("Deprecated in Java", ReplaceWith("classNameMatch(regex)")) - fun classNameMatches(regex: String) = also { addFilter(ClassNameFilter.matches(convertRegex(regex))) } + fun classNameContains(regex: NativeRegExp) = also { addFilter(ClassNameFilter.contains(regex)) } + + @ScriptInterface + @Deprecated("Deprecated in Java", ReplaceWith("classNameMatch(s)")) + fun classNameMatches(s: String) = also { addFilter(ClassNameFilter.matches(s)) } @ScriptInterface @Suppress("DEPRECATION") @Deprecated("Deprecated in Java", ReplaceWith("classNameMatch(regex)")) - fun classNameMatches(regex: NativeRegExp) = classNameMatches(regex.toString()) + fun classNameMatches(regex: NativeRegExp) = also { addFilter(ClassNameFilter.matches(regex)) } @ScriptInterface - fun classNameMatch(regex: String) = also { addFilter(ClassNameFilter.match(regex)) } + fun classNameMatch(s: String) = also { addFilter(ClassNameFilter.match(s)) } @ScriptInterface - fun classNameMatch(regex: NativeRegExp) = classNameMatch(convertRegex(regex.toString())) + fun classNameMatch(regex: NativeRegExp) = also { addFilter(ClassNameFilter.match(regex)) } @ScriptInterface - fun packageName(str: String) = also { addFilter(PackageNameFilter.equals(str)) } + fun packageName(s: String) = also { addFilter(PackageNameFilter.equals(s)) } + + @ScriptInterface + fun packageName(regex: NativeRegExp) = also { addFilter(PackageNameFilter.equals(regex)) } @ScriptInterface fun packageName(app: App) = also { addFilter(PackageNameFilter.equals(app.packageName)) } @@ -233,22 +265,25 @@ open class UiSelector : UiObjectActions, StringReadable { fun packageNameEndsWith(suffix: String) = also { addFilter(PackageNameFilter.endsWith(suffix)) } @ScriptInterface - fun packageNameContains(str: String) = also { addFilter(PackageNameFilter.contains(str)) } + fun packageNameContains(s: String) = also { addFilter(PackageNameFilter.contains(s)) } + + @ScriptInterface + fun packageNameContains(regex: NativeRegExp) = also { addFilter(PackageNameFilter.contains(regex)) } @ScriptInterface - @Deprecated("Deprecated in Java", ReplaceWith("packageNameMatch(regex)")) - fun packageNameMatches(regex: String) = also { addFilter(PackageNameFilter.matches(convertRegex(regex))) } + @Deprecated("Deprecated in Java", ReplaceWith("packageNameMatch(s)")) + fun packageNameMatches(s: String) = also { addFilter(PackageNameFilter.matches(s)) } @ScriptInterface @Suppress("DEPRECATION") @Deprecated("Deprecated in Java", ReplaceWith("packageNameMatch(regex)")) - fun packageNameMatches(regex: NativeRegExp) = packageNameMatches(regex.toString()) + fun packageNameMatches(regex: NativeRegExp) = also { addFilter(PackageNameFilter.matches(regex)) } @ScriptInterface - fun packageNameMatch(regex: String) = also { addFilter(PackageNameFilter.match(regex)) } + fun packageNameMatch(s: String) = also { addFilter(PackageNameFilter.match(s)) } @ScriptInterface - fun packageNameMatch(regex: NativeRegExp) = packageNameMatch(convertRegex(regex.toString())) + fun packageNameMatch(regex: NativeRegExp) = also { addFilter(PackageNameFilter.match(regex)) } @ScriptInterface fun currentApp(app: App) = also { addFilter(AppFilter(app)) } @@ -1019,7 +1054,7 @@ open class UiSelector : UiObjectActions, StringReadable { .invoke(tmp) is String -> tmp::class.java .getMethod(key, cString) - .invoke(tmp, value.toString()) + .invoke(tmp, value) is NativeRegExp -> tmp::class.java .getMethod(key, cNativeRegExp) .invoke(tmp, value) diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/ClassNameFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/ClassNameFilter.kt index 5748e622..eb5890c8 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/ClassNameFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/ClassNameFilter.kt @@ -1,10 +1,11 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by Stardust on Mar 9, 2017. - * Modified by SuperMonster003 as of Nov 19, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ object ClassNameFilter { @@ -59,7 +60,11 @@ object ClassNameFilter { else -> extendedClassNameMap[text] ?: "android.widget.$text" }.let { StringEqualsFilter(it, CLASS_NAME_GETTER) } - fun contains(str: String) = StringContainsFilter(str, CLASS_NAME_GETTER) + @Suppress("CovariantEquals") + fun equals(regex: NativeRegExp) = StringEqualsFilter(regex, CLASS_NAME_GETTER) + + fun contains(s: String) = StringContainsFilter(s, CLASS_NAME_GETTER) + fun contains(regex: NativeRegExp) = StringContainsFilter(regex, CLASS_NAME_GETTER) fun startsWith(prefix: String) = when (prefix.contains(".")) { true -> prefix @@ -68,8 +73,10 @@ object ClassNameFilter { fun endsWith(suffix: String) = StringEndsWithFilter(suffix, CLASS_NAME_GETTER) - fun matches(regex: String) = StringMatchesFilter(regex, CLASS_NAME_GETTER) + fun matches(s: String) = StringMatchesFilter(s, CLASS_NAME_GETTER) + fun matches(regex: NativeRegExp) = StringMatchesFilter(regex, CLASS_NAME_GETTER) - fun match(regex: String) = StringMatchFilter(regex, CLASS_NAME_GETTER) + fun match(s: String) = StringMatchFilter(s, CLASS_NAME_GETTER) + fun match(regex: NativeRegExp) = StringMatchFilter(regex, CLASS_NAME_GETTER) } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/ContentFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/ContentFilter.kt index 940ae9e1..648eb75a 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/ContentFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/ContentFilter.kt @@ -1,9 +1,11 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by SuperMonster003 on Jun 10, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ object ContentFilter { @@ -15,16 +17,23 @@ object ContentFilter { } - fun equals(text: String) = StringListEqualsFilter(text, CONTENT_GETTER) + @Suppress("CovariantEquals") + fun equals(s: String) = StringListEqualsFilter(s, CONTENT_GETTER) - fun contains(str: String) = StringListContainsFilter(str, CONTENT_GETTER) + @Suppress("CovariantEquals") + fun equals(regex: NativeRegExp) = StringListEqualsFilter(regex, CONTENT_GETTER) + + fun contains(s: String) = StringListContainsFilter(s, CONTENT_GETTER) + fun contains(regex: NativeRegExp) = StringListContainsFilter(regex, CONTENT_GETTER) fun startsWith(prefix: String) = StringListStartsWithFilter(prefix, CONTENT_GETTER) fun endsWith(suffix: String) = StringListEndsWithFilter(suffix, CONTENT_GETTER) - fun matches(regex: String) = StringListMatchesFilter(regex, CONTENT_GETTER) + fun matches(s: String) = StringListMatchesFilter(s, CONTENT_GETTER) + fun matches(regex: NativeRegExp) = StringListMatchesFilter(regex, CONTENT_GETTER) - fun match(regex: String) = StringListMatchFilter(regex, CONTENT_GETTER) + fun match(s: String) = StringListMatchFilter(s, CONTENT_GETTER) + fun match(regex: NativeRegExp) = StringListMatchFilter(regex, CONTENT_GETTER) } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/DescFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/DescFilter.kt index 758a0345..5983b2ad 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/DescFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/DescFilter.kt @@ -1,10 +1,11 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by Stardust on Mar 9, 2017. - * Modified by SuperMonster003 as of Nov 19, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ object DescFilter { @@ -16,16 +17,23 @@ object DescFilter { } - fun equals(text: String) = StringEqualsFilter(text, DESC_GETTER) + @Suppress("CovariantEquals") + fun equals(s: String) = StringEqualsFilter(s, DESC_GETTER) - fun contains(str: String) = StringContainsFilter(str, DESC_GETTER) + @Suppress("CovariantEquals") + fun equals(regex: NativeRegExp) = StringEqualsFilter(regex, DESC_GETTER) + + fun contains(s: String) = StringContainsFilter(s, DESC_GETTER) + fun contains(regex: NativeRegExp) = StringContainsFilter(regex, DESC_GETTER) fun startsWith(prefix: String) = StringStartsWithFilter(prefix, DESC_GETTER) fun endsWith(suffix: String) = StringEndsWithFilter(suffix, DESC_GETTER) - fun matches(regex: String) = StringMatchesFilter(regex, DESC_GETTER) + fun matches(s: String) = StringMatchesFilter(s, DESC_GETTER) + fun matches(regex: NativeRegExp) = StringMatchesFilter(regex, DESC_GETTER) - fun match(regex: String) = StringMatchFilter(regex, DESC_GETTER) + fun match(s: String) = StringMatchFilter(s, DESC_GETTER) + fun match(regex: NativeRegExp) = StringMatchFilter(regex, DESC_GETTER) } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/IdFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/IdFilter.kt index fbc131bd..269619f0 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/IdFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/IdFilter.kt @@ -2,10 +2,11 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.accessibility.UiSelector.Companion.ID_IDENTIFIER import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by Stardust on Mar 9, 2017. - * Modified by SuperMonster003 as of Nov 19, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ object IdFilter { @@ -18,17 +19,27 @@ object IdFilter { } @Suppress("CovariantEquals") - fun equals(str: String) = when (str.contains(ID_IDENTIFIER)) { - true -> StringEqualsFilter(str, ID_GETTER) + fun equals(s: String) = when (s.contains(ID_IDENTIFIER)) { + true -> StringEqualsFilter(s, ID_GETTER) else -> object : Filter { override fun filter(node: UiObject) = node.id()?.let { id -> when (id.contains(ID_IDENTIFIER)) { - true -> id.split(ID_IDENTIFIER).last() == str - else -> id == str + true -> id.split(ID_IDENTIFIER).last() == s + else -> id == s } } ?: false - override fun toString() = "id(\"$str\")" + override fun toString() = "${ID_GETTER}(\"$s\")" + } + } + + @Suppress("CovariantEquals") + fun equals(regex: NativeRegExp): Filter { + return object : StringMatchesFilter(regex, ID_GETTER) { + override fun toString(): String { + val literal = JsRegexUtils.formatAsJsRegexLiteral(regex.toString()) + return "${ID_GETTER}($literal)" + } } } @@ -42,16 +53,19 @@ object IdFilter { } } ?: false - override fun toString() = "idStartsWith(\"$prefix\")" + override fun toString() = "${ID_GETTER}StartsWith(\"$prefix\")" } } fun endsWith(suffix: String) = StringEndsWithFilter(suffix, ID_GETTER) - fun contains(contains: String) = StringContainsFilter(contains, ID_GETTER) + fun contains(s: String) = StringContainsFilter(s, ID_GETTER) + fun contains(regex: NativeRegExp) = StringContainsFilter(regex, ID_GETTER) - fun matches(regex: String) = StringMatchesFilter(regex, ID_GETTER) + fun matches(s: String) = StringMatchesFilter(s, ID_GETTER) + fun matches(regex: NativeRegExp) = StringMatchesFilter(regex, ID_GETTER) - fun match(regex: String) = StringMatchFilter(regex, ID_GETTER) + fun match(s: String) = StringMatchFilter(s, ID_GETTER) + fun match(regex: NativeRegExp) = StringMatchFilter(regex, ID_GETTER) } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/JsRegexUtils.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/JsRegexUtils.kt new file mode 100644 index 00000000..fbbe41e9 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/JsRegexUtils.kt @@ -0,0 +1,74 @@ +package org.autojs.autojs.core.automator.filter + +import java.util.regex.Pattern + +internal object JsRegexUtils { + + // Compile JavaScript regex literal "/pattern/flags" or plain pattern string to Kotlin Regex. + // zh-CN: 将 JavaScript 正则字面量 "/pattern/flags" 或普通模式字符串编译为 Kotlin 的 Regex. + fun compileJsOrPlainRegex(input: String): Regex { + parseJsRegexLiteral(input)?.let { (pattern, flags) -> + val javaFlags = toJavaPatternFlags(flags) + return Pattern.compile(pattern, javaFlags).toRegex() + } + return input.toRegex() + } + + // Parse JavaScript regex literal by scanning delimiter '/' while respecting escapes and character classes. + // zh-CN: 通过扫描分隔符 '/' 解析 JavaScript 正则字面量, 同时处理转义与字符类. + fun parseJsRegexLiteral(input: String): Pair? { + if (input.length < 2 || input[0] != '/') return null + + var escaped = false + var inCharClass = false + + for (i in 1 until input.length) { + val ch = input[i] + when { + escaped -> escaped = false + ch == '\\' -> escaped = true + ch == '[' -> inCharClass = true + ch == ']' && inCharClass -> inCharClass = false + ch == '/' && !inCharClass -> { + val pattern = input.substring(1, i) + val flags = input.substring(i + 1) + return pattern to flags + } + } + } + return null + } + + // Map JavaScript flags to java.util.regex.Pattern flags. Unknown flags are ignored. + // zh-CN: 将 JavaScript flags 映射到 java.util.regex.Pattern flags, 未知 flags 将被忽略. + fun toJavaPatternFlags(flags: String): Int { + var f = 0 + if (flags.contains('i')) f = f or Pattern.CASE_INSENSITIVE + if (flags.contains('m')) f = f or Pattern.MULTILINE + if (flags.contains('s')) f = f or Pattern.DOTALL + + // Java "u" is not identical to JavaScript "u", but enabling Unicode-aware behavior is usually closer. + // zh-CN: Java 的 "u" 与 JavaScript 的 "u" 并不完全等价, 但开启 Unicode 相关行为通常更接近预期. + if (flags.contains('u')) { + f = f or Pattern.UNICODE_CASE + f = f or Pattern.UNICODE_CHARACTER_CLASS + } + + // JavaScript "g/y" affects iteration/sticky behavior rather than "does it match", so it is ignored here. + // zh-CN: JavaScript 的 "g/y" 影响的是迭代/粘连行为, 而不是 "是否匹配", 因此这里忽略. + + return f + } + + // Format input regex as a JavaScript regex literal string for debugging display. + // zh-CN: 将输入正则格式化为 JavaScript 正则字面量字符串, 用于调试展示. + fun formatAsJsRegexLiteral(input: String): String { + val (pattern, flags) = parseJsRegexLiteral(input) ?: (input to "") + val safePattern = when (pattern.isEmpty()) { + true -> "(?:)" + else -> pattern.toRegex().toString().replace("/", "\\/") + } + return "/$safePattern/$flags" + } + +} diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/PackageNameFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/PackageNameFilter.kt index 102550e2..916bddce 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/PackageNameFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/PackageNameFilter.kt @@ -1,10 +1,11 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by Stardust on Mar 9, 2017. - * Modified by SuperMonster003 as of Nov 19, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ object PackageNameFilter { @@ -16,16 +17,23 @@ object PackageNameFilter { } - fun equals(text: String) = StringEqualsFilter(text, PACKAGE_NAME_GETTER) + @Suppress("CovariantEquals") + fun equals(s: String) = StringEqualsFilter(s, PACKAGE_NAME_GETTER) - fun contains(str: String) = StringContainsFilter(str, PACKAGE_NAME_GETTER) + @Suppress("CovariantEquals") + fun equals(regex: NativeRegExp) = StringEqualsFilter(regex, PACKAGE_NAME_GETTER) + + fun contains(s: String) = StringContainsFilter(s, PACKAGE_NAME_GETTER) + fun contains(regex: NativeRegExp) = StringContainsFilter(regex, PACKAGE_NAME_GETTER) fun startsWith(prefix: String) = StringStartsWithFilter(prefix, PACKAGE_NAME_GETTER) fun endsWith(suffix: String) = StringEndsWithFilter(suffix, PACKAGE_NAME_GETTER) - fun matches(regex: String) = StringMatchesFilter(regex, PACKAGE_NAME_GETTER) + fun matches(s: String) = StringMatchesFilter(s, PACKAGE_NAME_GETTER) + fun matches(regex: NativeRegExp) = StringMatchesFilter(regex, PACKAGE_NAME_GETTER) - fun match(regex: String) = StringMatchFilter(regex, PACKAGE_NAME_GETTER) + fun match(s: String) = StringMatchFilter(s, PACKAGE_NAME_GETTER) + fun match(regex: NativeRegExp) = StringMatchFilter(regex, PACKAGE_NAME_GETTER) } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/RegexFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/RegexFilter.kt new file mode 100644 index 00000000..b6b1916b --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/RegexFilter.kt @@ -0,0 +1,35 @@ +package org.autojs.autojs.core.automator.filter + +import org.autojs.autojs.util.StringUtils.uppercaseFirstChar +import org.mozilla.javascript.regexp.NativeRegExp + +/** + * Created by SuperMonster003 on Dec 27, 2025. + */ +abstract class RegexFilter(s: String, keyGetter: KeyGetter) : Filter { + + open val actionName: String = "" + + protected val input = s + protected val keyGetter = keyGetter + + protected var isRegexSource = false + private set + + // Compile regex only once to avoid repeated compilation during tree traversal. + // zh-CN: 仅编译一次正则, 避免在遍历节点树时重复编译带来的开销. + protected val compiledRegex by lazy(LazyThreadSafetyMode.NONE) { JsRegexUtils.compileJsOrPlainRegex(input) } + + constructor(regex: NativeRegExp, keyGetter: KeyGetter) : this(regex.toString(), keyGetter) { + isRegexSource = true + } + + override fun toString(): String { + val literal = when { + isRegexSource -> JsRegexUtils.formatAsJsRegexLiteral(input) + else -> "\"$input\"" + } + return "${keyGetter}${actionName.uppercaseFirstChar()}($literal)" + } + +} diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/RegexListFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/RegexListFilter.kt new file mode 100644 index 00000000..b112eb1f --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/RegexListFilter.kt @@ -0,0 +1,35 @@ +package org.autojs.autojs.core.automator.filter + +import org.autojs.autojs.util.StringUtils.uppercaseFirstChar +import org.mozilla.javascript.regexp.NativeRegExp + +/** + * Created by SuperMonster003 on Dec 27, 2025. + */ +abstract class RegexListFilter(s: String, keysGetter: KeysGetter) : Filter { + + open val actionName: String = "" + + protected val input = s + protected val keysGetter = keysGetter + + protected var isRegexSource = false + private set + + // Compile regex only once to avoid repeated compilation during tree traversal. + // zh-CN: 仅编译一次正则, 避免在遍历节点树时重复编译带来的开销. + protected val compiledRegex by lazy(LazyThreadSafetyMode.NONE) { JsRegexUtils.compileJsOrPlainRegex(input) } + + constructor(regex: NativeRegExp, keysGetter: KeysGetter) : this(regex.toString(), keysGetter) { + isRegexSource = true + } + + override fun toString(): String { + val literal = when { + isRegexSource -> JsRegexUtils.formatAsJsRegexLiteral(input) + else -> "\"$input\"" + } + return "${keysGetter}${actionName.uppercaseFirstChar()}($literal)" + } + +} diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringContainsFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringContainsFilter.kt index 546b2ecd..d52017f7 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringContainsFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringContainsFilter.kt @@ -1,15 +1,19 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by Stardust on Mar 9, 2017. - * Modified by SuperMonster003 as of Nov 19, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ -class StringContainsFilter internal constructor(private val mContains: String, private val mKeyGetter: KeyGetter) : Filter { +class StringContainsFilter : RegexFilter { - override fun filter(node: UiObject) = mKeyGetter.getKey(node)?.contains(mContains) ?: false + override val actionName = "contains" - override fun toString() = "${mKeyGetter}Contains(\"$mContains\")" + constructor(s: String, keyGetter: KeyGetter) : super(s, keyGetter) + constructor(regex: NativeRegExp, keyGetter: KeyGetter) : super(regex, keyGetter) + + override fun filter(node: UiObject) = keyGetter.getKey(node)?.contains(compiledRegex) == true } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringEqualsFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringEqualsFilter.kt index 016ba1db..188f5d26 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringEqualsFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringEqualsFilter.kt @@ -1,15 +1,20 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by Stardust on Mar 9, 2017. - * Modified by SuperMonster003 as of Nov 19, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ -class StringEqualsFilter(private val mValue: String, private val mKeyGetter: KeyGetter) : Filter { +class StringEqualsFilter : RegexFilter { - override fun filter(node: UiObject) = mKeyGetter.getKey(node)?.let { it == mValue } ?: false + constructor(s: String, keyGetter: KeyGetter) : super(s, keyGetter) + constructor(regex: NativeRegExp, keyGetter: KeyGetter) : super(regex, keyGetter) - override fun toString() = "$mKeyGetter(\"$mValue\")" + override fun filter(node: UiObject) = when { + isRegexSource -> keyGetter.getKey(node)?.matches(compiledRegex) == true + else -> keyGetter.getKey(node)?.contentEquals(input) == true + } } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListContainsFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListContainsFilter.kt index 7f01521c..51d9f521 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListContainsFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListContainsFilter.kt @@ -1,14 +1,21 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by SuperMonster003 on Jun 10, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ -class StringListContainsFilter internal constructor(private val mContains: String, private val mKeysGetter: KeysGetter) : Filter { +class StringListContainsFilter : RegexListFilter { - override fun filter(node: UiObject) = mKeysGetter.getKeys(node).any { it?.contains(mContains) ?: false } + override val actionName = "contains" - override fun toString() = "${mKeysGetter}Contains(\"$mContains\")" + constructor(s: String, keysGetter: KeysGetter) : super(s, keysGetter) + constructor(regex: NativeRegExp, keysGetter: KeysGetter) : super(regex, keysGetter) + + override fun filter(node: UiObject) = keysGetter.getKeys(node).any { + it?.contains(compiledRegex) == true + } } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListEqualsFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListEqualsFilter.kt index cdacfa8b..04b730eb 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListEqualsFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListEqualsFilter.kt @@ -1,14 +1,23 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by SuperMonster003 on Jun 10, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ -class StringListEqualsFilter(private val mValue: String, private val mKeysGetter: KeysGetter) : Filter { +class StringListEqualsFilter : RegexListFilter { - override fun filter(node: UiObject) = mKeysGetter.getKeys(node).any { it.contentEquals(mValue) } - - override fun toString() = "$mKeysGetter(\"$mValue\")" + constructor(s: String, keysGetter: KeysGetter) : super(s, keysGetter) + constructor(regex: NativeRegExp, keysGetter: KeysGetter) : super(regex, keysGetter) + override fun filter(node: UiObject) = when { + isRegexSource -> keysGetter.getKeys(node).any { + it?.matches(compiledRegex) == true + } + else -> keysGetter.getKeys(node).any { + it?.contentEquals(input) == true + } + } } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListMatchFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListMatchFilter.kt index b988b7b8..b03e621b 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListMatchFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListMatchFilter.kt @@ -1,36 +1,21 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by SuperMonster003 on Oct 17, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ -class StringListMatchFilter internal constructor(private val mRegex: String, private val mKeysGetter: KeysGetter) : Filter { +class StringListMatchFilter : RegexListFilter { - // @Hint by SuperMonster003 on Oct 17, 2022. - // ! Similar to JavaScript "String.prototype.match" - // ! which returns the result of matching a string against a regular expression. - // ! https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match - // ! https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-regex/contains-match-in.html - // ! https://stackoverflow.com/questions/21883629/difference-in-results-between-java-matches-vs-javascript-match - // ! zh-CN: - // ! 与 JavaScript 的方法 "String.prototype.match" 类似, - // ! 它返回字符串与正则表达式匹配的结果. - // ! 参考链接见上. - override fun filter(node: UiObject) = mKeysGetter.getKeys(node).any { - it ?: return@any false - val prefix = "/" - val suffix = "/i" - if (mRegex.startsWith(prefix) && mRegex.endsWith(suffix)) { - mRegex - .slice(prefix.length until mRegex.length - suffix.length) - .toRegex(RegexOption.IGNORE_CASE) - .containsMatchIn(it) - } else { - mRegex.toRegex().containsMatchIn(it) - } + override val actionName = "match" + + constructor(s: String, keysGetter: KeysGetter) : super(s, keysGetter) + constructor(regex: NativeRegExp, keysGetter: KeysGetter) : super(regex, keysGetter) + + override fun filter(node: UiObject) = keysGetter.getKeys(node).any { + it?.contains(compiledRegex) == true } - override fun toString() = "${mKeysGetter}Match(\"$mRegex\")" - } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListMatchesFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListMatchesFilter.kt index 7685a826..f1384c87 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListMatchesFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringListMatchesFilter.kt @@ -1,24 +1,21 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by SuperMonster003 on Jun 10, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ -class StringListMatchesFilter internal constructor(private val mRegex: String, private val mKeysGetter: KeysGetter) : Filter { +class StringListMatchesFilter : RegexListFilter { - // @Hint by SuperMonster003 on Oct 17, 2022. - // ! Kotlin method "CharSequence.matches(regex: Regex): Boolean" - // ! indicates whether the regular expression matches the ENTIRE input (not partial input). - // ! https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/matches.html - // ! https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-regex/matches.html - // ! https://stackoverflow.com/questions/21883629/difference-in-results-between-java-matches-vs-javascript-match - // ! zh-CN: - // ! Kotlin 的方法 "CharSequence.matches(regex: Regex): Boolean" - // ! 表示正则表达式是否完全匹配输入 (注意是完全而非部分匹配). - // ! 参考链接见上. - override fun filter(node: UiObject) = mKeysGetter.getKeys(node).any { it?.matches(mRegex.toRegex()) ?: false } + override val actionName = "matches" - override fun toString() = "${mKeysGetter}Matches(\"$mRegex\")" + constructor(s: String, keysGetter: KeysGetter) : super(s, keysGetter) + constructor(regex: NativeRegExp, keysGetter: KeysGetter) : super(regex, keysGetter) + + override fun filter(node: UiObject) = keysGetter.getKeys(node).any { + it?.matches(compiledRegex) == true + } } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringMatchFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringMatchFilter.kt index bc305f3a..20b6a08d 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringMatchFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringMatchFilter.kt @@ -1,31 +1,19 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by Stardust on Mar 9, 2017. - * Modified by SuperMonster003 as of Nov 19, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ -class StringMatchFilter internal constructor(private val mRegex: String, private val mKeyGetter: KeyGetter) : Filter { +class StringMatchFilter : RegexFilter { - // @Hint by SuperMonster003 on Oct 17, 2022. - // ! Similar to JavaScript "String.prototype.match" - // ! which returns the result of matching a string against a regular expression. - // ! https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match - // ! https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-regex/contains-match-in.html - // ! https://stackoverflow.com/questions/21883629/difference-in-results-between-java-matches-vs-javascript-match - // ! zh-CN: - // ! 与 JavaScript 的方法 "String.prototype.match" 类似, - // ! 它返回字符串与正则表达式匹配的结果. - // ! 参考链接见上. - override fun filter(node: UiObject) = mKeyGetter.getKey(node)?.contains(mRegex.toRegex()) ?: false + override val actionName = "match" - override fun toString(): String { - val regexStr = when (mRegex.isEmpty()) { - true -> "(?:)" - else -> mRegex.toRegex().toString().replace("/", "\\/") - } - return "${mKeyGetter}Match(/$regexStr/)" - } + constructor(s: String, keyGetter: KeyGetter) : super(s, keyGetter) + constructor(regex: NativeRegExp, keyGetter: KeyGetter) : super(regex, keyGetter) + + override fun filter(node: UiObject) = keyGetter.getKey(node)?.contains(compiledRegex) == true } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringMatchesFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringMatchesFilter.kt index 01db4ae9..960dc997 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/StringMatchesFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/StringMatchesFilter.kt @@ -1,30 +1,19 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by Stardust on Mar 9, 2017. + * Modified by SuperMonster003 as of Dec 27, 2025. */ -class StringMatchesFilter internal constructor(private val mRegex: String, private val mKeyGetter: KeyGetter) : Filter { +open class StringMatchesFilter : RegexFilter { - // @Hint by SuperMonster003 on Oct 17, 2022. - // ! Kotlin method "CharSequence.matches(regex: Regex): Boolean" - // ! indicates whether the regular expression matches the ENTIRE input (not partial input). - // ! https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/matches.html - // ! https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-regex/matches.html - // ! https://stackoverflow.com/questions/21883629/difference-in-results-between-java-matches-vs-javascript-match - // ! zh-CN: - // ! Kotlin 的方法 "CharSequence.matches(regex: Regex): Boolean" - // ! 表示正则表达式是否完全匹配输入 (注意是完全而非部分匹配). - // ! 参考链接见上. - override fun filter(node: UiObject) = mKeyGetter.getKey(node)?.matches(mRegex.toRegex()) ?: false + override val actionName = "matches" - override fun toString(): String { - val regexStr = when (mRegex.isEmpty()) { - true -> "(?:)" - else -> mRegex.toRegex().toString().replace("/", "\\/") - } - return "${mKeyGetter}Matches(/$regexStr/)" - } + constructor(s: String, keyGetter: KeyGetter) : super(s, keyGetter) + constructor(regex: NativeRegExp, keyGetter: KeyGetter) : super(regex, keyGetter) + + override fun filter(node: UiObject) = keyGetter.getKey(node)?.matches(compiledRegex) == true } diff --git a/app/src/main/java/org/autojs/autojs/core/automator/filter/TextFilter.kt b/app/src/main/java/org/autojs/autojs/core/automator/filter/TextFilter.kt index 9c0f6d45..7e8a6746 100644 --- a/app/src/main/java/org/autojs/autojs/core/automator/filter/TextFilter.kt +++ b/app/src/main/java/org/autojs/autojs/core/automator/filter/TextFilter.kt @@ -1,10 +1,11 @@ package org.autojs.autojs.core.automator.filter import org.autojs.autojs.core.automator.UiObject +import org.mozilla.javascript.regexp.NativeRegExp /** * Created by Stardust on Mar 9, 2017. - * Modified by SuperMonster003 as of Nov 19, 2022. + * Modified by SuperMonster003 as of Dec 27, 2025. */ object TextFilter { @@ -16,16 +17,23 @@ object TextFilter { } - fun equals(text: String) = StringEqualsFilter(text, TEXT_GETTER) + @Suppress("CovariantEquals") + fun equals(s: String) = StringEqualsFilter(s, TEXT_GETTER) - fun contains(str: String) = StringContainsFilter(str, TEXT_GETTER) + @Suppress("CovariantEquals") + fun equals(regex: NativeRegExp) = StringEqualsFilter(regex, TEXT_GETTER) + + fun contains(s: String) = StringContainsFilter(s, TEXT_GETTER) + fun contains(regex: NativeRegExp) = StringContainsFilter(regex, TEXT_GETTER) fun startsWith(prefix: String) = StringStartsWithFilter(prefix, TEXT_GETTER) fun endsWith(suffix: String) = StringEndsWithFilter(suffix, TEXT_GETTER) - fun matches(regex: String) = StringMatchesFilter(regex, TEXT_GETTER) + fun matches(s: String) = StringMatchesFilter(s, TEXT_GETTER) + fun matches(regex: NativeRegExp) = StringMatchesFilter(regex, TEXT_GETTER) - fun match(regex: String) = StringMatchFilter(regex, TEXT_GETTER) + fun match(s: String) = StringMatchFilter(s, TEXT_GETTER) + fun match(regex: NativeRegExp) = StringMatchFilter(regex, TEXT_GETTER) } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/Augmentable.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/Augmentable.kt index 6841ca49..111b4dc9 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/Augmentable.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/Augmentable.kt @@ -66,7 +66,7 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : F open val key: String get() = when { mIsOriginalKeyName -> javaClass.simpleName - else -> lowercaseFirstChar(javaClass.simpleName) + else -> javaClass.simpleName.lowercaseFirstChar() } /** diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/AugmentableProxy.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/AugmentableProxy.kt index d1167d89..7633ad75 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/AugmentableProxy.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/AugmentableProxy.kt @@ -30,11 +30,11 @@ open class AugmentableProxy(private val scriptRuntime: ScriptRuntime) : Augmenta val setterResult = listOf( when { Regex("^set[A-Z].*").containsMatchIn(key) -> key - else -> "set${uppercaseFirstChar(key)}" + else -> "set${key.uppercaseFirstChar()}" }, when { Regex("^is[A-Z].*").containsMatchIn(key) -> key - else -> "is${uppercaseFirstChar(key)}" + else -> "is${key.uppercaseFirstChar()}" }, ).any { setCore(augmented, it, value) } @@ -62,8 +62,8 @@ open class AugmentableProxy(private val scriptRuntime: ScriptRuntime) : Augmenta open fun get(augmented: ScriptableObject, key: String): Any? { listOf( key, - "get${uppercaseFirstChar(key)}", - "is${uppercaseFirstChar(key)}", + "get${key.uppercaseFirstChar()}", + "is${key.uppercaseFirstChar()}", ).forEach { getCore(augmented, it).let { result -> if (result != NOT_FOUND) return result diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/colors/ColorNativeObject.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/colors/ColorNativeObject.kt index 84d5fe7d..5e39179f 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/colors/ColorNativeObject.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/colors/ColorNativeObject.kt @@ -55,7 +55,7 @@ class ColorNativeObject @JvmOverloads constructor(color: Any? = BLACK) : NativeO return when (name) { "equals", StringReadable.KEY -> true in mProxySetterNames -> true - in mProxyTowardsNames.map { "to${uppercaseFirstChar(it)}" } -> true + in mProxyTowardsNames.map { "to${it.uppercaseFirstChar()}" } -> true else -> super.has(name, start) } } @@ -80,7 +80,7 @@ class ColorNativeObject @JvmOverloads constructor(color: Any? = BLACK) : NativeO } else -> { val protoName = when (name) { - in mProxyTowardsNames -> "to${uppercaseFirstChar(name)}" + in mProxyTowardsNames -> "to${name.uppercaseFirstChar()}" else -> name } try { diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/console/Console.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/console/Console.kt index a89d67ee..bb5542ec 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/console/Console.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/console/Console.kt @@ -220,14 +220,14 @@ class Console(scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRuntime) { @JvmStatic @RhinoRuntimeFunctionInterface fun input(scriptRuntime: ScriptRuntime, args: Array) { - val s = "${lowercaseFirstChar(Console::class.java.simpleName)}.${::input.name}" + val s = "${Console::class.java.simpleName.lowercaseFirstChar()}.${::input.name}" throw RuntimeException(globalContext.getString(R.string.error_abandoned_method, s)) } @JvmStatic @RhinoRuntimeFunctionInterface fun rawInput(scriptRuntime: ScriptRuntime, args: Array) { - val s = "${lowercaseFirstChar(Console::class.java.simpleName)}.${::rawInput.name}" + val s = "${Console::class.java.simpleName.lowercaseFirstChar()}.${::rawInput.name}" throw RuntimeException(globalContext.getString(R.string.error_abandoned_method, s)) } @@ -311,11 +311,11 @@ class Console(scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRuntime) { val fName = listOf( when { Regex("^set[A-Z].*").containsMatchIn(key) -> key - else -> "set${uppercaseFirstChar(key)}" + else -> "set${key.uppercaseFirstChar()}" }, when { Regex("^is[A-Z].*").containsMatchIn(key) -> key - else -> "is${uppercaseFirstChar(key)}" + else -> "is${key.uppercaseFirstChar()}" }, ).find { name -> configurator::class.java.methods.any { method -> method.name == name } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/dialogs/Dialogs.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/dialogs/Dialogs.kt index 59364454..24241a7a 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/dialogs/Dialogs.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/dialogs/Dialogs.kt @@ -15,6 +15,10 @@ import org.autojs.autojs.extension.AnyExtensions.isJsXml import org.autojs.autojs.extension.AnyExtensions.jsBrief import org.autojs.autojs.extension.AnyExtensions.jsUnwrapped import org.autojs.autojs.extension.ArrayExtensions.toNativeArray +import org.autojs.autojs.extension.FlexibleArray.Companion.component1 +import org.autojs.autojs.extension.FlexibleArray.Companion.component2 +import org.autojs.autojs.extension.FlexibleArray.Companion.component3 +import org.autojs.autojs.extension.FlexibleArray.Companion.component4 import org.autojs.autojs.extension.ScriptableExtensions.defineProp import org.autojs.autojs.extension.ScriptableExtensions.prop import org.autojs.autojs.extension.ScriptableObjectExtensions.inquire @@ -36,7 +40,7 @@ import org.autojs.autojs.util.RhinoUtils.isUiThread import org.autojs.autojs.util.RhinoUtils.js_eval import org.autojs.autojs.util.RhinoUtils.newBaseFunction import org.autojs.autojs.util.RhinoUtils.newNativeObject -import org.autojs.autojs.util.StringUtils +import org.autojs.autojs.util.StringUtils.uppercaseFirstChar import org.autojs.autojs6.R import org.mozilla.javascript.BaseFunction import org.mozilla.javascript.Context @@ -672,7 +676,7 @@ class Dialogs(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { if (animation == "default") { win.setWindowAnimations(android.R.style.Animation) } else { - val suffix = StringUtils.uppercaseFirstChar(animation.replace('-', '_')) + val suffix = animation.replace('-', '_').uppercaseFirstChar() val animationStyle = android.R.style::class.java.getDeclaredField("Animation_$suffix").getInt(null) win.setWindowAnimations(animationStyle) } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/jsox/Jsox.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/jsox/Jsox.kt index 661132cb..9de75ebe 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/jsox/Jsox.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/jsox/Jsox.kt @@ -11,13 +11,13 @@ import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException import org.autojs.autojs.util.RhinoUtils.UNDEFINED import org.autojs.autojs.util.RhinoUtils.coerceString import org.autojs.autojs.util.RhinoUtils.flatten -import org.autojs.autojs.util.StringUtils import org.autojs.autojs.util.StringUtils.lowercaseFirstChar +import org.autojs.autojs.util.StringUtils.uppercaseFirstChar import org.mozilla.javascript.Undefined class Jsox(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), Invokable { - override val key = lowercaseFirstChar(javaClass.simpleName) + override val key = javaClass.simpleName.lowercaseFirstChar() override val selfAssignmentFunctions = listOf( ::extend.name, @@ -73,7 +73,7 @@ class Jsox(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime fun extendAllRhinoWithRuntime(scriptRuntime: ScriptRuntime): Undefined = extendRhinoWithRuntime(scriptRuntime, presetModules) private fun normalizeModuleName(name: String): String { - return StringUtils.uppercaseFirstChar(if (!name.endsWith('x')) "${name}x" else name) + return "${name.removeSuffix("x")}x".uppercaseFirstChar() } } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/sysprops/Sysprops.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/sysprops/Sysprops.kt index fe752f5d..4ce7cb53 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/sysprops/Sysprops.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/sysprops/Sysprops.kt @@ -12,7 +12,6 @@ import org.autojs.autojs.util.AndroidUtils.SystemProperties import org.autojs.autojs.util.RhinoUtils.coerceBoolean import org.autojs.autojs.util.RhinoUtils.coerceIntNumber import org.autojs.autojs.util.RhinoUtils.coerceString -import org.autojs.autojs.util.StringUtils.convertRegex import org.mozilla.javascript.NativeObject import org.mozilla.javascript.regexp.NativeRegExp @@ -85,7 +84,7 @@ class SysProps(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), Invok private fun matchFilter(input: String, filter: Any?) = when { filter.isJsNullish() -> true - filter is NativeRegExp -> Regex(convertRegex(filter.toString())).containsMatchIn(input) + filter is NativeRegExp -> filter.toString().toRegex().containsMatchIn(input) else -> input.contains(coerceString(filter)) } diff --git a/app/src/main/java/org/autojs/autojs/util/IntentUtils.kt b/app/src/main/java/org/autojs/autojs/util/IntentUtils.kt index 1200b6cb..4da64ffe 100644 --- a/app/src/main/java/org/autojs/autojs/util/IntentUtils.kt +++ b/app/src/main/java/org/autojs/autojs/util/IntentUtils.kt @@ -91,7 +91,6 @@ object IntentUtils { .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .let { context.startActivity(it) } } - } catch (e: ActivityNotFoundException) { exceptionHolder?.show(R.string.error_no_applications_available_for_browsing_this_link) // ViewUtils.showToast(context, R.string.text_no_browser, true) diff --git a/app/src/main/java/org/autojs/autojs/util/StringUtils.kt b/app/src/main/java/org/autojs/autojs/util/StringUtils.kt index e0350627..e271194a 100644 --- a/app/src/main/java/org/autojs/autojs/util/StringUtils.kt +++ b/app/src/main/java/org/autojs/autojs/util/StringUtils.kt @@ -11,7 +11,7 @@ import org.autojs.autojs.extension.NumberExtensions.roundToString import org.opencv.core.Point import java.nio.charset.Charset import java.nio.charset.StandardCharsets -import java.util.Locale +import java.util.* import kotlin.math.min import kotlin.math.pow @@ -21,8 +21,6 @@ import kotlin.math.pow */ object StringUtils { - private val regexPattern = "^/(.+)/$".toRegex() - private val globalAppContext by lazy { GlobalAppContext.get() } private val localePref = mapOf( @@ -39,22 +37,6 @@ object StringUtils { @JvmStatic fun key(@LocaleNonRelated resId: Int): String = globalAppContext.getString(resId) - // @Overwrite by SuperMonster003 on May 5, 2022. - // ! Dunno what "better implementation" really means. - // ! The only thing I did was make code more "lightweight". ;) - // ! zh-CN: - // ! 不清楚 "更好的实现方式" 的真正含义. - // ! 唯一做的只是使代码更 "轻量级". [眨眼符号] - // @TodoDiary by Stardust on Jan 30, 2018. - // ! 更好的实现方式. - // ! en-US (translated by SuperMonster003 on Jul 29, 2024): - // ! Better implementation. - @JvmStatic - fun convertRegex(regex: String) = regex.apply { if (shouldTakenAsRegex(this)) return replace(regexPattern, "$1") } - - @JvmStatic - fun shouldTakenAsRegex(s: String) = regexPattern.containsMatchIn(s) - @JvmStatic fun join(delimiter: CharSequence?, vararg tokens: Any?): String = TextUtils.join(delimiter!!, tokens) @@ -209,14 +191,20 @@ object StringUtils { } @JvmStatic - fun uppercaseFirstChar(s: String) = if (s.isEmpty()) s else s.replaceFirstChar { s[0].uppercaseChar() } + fun String.uppercaseFirstChar(): String { + val s = this + return if (s.isEmpty()) s else s.replaceFirstChar { s[0].uppercaseChar() } + } @JvmStatic - fun lowercaseFirstChar(s: String) = if (s.isEmpty()) s else s.replaceFirstChar { s[0].lowercaseChar() } + fun String.lowercaseFirstChar(): String { + val s = this + return if (s.isEmpty()) s else s.replaceFirstChar { s[0].lowercaseChar() } + } @JvmStatic @Deprecated("Deprecated since v6.6.0", ReplaceWith("uppercaseFirstChar(s)")) - fun toUpperCaseFirst(s: String) = uppercaseFirstChar(s) + fun toUpperCaseFirst(s: String) = s.uppercaseFirstChar() @JvmStatic fun toFormattedSummary(dataList: List Any?>>): String { diff --git a/version.properties b/version.properties index f8e742d0..2d86a76e 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Sat Dec 27 13:20:38 CST 2025 -BUILD_TIME=1766812838968 +#Sat Dec 27 21:41:16 CST 2025 +BUILD_TIME=1766842876384 COMPILE_SDK_VERSION=36 IMAGE_QUANT_CMAKE_VERSION=3.22.1 IMAGE_QUANT_NDK_VERSION=26.1.10909125 @@ -27,6 +27,6 @@ RAPID_OCR_OPENCV_MOBILE_LABEL_VERSION=13 RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3 TARGET_SDK_VERSION=36 TARGET_SDK_VERSION_INRT=29 -VERSION_BUILD=3554 +VERSION_BUILD=3557 VERSION_NAME=6.7.0 Alpha13 VSCODE_EXT_REQUIRED_VERSION=1.0.8