6.6.1 - Alpha2 - 优化 app.startActivity/startDualActivity 等方法适配性

This commit is contained in:
SuperMonster003
2024-12-27 19:42:12 +08:00
parent 13b71a4310
commit cfb8557545
35 changed files with 333 additions and 197 deletions

View File

@@ -6,7 +6,7 @@
# v6.6.1
###### 2024/12/26
###### 2024/12/27
* `إضافة جديدة` وحدة Pinyin لتحويل النصوص الصينية إلى بينيين (راجع وثائق المشروع > [البينيين الصيني](https://docs.autojs6.com/#/pinyin))
* `إضافة جديدة` وحدة Pinyin4j لتحويل النصوص الصينية إلى بينيين (راجع وثائق المشروع > [البينيين الصيني](https://docs.autojs6.com/#/pinyin4j))
@@ -21,6 +21,7 @@
* `تحسين` استعادة أكبر قدر ممكن من المعلومات الأساسية لمشاريع النصوص عند تلف ملف project.json
* `تحسين` تحويل اللغة الصينية المبسطة تلقائيًا إلى نظام بينيين (بما في ذلك الحروف متعددة النغمات) عند توليد اللواحق للأسماء في الملفات المفردة
* `تحسين` دعم الوسائط السلبية في الطرق UiSelector#findOnce و UiSelector#find
* `تحسين` تم تحسين تكيفية أساليب app.startActivity/startDualActivity
* `تحسين` دعم أشكال مختصرة إضافية لبادئات الأسماء في المصفوفات المرتبطة بعناصر الواجهة (مثل RecyclerView و Snackbar وغيرها)
* `تحسين` مزامنة أحدث كود من المصدر الرئيسي لمحرك Rhino وتكييفه مع المشروع الحالي
* `التبعيات` إضافة Pinyin4j الإصدار 2.5.0

View File

@@ -6,7 +6,7 @@
# v6.6.1
###### 2024/12/26
###### 2024/12/27
* `Feature` Pinyin module for Chinese Pinyin conversion (Refer to Project Documentation > [Chinese Pinyin](https://docs.autojs6.com/#/pinyin))
* `Feature` Pinyin4j module for Chinese Pinyin conversion (Refer to Project Documentation > [Chinese Pinyin](https://docs.autojs6.com/#/pinyin4j))
@@ -21,6 +21,7 @@
* `Improvement` Recover as much critical information as possible for script projects when project.json is corrupted
* `Improvement` Automatically convert Simplified Chinese to Pinyin (including multi-tone characters) for generated package name suffixes when packaging single files
* `Improvement` Support for negative arguments in the UiSelector#findOnce and UiSelector#find methods
* `Improvement` Enhanced adaptability of app.startActivity/startDualActivity methods
* `Improvement` UI elements and className-related selectors now support more package name prefix omission forms (e.g., RecyclerView, Snackbar, etc.)
* `Improvement` Synchronize with the latest upstream code of the Rhino engine and adapt it to the existing project
* `Dependency` Added Pinyin4j version 2.5.0

View File

@@ -6,7 +6,7 @@
# v6.6.1
###### 2024/12/26
###### 2024/12/27
* `Nuevo` Módulo Pinyin para la conversión de pinyin en chino (Consulte la documentación del proyecto > [Pinyin chino](https://docs.autojs6.com/#/pinyin))
* `Nuevo` Módulo Pinyin4j para la conversión de pinyin en chino (Consulte la documentación del proyecto > [Pinyin chino](https://docs.autojs6.com/#/pinyin4j))
@@ -21,6 +21,7 @@
* `Mejora` Recuperar la mayor cantidad de información crítica posible para proyectos de scripts cuando el archivo project.json está dañado
* `Mejora` Convertir automáticamente chino simplificado a Pinyin (incluyendo caracteres con múltiples tonos) para los sufijos de nombres de paquetes generados al empaquetar archivos individuales
* `Mejora` Soporte para argumentos negativos en los métodos UiSelector#findOnce y UiSelector#find
* `Mejora` Se mejoró la adaptabilidad de los métodos app.startActivity/startDualActivity
* `Mejora` Mayor soporte para formas abreviadas de prefijos de nombres de paquetes en selectores relacionados con elementos UI y className (por ejemplo, RecyclerView, Snackbar, etc.)
* `Mejora` Sincronizar el código más reciente del upstream del motor Rhino y adaptarlo al proyecto existente
* `Dependencia` Agregado Pinyin4j versión 2.5.0

View File

@@ -6,7 +6,7 @@
# v6.6.1
###### 2024/12/26
###### 2024/12/27
* `Fonctionnalité` Module Pinyin pour la conversion du pinyin chinois (Consultez la documentation du projet > [Pinyin chinois](https://docs.autojs6.com/#/pinyin))
* `Fonctionnalité` Module Pinyin4j pour la conversion du pinyin chinois (Consultez la documentation du projet > [Pinyin chinois](https://docs.autojs6.com/#/pinyin4j))
@@ -21,6 +21,7 @@
* `Amélioration` Récupérer autant d'informations critiques que possible pour les projets de script en cas de corruption du fichier project.json
* `Amélioration` Convertir automatiquement le chinois simplifié en pinyin (y compris les caractères à tons multiples) pour les suffixes de noms de paquet générés lors de l'empaquetage de fichiers uniques
* `Amélioration` Soutien des arguments négatifs dans les méthodes UiSelector#findOnce et UiSelector#find
* `Amélioration` Amélioration de l'adaptabilité des méthodes app.startActivity/startDualActivity
* `Amélioration` Prise en charge des formes abrégées supplémentaires pour les préfixes de noms de paquet dans les sélecteurs liés aux éléments de l'interface utilisateur et aux className (par exemple RecyclerView, Snackbar, etc.)
* `Amélioration` Synchroniser le code en amont le plus récent du moteur Rhino et l'adapter au projet existant
* `Dépendance` Ajout de Pinyin4j version 2.5.0

View File

@@ -6,7 +6,7 @@
# v6.6.1
###### 2024/12/26
###### 2024/12/27
* `新機能` 中国語のピンイン変換用の Pinyin モジュール (プロジェクトドキュメントを参照 > [中国語ピンイン](https://docs.autojs6.com/#/pinyin))
* `新機能` 中国語のピンイン変換用の Pinyin4j モジュール (プロジェクトドキュメントを参照 > [中国語ピンイン](https://docs.autojs6.com/#/pinyin4j))
@@ -21,6 +21,7 @@
* `改善` project.json ファイルが破損した場合でも, スクリプトプロジェクトの重要な情報を可能な限り復元
* `改善` 単一ファイルをパッケージ化する際に, 自動生成されるパッケージ名のサフィックスを簡体字中国語からピンインに変換 (多音字対応)
* `改善` UiSelector#findOnce と UiSelector#find メソッドで負の引数をサポート
* `改善` app.startActivity/startDualActivity メソッドの適応性が向上しました
* `改善` UI要素や className に関連するセレクターが RecyclerView や Snackbar などのパッケージ名プレフィックス省略形式にさらに対応
* `改善` Rhino エンジンの最新の上流コードを同期し, 既存のプロジェクトに適応させる
* `依存関係` Pinyin4j バージョン 2.5.0 を追加

View File

@@ -6,7 +6,7 @@
# v6.6.1
###### 2024/12/26
###### 2024/12/27
* `추가` 중국어 병음 변환을 위한 Pinyin 모듈 (프로젝트 문서 참고 > [중국어 병음](https://docs.autojs6.com/#/pinyin))
* `추가` 중국어 병음 변환을 위한 Pinyin4j 모듈 (프로젝트 문서 참고 > [중국어 병음](https://docs.autojs6.com/#/pinyin4j))
@@ -21,6 +21,7 @@
* `개선` project.json 파일이 손상된 경우에도 가능한 한 중요한 정보를 복원
* `개선` 단일 파일을 패키징할 때 자동 생성된 패키지 이름 접미사를 간체자로부터 병음으로 변환 (다음 음도 지원)
* `개선` UiSelector#findOnce 및 UiSelector#find 메서드에서 음수 인수 지원
* `개선` app.startActivity/startDualActivity 메서드의 적응성이 향상되었습니다
* `개선` UI 요소 및 className 관련 선택자가 RecyclerView, Snackbar 등과 같은 더욱 다양한 패키지 이름 접두사 생략 형식을 지원
* `개선` Rhino 엔진의 최신 업스트림 코드를 동기화하고 기존 프로젝트에 맞게 조정합니다
* `의존성` Pinyin4j 버전 2.5.0 추가

View File

@@ -6,7 +6,7 @@
# v6.6.1
###### 2024/12/26
###### 2024/12/27
* `Новое` Модуль Pinyin для преобразования китайского пиньиня (См. документацию проекта > [Китайский Пиньинь](https://docs.autojs6.com/#/pinyin))
* `Новое` Модуль Pinyin4j для преобразования китайского пиньиня (См. документацию проекта > [Китайский Пиньинь](https://docs.autojs6.com/#/pinyin4j))
@@ -21,6 +21,7 @@
* `Улучшение` Максимальное восстановление ключевой информации для проектов скриптов в случае повреждения файла project.json
* `Улучшение` Автоматическая конвертация упрощенного китайского в пиньинь (включая многозначные символы) для суффиксов пакетов, создаваемых при упаковке отдельных файлов
* `Улучшение` Поддержка отрицательных аргументов в методах UiSelector#findOnce и UiSelector#find
* `Улучшение` Улучшена адаптивность методов app.startActivity/startDualActivity
* `Улучшение` Поддержка дополнительных сокращённых форм префиксов имён пакетов в селекторах, связанных с элементами UI и className (например, RecyclerView, Snackbar и т. д.)
* `Улучшение` Синхронизировать последний код из официального репозитория Rhino и адаптировать его к существующему проекту
* `Зависимость` Добавлена Pinyin4j версии 2.5.0

View File

@@ -6,7 +6,7 @@
# v6.6.1
###### 2024/12/26
###### 2024/12/27
* `新增` pinyin 模块, 用于汉语拼音转换 (参阅 项目文档 > [汉语拼音](https://docs.autojs6.com/#/pinyin))
* `新增` pinyin4j 模块, 用于汉语拼音转换 (参阅 项目文档 > [汉语拼音](https://docs.autojs6.com/#/pinyin4j))
@@ -21,6 +21,7 @@
* `优化` 脚本项目识别在 project.json 损坏情况下尽可能还原关键信息
* `优化` 打包单文件时自动生成的包名后缀支持将简体中文转换为拼音 (支持多音字)
* `优化` UiSelector#findOnce 及 UiSelector#find 方法支持负数参数
* `优化` app.startActivity/startDualActivity 方法增强适配性
* `优化` UI 元素及 className 相关选择器支持更多的包名前缀省略形式 (如 RecyclerView, Snackbar 等)
* `优化` 同步最新的 Rhino 引擎官方上游代码并进行必要的代码适配
* `依赖` 附加 Pinyin4j 版本 2.5.0

View File

@@ -6,7 +6,7 @@
# v6.6.1
###### 2024/12/26
###### 2024/12/27
* `新增` pinyin 模塊, 用於漢語拼音轉換 (參閲 項目文檔 > [漢語拼音](https://docs.autojs6.com/#/pinyin))
* `新增` pinyin4j 模塊, 用於漢語拼音轉換 (參閲 項目文檔 > [漢語拼音](https://docs.autojs6.com/#/pinyin4j))
@@ -21,6 +21,7 @@
* `優化` 腳本項目識別在 project.json 損壞情況下儘可能還原關鍵信息
* `優化` 打包單文件時自動生成的包名後綴支持將簡體中文轉換為拼音 (支持多音字)
* `優化` UiSelector#findOnce 及 UiSelector#find 方法支持負數參數
* `優化` app.startActivity/startDualActivity 方法增強適配性
* `優化` UI 元素及 className 相關選擇器支持更多的包名前綴省略形式 (如 RecyclerView, Snackbar 等)
* `優化` 同步最新的 Rhino 引擎官方上游代碼並進行必要的代碼適配
* `依賴` 附加 Pinyin4j 版本 2.5.0

View File

@@ -6,7 +6,7 @@
# v6.6.1
###### 2024/12/26
###### 2024/12/27
* `新增` pinyin 模組, 用於漢語拼音轉換 (參閱 專案文件 > [漢語拼音](https://docs.autojs6.com/#/pinyin))
* `新增` pinyin4j 模組, 用於漢語拼音轉換 (參閱 專案文件 > [漢語拼音](https://docs.autojs6.com/#/pinyin4j))
@@ -21,6 +21,7 @@
* `最佳化` 指令碼專案識別在 project.json 損壞情況下儘可能還原關鍵資訊
* `最佳化` 打包單檔案時自動生成的包名字尾支援將簡體中文轉換為拼音 (支援多音字)
* `最佳化` UiSelector#findOnce 及 UiSelector#find 方法支援負數引數
* `最佳化` app.startActivity/startDualActivity 方法增強適配性
* `最佳化` UI 元素及 className 相關選擇器支援更多的包名字首省略形式 (如 RecyclerView, Snackbar 等)
* `最佳化` 同步最新的 Rhino 引擎官方上游程式碼並進行必要的程式碼適配
* `依賴` 附加 Pinyin4j 版本 2.5.0

View File

@@ -6,7 +6,7 @@
# v6.6.1
###### 2024/12/26
###### 2024/12/27
* `新增` pinyin 模块, 用于汉语拼音转换 (参阅 项目文档 > [汉语拼音](https://docs.autojs6.com/#/pinyin))
* `新增` pinyin4j 模块, 用于汉语拼音转换 (参阅 项目文档 > [汉语拼音](https://docs.autojs6.com/#/pinyin4j))
@@ -21,6 +21,7 @@
* `优化` 脚本项目识别在 project.json 损坏情况下尽可能还原关键信息
* `优化` 打包单文件时自动生成的包名后缀支持将简体中文转换为拼音 (支持多音字)
* `优化` UiSelector#findOnce 及 UiSelector#find 方法支持负数参数
* `优化` app.startActivity/startDualActivity 方法增强适配性
* `优化` UI 元素及 className 相关选择器支持更多的包名前缀省略形式 (如 RecyclerView, Snackbar 等)
* `优化` 同步最新的 Rhino 引擎官方上游代码并进行必要的代码适配
* `依赖` 附加 Pinyin4j 版本 2.5.0

View File

@@ -18,11 +18,13 @@ import org.autojs.autojs.runtime.api.AppUtils.Companion.BroadcastShortForm
import org.autojs.autojs.runtime.api.WrappedShizuku
import org.autojs.autojs.runtime.api.augment.Augmentable
import org.autojs.autojs.runtime.api.augment.shell.Shell
import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
import org.autojs.autojs.runtime.exception.ShouldNeverHappenException
import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
import org.autojs.autojs.util.RhinoUtils
import org.autojs.autojs.util.RhinoUtils.UNDEFINED
import org.autojs.autojs.util.RhinoUtils.coerceBoolean
import org.autojs.autojs.util.RhinoUtils.coerceString
import org.autojs.autojs.util.RhinoUtils.js_object_assign
import org.autojs.autojs.util.RhinoUtils.newNativeArray
import org.autojs.autojs.util.RhinoUtils.newNativeObject
import org.autojs.autojs.util.RhinoUtils.undefined
@@ -56,6 +58,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
::sendLocalBroadcastSync.name,
::parseUri.name,
::openUrl.name,
::openDualUrl.name,
::getUriForFile.name,
::getAppByAlias.name,
::launch.name to AS_GLOBAL,
@@ -98,131 +101,117 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
@JvmStatic
@RhinoFunctionBody
fun intentRhinoWithRuntime(scriptRuntime: ScriptRuntime, o: Any?): Intent {
if (o is Intent) return o
require(o is NativeObject) {
"Argument for app.intent must be a JavaScript Object rather than ${o?.javaClass?.name ?: "null"}"
}
val intent = Intent()
if (!o.prop("url").isJsNullish()) {
o.put("data", o, parseIntentUrl(scriptRuntime, o))
}
if (!o.prop("package").isJsNullish()) {
if (o.prop("packageName").isJsNullish()) {
o.put("packageName", o, o.prop("package"))
}
} else {
if (!o.prop("packageName").isJsNullish()) {
o.put("package", o, o.prop("packageName"))
}
}
if (!o.prop("packageName").isJsNullish()) {
val k = Context.toString(o.prop("packageName"))
if (k in presetPackageNames) {
o.defineProp("packageName", presetPackageNames[k])
}
if (!o.prop("className").isJsNullish()) {
intent.setClassName(coerceString(o.prop("packageName")), parseClassName(o))
} else {
// @Hint by SuperMonster003 on Jun 23, 2020.
// ! the Intent can only match the components
// ! in the given application package with setPackage().
// ! Otherwise, if there's more than one app that can handle the intent,
// ! the system presents the user with a dialog to pick which app to use.
// ! zh-CN:
// ! Intent 只能匹配通过 setPackage() 设置的给定应用包中的组件.
// ! 否则, 如果有多个应用可以处理该 Intent,
// ! 系统会向用户展示一个对话框, 让用户选择要使用哪个应用.
intent.setPackage(coerceString(o.prop("packageName")))
}
}
if (o.prop("extras") is NativeObject) {
(o.prop("extras") as NativeObject).entries.forEach { entry ->
val (key, value) = entry
RhinoUtils.putExtraForIntent(intent, key, value)
}
}
if (!o.prop("category").isJsNullish()) {
if (o.prop("category") is Iterable<*>) {
(o.prop("category") as Iterable<*>).forEach { cat ->
intent.addCategory(Context.toString(cat))
}
} else {
intent.addCategory(Context.toString(o.prop("category")))
}
}
if (!o.prop("action").isJsNullish()) {
intent.setAction(parseIntentAction(o.prop("action")))
}
if (!o.prop("flags").isJsNullish()) {
intent.setFlags(parseIntentFlags(o.prop("flags")))
}
if (!o.prop("type").isJsNullish()) {
if (!o.prop("data").isJsNullish()) {
intent.setDataAndType(parseUriRhinoWithRuntime(scriptRuntime, o.prop("data")), Context.toString(o.prop("type")))
} else {
intent.setType(Context.toString(o.prop("type")))
}
} else {
if (!o.prop("data").isJsNullish()) {
intent.setData(Uri.parse(Context.toString(o.prop("data"))))
}
}
return intent
fun intentRhinoWithRuntime(scriptRuntime: ScriptRuntime, o: Any?): Intent = when (o) {
is Intent -> o
is NativeObject -> Intent().configure(scriptRuntime, o)
else -> throw IllegalArgumentException("Argument for app.intent must be either an Intent or a JavaScript Object rather than ${o.jsBrief()}")
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun startActivity(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Unit = ensureArgumentsOnlyOne(args) { o ->
when (o) {
@Suppress("HttpUrlsUsage")
fun startActivity(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsLengthInRange(args, 1..2) { argList ->
val (obj, options) = argList
when (obj) {
is String -> when {
o.contains("://") -> {
openUrlRhino(o)
}
rexWebSiteWithoutProtocol.matches(o) -> {
@Suppress("HttpUrlsUsage")
openUrlRhino("http://$o")
}
!options.isJsNullish() -> throw IllegalArgumentException("Method app.startActivity can only have one argument when argument[0] is String")
obj.contains("://") -> openUrlRhino(obj)
rexWebSiteWithoutProtocol.matches(obj) -> openUrlRhino("http://$obj")
else -> runCatching {
startActivityWithGlobalContext(Intent(globalContext, ActivityShortForm.valueOf(o.uppercase()).classType))
startActivityWithGlobalContext(Intent(globalContext, ActivityShortForm.valueOf(obj.uppercase()).classType))
}.getOrElse {
when (it) {
is WrappedIllegalArgumentException -> throw WrappedIllegalArgumentException("Activity short form $o cannot be found")
is WrappedIllegalArgumentException -> throw WrappedIllegalArgumentException("Activity short form $obj cannot be found")
else -> throw it
}
}
}
is Intent -> when {
WrappedShizuku.isOperational() -> WrappedShizuku.execCommand("am start ${toIntentToShell(scriptRuntime, o)}")
else -> startActivityWithGlobalContext(o)
options.isJsNullish() -> startActivityWithGlobalContext(obj)
options is NativeObject -> obj.configure(scriptRuntime, options).let { configuredIntent ->
when {
checkDualProperty(options) -> startDualActivity(scriptRuntime, args)
checkRootProperty(options) && RootUtils.isRootAvailable() -> {
val tmpIntent = configuredIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
Shell.execCommand(scriptRuntime, arrayOf("am start ${intentToShellRhino(tmpIntent)}", /* withRoot = */ true)).throwIfError()
}
checkShizukuProperty(options) && WrappedShizuku.isOperational() -> {
val tmpIntent = configuredIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
WrappedShizuku.execCommand("am start ${intentToShellRhino(tmpIntent)}").throwIfError()
}
else -> startActivityWithGlobalContext(configuredIntent)
}
}
else -> throw IllegalArgumentException("Argument[1] for app.startActivity must be a JavaScript Object when argument[0] is Intent")
}
is URI -> openUrlRhino(o)
is NativeObject -> when {
checkDualProperty(o) -> startDualActivity(scriptRuntime, args)
checkRootProperty(o) -> Shell.execCommand(scriptRuntime, arrayOf("am start ${toIntentToShell(scriptRuntime, o)}", true)).throwIfError()
WrappedShizuku.isOperational() -> WrappedShizuku.execCommand("am start ${toIntentToShell(scriptRuntime, o)}").throwIfError()
else -> startActivityWithGlobalContext(scriptRuntime, o)
is URI -> when {
!options.isJsNullish() -> throw IllegalArgumentException("Method app.startActivity can only have one argument when argument[0] is URI")
else -> openUrlRhino(obj)
}
else -> startActivityWithGlobalContext(scriptRuntime, o)
is NativeObject -> {
val opt = when {
options.isJsNullish() -> obj
options is NativeObject -> js_object_assign(js_object_assign(newNativeObject(), obj), options) as NativeObject
else -> throw IllegalArgumentException("Argument[1] for app.startActivity must be a JavaScript Object when argument[0] is JavaScript Object")
}
when {
checkDualProperty(opt) -> startDualActivity(scriptRuntime, args)
checkRootProperty(opt) && RootUtils.isRootAvailable() -> {
val tmpIntent = intentRhinoWithRuntime(scriptRuntime, opt).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
Shell.execCommand(scriptRuntime, arrayOf("am start ${intentToShellRhino(tmpIntent)}", /* withRoot = */ true)).throwIfError()
}
checkShizukuProperty(opt) && WrappedShizuku.isOperational() -> {
val tmpIntent = intentRhinoWithRuntime(scriptRuntime, opt).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
val intentCommand = intentToShellRhino(tmpIntent)
WrappedShizuku.execCommand("am start $intentCommand").throwIfError()
}
else -> startActivityWithGlobalContext(scriptRuntime, opt)
}
}
else -> throw IllegalArgumentException("Unknown type of argument[0]: ${obj.jsBrief()}; method: app.startActivity")
}
UNDEFINED
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun startDualActivity(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Unit = ensureArgumentsOnlyOne(args) { intent ->
execCommandByDualUser(scriptRuntime, intent)
@Suppress("HttpUrlsUsage")
fun startDualActivity(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsLengthInRange(args, 1..2) { argList ->
val (obj, options) = argList
when (obj) {
is String -> when {
!options.isJsNullish() -> throw IllegalArgumentException("Method app.startDualActivity can only have one argument when argument[0] is String")
obj.contains("://") -> openDualUrlRhino(scriptRuntime, obj)
rexWebSiteWithoutProtocol.matches(obj) -> openDualUrlRhino(scriptRuntime, "http://$obj")
else -> runCatching {
startActivityForDualUser(scriptRuntime, Intent(globalContext, ActivityShortForm.valueOf(obj.uppercase()).classType))
}.getOrElse {
when (it) {
is WrappedIllegalArgumentException -> throw WrappedIllegalArgumentException("Activity short form $obj cannot be found")
else -> throw it
}
}
}
is Intent -> when {
options.isJsNullish() -> startActivityForDualUser(scriptRuntime, obj)
options is NativeObject -> startActivityForDualUser(scriptRuntime, obj.configure(scriptRuntime, options))
else -> throw IllegalArgumentException("Argument[1] for app.startDualActivity must be a JavaScript Object when argument[0] is Intent")
}
is URI -> when {
!options.isJsNullish() -> throw IllegalArgumentException("Method app.startDualActivity can only have one argument when argument[0] is URI")
else -> openUrlRhino(obj)
}
is NativeObject -> {
val opt = when {
options.isJsNullish() -> obj
options is NativeObject -> js_object_assign(js_object_assign(newNativeObject(), obj), options) as NativeObject
else -> throw IllegalArgumentException("Argument[1] for app.startDualActivity must be a JavaScript Object when argument[0] is JavaScript Object")
}
startActivityForDualUser(scriptRuntime, opt)
}
else -> throw IllegalArgumentException("Unknown type of argument[0]: ${obj.jsBrief()}; method: app.startDualActivity")
}
UNDEFINED
}
@JvmStatic
@@ -383,19 +372,20 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
@JvmStatic
@RhinoRuntimeFunctionInterface
fun startService(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Unit = ensureArgumentsOnlyOne(args) { o ->
fun startService(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsOnlyOne(args) { o ->
when {
o is NativeObject && checkRootProperty(o) -> {
@Suppress("SpellCheckingInspection")
Shell.execCommand(scriptRuntime, arrayOf(/* cmd = */ "am startservice ${intentToShellRhino(o)}", /* withRoot = */ 1))
Shell.execCommand(scriptRuntime, arrayOf(/* cmd = */ "am startservice ${intentToShellRhino(o)}", /* withRoot = */ true))
}
else -> globalContext.startService(intentRhinoWithRuntime(scriptRuntime, o))
}
UNDEFINED
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun sendEmail(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Unit = ensureArgumentsOnlyOne(args) { options ->
fun sendEmail(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsOnlyOne(args) { options ->
val optionsMap = options as? NativeObject ?: newNativeObject()
val emailIntent = Intent(Intent.ACTION_SEND).apply {
@@ -422,11 +412,13 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
}
startActivityWithGlobalContext(Intent.createChooser(emailIntent, "Send Email"))
UNDEFINED
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun sendBroadcast(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Unit = ensureArgumentsOnlyOne(args) { o ->
fun sendBroadcast(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsOnlyOne(args) { o ->
when (o) {
is String -> {
runCatching {
@@ -443,11 +435,12 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
}
else -> when {
o is NativeObject && checkRootProperty(o) -> {
Shell.execCommand(scriptRuntime, arrayOf("am broadcast ${intentToShellRhino(o)}", 1))
Shell.execCommand(scriptRuntime, arrayOf("am broadcast ${intentToShellRhino(o)}", /* withRoot = */ true))
}
else -> globalContext.sendBroadcast(intentRhinoWithRuntime(scriptRuntime, o))
}
}
UNDEFINED
}
@JvmStatic
@@ -490,10 +483,20 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
openUrlRhino(it)
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun openDualUrl(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsOnlyOne(args) {
openDualUrlRhino(scriptRuntime, it)
}
@JvmStatic
@RhinoFunctionBody
fun openUrlRhino(url: Any?) = undefined { openUrlInternal(coerceString(url)) }
@JvmStatic
@RhinoFunctionBody
fun openDualUrlRhino(scriptRuntime: ScriptRuntime, url: Any?) = undefined { openDualUrlInternal(scriptRuntime, coerceString(url)) }
@Suppress("HttpUrlsUsage")
fun openUrlInternal(url: String) {
val prefix = "http://".takeUnless { url.contains("://") } ?: ""
@@ -503,6 +506,15 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
.let { globalContext.startActivity(it) }
}
@Suppress("HttpUrlsUsage")
private fun openDualUrlInternal(scriptRuntime: ScriptRuntime, url: String) {
val prefix = "http://".takeUnless { url.contains("://") } ?: ""
Intent(Intent.ACTION_VIEW)
.setData(Uri.parse(prefix + url))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.let { startActivityForDualUser(scriptRuntime, it) }
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun getUriForFile(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Uri? = ensureArgumentsOnlyOne(args) { o ->
@@ -559,7 +571,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
o is PresetApp -> launchDualPackageInternal(scriptRuntime, o.packageName)
else -> launchDualPackageInternal(scriptRuntime, getAppByAliasRhino(o)?.packageName ?: Context.toString(o))
}
}.isSuccess
}.getOrElse { false }
}
@JvmStatic
@@ -588,7 +600,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
launchDualPackageInternal(scriptRuntime, it.packageName)
} ?: launchDualAppInternal(scriptRuntime, Context.toString(o))
}
}.isSuccess
}.getOrElse { false }
}
@JvmStatic
@@ -656,7 +668,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
@JvmStatic
@RhinoRuntimeFunctionInterface
fun uninstall(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Unit = ensureArgumentsOnlyOne(args) { o ->
fun uninstall(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsOnlyOne(args) { o ->
when {
o.isJsNullish() -> Unit
o is PresetApp -> scriptRuntime.app.uninstall(o.packageName)
@@ -664,11 +676,12 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
scriptRuntime.app.uninstall(it.packageName)
} ?: scriptRuntime.app.uninstall(Context.toString(o))
}
UNDEFINED
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun uninstallDual(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Unit = ensureArgumentsOnlyOne(args) { o ->
fun uninstallDual(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsOnlyOne(args) { o ->
when {
o.isJsNullish() -> Unit
o is PresetApp -> uninstallDualInternal(scriptRuntime, o.packageName)
@@ -676,6 +689,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
uninstallDualInternal(scriptRuntime, it.packageName)
} ?: uninstallDualInternal(scriptRuntime, Context.toString(o))
}
UNDEFINED
}
// TODO by SuperMonster003 on May 23, 2024.
@@ -728,10 +742,10 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
val packageName = getPackageName(scriptRuntime, argList) ?: return@ensureArgumentsLength false
val command = "am force-stop $packageName"
when {
RootUtils.isRootAvailable() -> Shell.execCommand(scriptRuntime, arrayOf(command, true)).code == 0
WrappedShizuku.isOperational() -> WrappedShizuku.execCommand(command).code == 0
else -> Shell.execCommand(scriptRuntime, arrayOf(command, false)).code == 0
}
RootUtils.isRootAvailable() -> Shell.execCommand(scriptRuntime, arrayOf(command, /* withRoot = */ true))
WrappedShizuku.isOperational() -> WrappedShizuku.execCommand(command)
else -> Shell.execCommand(scriptRuntime, arrayOf(command, /* withRoot = */ false))
}.code == 0
}
// @Hint by SuperMonster003 on Oct 30, 2024.
@@ -743,7 +757,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
fun killDual(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLength(args, 1) { argList ->
val packageName = getPackageName(scriptRuntime, argList) ?: return@ensureArgumentsLength false
val command = "am force-stop $packageName"
runCatching { execCommandByDualUser(scriptRuntime, command, RootUtils.isRootAvailable()) }.isSuccess
runCatching { execCommandForDualUser(scriptRuntime, command, RootUtils.isRootAvailable(), WrappedShizuku.isOperational()) }.isSuccess
}
private fun parseClassName(o: NativeObject): String {
@@ -761,11 +775,18 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
private fun parseIntentFlags(flags: Any?): Int {
fun parse(o: Any?) =
fun parse(o: Any?): Int =
when (o) {
is String -> Intent::class.java.fields
.firstOrNull { it.name == "FLAG_${o.uppercase()}" }
?.getInt(null)
is String -> {
if (o.contains("|")) {
o.split(Regex("\\s*\\|\\s*")).map(::parse).fold(0) { a, b -> a or b }
} else {
Intent::class.java.fields.firstOrNull {
val sanitizedInputRegex = Regex.escape(o.replace(Regex("\\W"), "_"))
it.name.matches(Regex("(flag_)?(activity_)?$sanitizedInputRegex(_task)?", RegexOption.IGNORE_CASE))
}?.getInt(null)
}
}
is Number -> o.toInt()
else -> null
} ?: throw WrappedIllegalArgumentException("Invalid flags: $o")
@@ -830,21 +851,20 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
globalContext.startActivity(o.apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
}
private fun toIntentToShell(scriptRuntime: ScriptRuntime, intent: Any?) = intentToShellRhino(intentRhinoWithRuntime(scriptRuntime, intent))
private fun execCommandByDualUser(scriptRuntime: ScriptRuntime, intent: Any?) {
executeCommandForDualUser(scriptRuntime, { userIdentifier ->
"am start ${toIntentToShell(scriptRuntime, intent)} --user $userIdentifier"
}, intent is NativeObject && checkRootProperty(intent))
private fun startActivityForDualUser(scriptRuntime: ScriptRuntime, o: Any?) {
val intent = intentRhinoWithRuntime(scriptRuntime, o).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
val command = "am start ${intentToShellRhino(intent)}"
when (o) {
is NativeObject -> {
val withRoot = o.inquire("root", ::coerceBoolean, true)
val withShizuku = o.inquire("shizuku", ::coerceBoolean, true)
execCommandForDualUser(scriptRuntime, command, withRoot, withShizuku)
}
else -> execCommandForDualUser(scriptRuntime, command)
}
}
private fun execCommandByDualUser(scriptRuntime: ScriptRuntime, command: String, withRoot: Boolean) {
executeCommandForDualUser(scriptRuntime, { userIdentifier ->
"$command --user $userIdentifier"
}, withRoot)
}
private fun executeCommandForDualUser(scriptRuntime: ScriptRuntime, commandSupplier: (Int) -> String, withRoot: Boolean) {
private fun execCommandForDualUser(scriptRuntime: ScriptRuntime, command: String, withRoot: Boolean = true, withShizuku: Boolean = true) {
val userManager = globalContext.getSystemService(Class.forName("android.os.UserManager"))
val getUserProfilesMethod = userManager.javaClass.getDeclaredMethod("getUserProfiles")
@@ -861,11 +881,11 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
for (userHandle in userProfiles) {
val currentUserIdentifier = getIdentifierMethod.invoke(userHandle) as Int
if (currentUserIdentifier != processUserIdentifier) {
val command = commandSupplier(currentUserIdentifier)
val niceCommand = "$command --user $currentUserIdentifier"
when {
withRoot -> Shell.execCommand(scriptRuntime, arrayOf(command, 1))
WrappedShizuku.isOperational() -> WrappedShizuku.execCommand(command)
else -> Shell.execCommand(scriptRuntime, arrayOf(command, 0))
withRoot && RootUtils.isRootAvailable() -> Shell.execCommand(scriptRuntime, arrayOf(niceCommand, /* withRoot = */ true))
withShizuku && WrappedShizuku.isOperational() -> WrappedShizuku.execCommand(niceCommand)
else -> Shell.execCommand(scriptRuntime, arrayOf(niceCommand, /* withRoot = */ false))
}.throwIfError()
}
}
@@ -875,32 +895,113 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
return o?.let { PresetApp.getAppByAlias(Context.toString(it)) }
}
private fun launchDualPackageInternal(scriptRuntime: ScriptRuntime, o: String) {
private fun launchDualPackageInternal(scriptRuntime: ScriptRuntime, o: String): Boolean {
val nicePackageName = getAppByAlias(scriptRuntime, arrayOf(o))?.packageName ?: (/* packageName = */ o)
val intent = globalContext.packageManager.getLaunchIntentForPackage(nicePackageName) ?: return
execCommandByDualUser(scriptRuntime, intent)
val intent = globalContext.packageManager.getLaunchIntentForPackage(nicePackageName) ?: return false
startActivityForDualUser(scriptRuntime, intent)
return true
}
private fun launchDualAppInternal(scriptRuntime: ScriptRuntime, packageName: String) {
getPackageName(scriptRuntime, arrayOf(packageName))?.let { launchDualPackageInternal(scriptRuntime, it) } ?: false
private fun launchDualAppInternal(scriptRuntime: ScriptRuntime, packageName: String): Boolean {
return getPackageName(scriptRuntime, arrayOf(packageName))?.let { launchDualPackageInternal(scriptRuntime, it) } ?: false
}
private fun launchDualSettingsInternal(scriptRuntime: ScriptRuntime, packageName: String) {
execCommandByDualUser(scriptRuntime, Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
addCategory(Intent.CATEGORY_DEFAULT)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivityForDualUser(scriptRuntime, Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.parse("package:$packageName")
})
}
private fun uninstallDualInternal(scriptRuntime: ScriptRuntime, packageName: String) {
execCommandByDualUser(scriptRuntime, Intent(Intent.ACTION_DELETE, Uri.parse("package:$packageName")))
startActivityForDualUser(scriptRuntime, Intent(Intent.ACTION_DELETE).apply {
data = Uri.parse("package:$packageName")
})
}
private fun checkRootProperty(o: NativeObject) = o.inquire("root", ::coerceBoolean, false)
private fun checkShizukuProperty(o: NativeObject) = o.inquire("shizuku", ::coerceBoolean, false) && WrappedShizuku.isOperational()
private fun checkDualProperty(o: NativeObject) = o.inquire("dual", ::coerceBoolean, false)
private fun Intent.configure(scriptRuntime: ScriptRuntime, o: NativeObject): Intent {
val intent = this
if (!o.prop("url").isJsNullish()) {
o.put("data", o, parseIntentUrl(scriptRuntime, o))
}
if (!o.prop("package").isJsNullish()) {
if (o.prop("packageName").isJsNullish()) {
o.put("packageName", o, o.prop("package"))
}
} else {
if (!o.prop("packageName").isJsNullish()) {
o.put("package", o, o.prop("packageName"))
}
}
if (!o.prop("packageName").isJsNullish()) {
val k = Context.toString(o.prop("packageName"))
if (k in presetPackageNames) {
o.defineProp("packageName", presetPackageNames[k])
}
if (!o.prop("className").isJsNullish()) {
intent.setClassName(coerceString(o.prop("packageName")), parseClassName(o))
} else {
// @Hint by SuperMonster003 on Jun 23, 2020.
// ! the Intent can only match the components
// ! in the given application package with setPackage().
// ! Otherwise, if there's more than one app that can handle the intent,
// ! the system presents the user with a dialog to pick which app to use.
// ! zh-CN:
// ! Intent 只能匹配通过 setPackage() 设置的给定应用包中的组件.
// ! 否则, 如果有多个应用可以处理该 Intent,
// ! 系统会向用户展示一个对话框, 让用户选择要使用哪个应用.
intent.setPackage(coerceString(o.prop("packageName")))
}
}
if (o.prop("extras") is NativeObject) {
(o.prop("extras") as NativeObject).entries.forEach { entry ->
val (key, value) = entry
RhinoUtils.putExtraForIntent(intent, key, value)
}
}
if (!o.prop("category").isJsNullish()) {
if (o.prop("category") is Iterable<*>) {
(o.prop("category") as Iterable<*>).forEach { cat ->
intent.addCategory(Context.toString(cat))
}
} else {
intent.addCategory(Context.toString(o.prop("category")))
}
}
if (!o.prop("action").isJsNullish()) {
intent.setAction(parseIntentAction(o.prop("action")))
}
if (!o.prop("flags").isJsNullish()) {
intent.setFlags(parseIntentFlags(o.prop("flags")))
}
if (!o.prop("type").isJsNullish()) {
if (!o.prop("data").isJsNullish()) {
intent.setDataAndType(parseUriRhinoWithRuntime(scriptRuntime, o.prop("data")), Context.toString(o.prop("type")))
} else {
intent.setType(Context.toString(o.prop("type")))
}
} else {
if (!o.prop("data").isJsNullish()) {
intent.setData(Uri.parse(Context.toString(o.prop("data"))))
}
}
return intent
}
}
}

View File

@@ -7,11 +7,13 @@ import org.autojs.autojs.extension.FlexibleArray
import org.autojs.autojs.runtime.ScriptRuntime
import org.autojs.autojs.runtime.api.augment.Augmentable
import org.autojs.autojs.runtime.exception.ShouldNeverHappenException
import org.autojs.autojs.util.RhinoUtils.UNDEFINED
import org.autojs.autojs.util.RhinoUtils.coerceFunction
import org.autojs.autojs.util.RhinoUtils.coerceLongNumber
import org.autojs.autojs.util.RhinoUtils.coerceNumber
import org.autojs.autojs6.R
import org.mozilla.javascript.BaseFunction
import org.mozilla.javascript.Undefined
@Suppress("unused", "UNUSED_PARAMETER")
open class Timers(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
@@ -89,10 +91,11 @@ open class Timers(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
@JvmStatic
@RhinoRuntimeFunctionInterface
fun loop(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Unit = ensureArgumentsIsEmpty(args) {
fun loop(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsIsEmpty(args) {
AutoJs.instance.globalConsole.warn("")
AutoJs.instance.globalConsole.warn(AutoJs.instance.applicationContext.getString(R.string.error_abandoned_method, "loop"))
AutoJs.instance.globalConsole.warn("")
UNDEFINED
}
@JvmStatic