diff --git a/README.md b/README.md index f1fbd540..3a5080a7 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,38 @@ [comment]: <> "Version history only shows last 3 versions" +# v6.3.1 + +###### 2023/05/26 + +* `新增` 发布通知权限及主页抽屉开关 _[`issue #55`](http://issues.autojs6.com/55)_ +* `新增` UI 模式支持简单的 Android 布局解析 (参阅 示例代码 > 布局 > 简单安卓布局) +* `新增` UI 模式增加 console / imagebutton / ratingbar / switch / textclock / togglebutton 等控件 +* `新增` UI 模式控件的颜色色值支持 [OmniColor](https://docs.autojs6.com/#/omniTypes?id=omnicolor) 类型 (如 color="orange") +* `新增` UI 模式的控件完全支持 attr 方法设置控件属性 (如 ui.text.attr('color', 'blue')) +* `新增` UI 模式控件支持布尔类型属性值的缺省形式 (如 clickable="true" 可简写为 clickable 或 isClickable) +* `新增` button 控件支持 isColored 及 isBorderless 布尔类型属性 +* `新增` console.resetGlobalLogConfig 方法用于重置全局日志配置 +* `新增` web.newWebSocket 方法用于创建 Web Socket 实例 (参阅 项目文档 > [万维网](https://docs.autojs6.com/#/web?id=m-newwebsocket)) +* `修复` 文件管理器的文件夹排序异常 +* `修复` floaty 模块构建的浮动窗口无法调节样式及位置的问题 _[`issue #60`](http://issues.autojs6.com/60)_ +* `修复` floaty 模块构建的浮动窗口与系统状态栏重叠的问题 +* `修复` http.postMultipart 方法功能异常 _[`issue #56`](http://issues.autojs6.com/56)_ +* `修复` Android 7.x 无法运行任何脚本的问题 _[`issue #61`](http://issues.autojs6.com/61)_ +* `修复` sign.property 文件不存在时无法构建项目的问题 +* `修复` 高版本系统 AutoJs6 置于后台时可能因无前台通知权限而崩溃的问题 (API >= 33) +* `修复` 调用 console.show 方法后日志窗口点击 FAB 按钮无法清空日志的问题 +* `修复` 脚本编辑器调试时出现的 prototype 空指针异常 +* `修复` 脚本编辑器运行脚本时在缓存文件夹运行临时脚本而非先保存再在原始位置运行以避免可能的脚本内容丢失问题 +* `修复` 调整布局层次分析的层级色条宽度避免层级过多时控件名称无法显示的问题 _[`issue #46`](http://issues.autojs6.com/46)_ +* `优化` 布局分析浮动窗口增加退出按钮以关闭窗口 _[`issue #63`](http://issues.autojs6.com/63)_ +* `优化` 脚本绝对路径使用简称形式以缩减文本长度并增加可读性 +* `优化` 将 Error 替换为 Exception 避免出现异常时 AutoJs6 应用崩溃 +* `优化` 视图 (View) 绑定方式由 ButterKnife 迁移至 View Binding _[`issue #48`](http://issues.autojs6.com/48)_ +* `优化` 服务端模式非正常关闭时将于 AutoJs6 启动时自动开启 _[`issue #64`](http://issues.autojs6.com/64)_ +* `优化` 客户端模式非正常关闭时将于 AutoJs6 启动时按最近一次的历史地址自动连接 +* `优化` 部分依赖或本地库版本调整 _[`CHANGELOG.md`](http://project.autojs6.com/blob/master/app/src/main/assets/doc/CHANGELOG.md#v631)_ + # v6.3.0 ###### 2023/04/29 @@ -259,19 +291,6 @@ * `优化` 重新设计 colors 全局对象并增加 HSV / HSL 等色彩模式支持 (参阅 项目文档 > [颜色](https://docs.autojs6.com/#/color)) * `优化` 部分依赖或本地库版本调整 _[`CHANGELOG.md`](http://project.autojs6.com/blob/master/app/src/main/assets/doc/CHANGELOG.md#v620)_ -# v6.1.1 - -###### 2022/05/31 - -* `新增` 检查更新/下载更新/更新提示功能 (参阅 设置页面) (暂不支持安卓 7.x 系统) -* `修复` 应用在安卓 10 系统无法读写外部存储的问题 _[`issue #17`](http://issues.autojs6.com/17)_ -* `修复` 编辑器页面长按时可能导致应用崩溃的问题 _[`issue #18`](http://issues.autojs6.com/18)_ -* `修复` 编辑器页面长按菜单 "删除行" 和 "复制行" 功能无效的问题 -* `修复` 编辑器页面选项菜单中 "粘贴" 功能缺失的问题 -* `优化` 部分异常消息字符串资源化 (en / zh) -* `优化` 调整内容未保存对话框的按钮布局并增加颜色区分 -* `优化` 部分依赖或本地库版本调整 _[`CHANGELOG.md`](http://project.autojs6.com/blob/master/app/src/main/assets/doc/CHANGELOG.md#v611)_ - ##### 更多版本历史可参阅 * [CHANGELOG.md](http://changelog.autojs6.com) @@ -297,12 +316,12 @@ #### Android Studio 准备 -下载 `Android Studio Flamingo | 2022.2.1` 版本 (按需选择其一): +下载 `Android Studio Flamingo | 2022.2.1 Patch 2` 版本 (按需选择其一): -- [android-studio-2022.2.1.18-windows.exe](https://redirector.gvt1.com/edgedl/android/studio/install/2022.2.1.18/android-studio-2022.2.1.18-windows.exe) (1.0 GB) -- [android-studio-2022.2.1.18-windows.zip](https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2022.2.1.18/android-studio-2022.2.1.18-windows.zip) (1.0 GB) +- [android-studio-2022.2.1.20-windows.exe](https://redirector.gvt1.com/edgedl/android/studio/install/2022.2.1.20/android-studio-2022.2.1.20-windows.exe) (1.0 GB) +- [android-studio-2022.2.1.20-windows.zip](https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2022.2.1.20/android-studio-2022.2.1.20-windows.zip) (1.0 GB) -> 注: 如需下载其他版本, 或上述链接已失效, 可前往 [Android Studio 发行版本归档](https://developer.android.com/studio/archive) 页面. +> 注: 上述版本发布时间为 2023 年 5 月 24 日. 如需下载其他版本, 或上述链接已失效, 可访问 [Android Studio 发行版本归档](https://developer.android.com/studio/archive) 页面. 安装或解压上述文件, 运行 Android Studio 软件 (如 `"D:\android-studio\bin\studio64.exe"`). diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 23bd800a..0e7acac1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -21,12 +21,12 @@ plugins { dependencies /* Unclassified */ { // LeakCanary - debugImplementation("com.squareup.leakcanary:leakcanary-android:2.10") + debugImplementation("com.squareup.leakcanary:leakcanary-android:2.11") // Android supports implementation("androidx.cardview:cardview:1.0.0") implementation("androidx.multidex:multidex:2.0.1") - implementation("com.google.android.material:material:1.8.0") + implementation("com.google.android.material:material:1.9.0") // SwipeRefreshLayout implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") @@ -60,10 +60,10 @@ dependencies /* Unclassified */ { implementation(project(":libs:com.tencent.bugly.crashreport-4.0.4")) // OkHttp - implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.9") + implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.11") // Webkit - implementation("androidx.webkit:webkit:1.6.1") + implementation("androidx.webkit:webkit:1.7.0") // Gson implementation("com.google.code.gson:gson:2.10.1") @@ -76,6 +76,7 @@ dependencies /* Unclassified */ { implementation("log4j:log4j:1.2.17") // Preference + implementation("androidx.preference:preference:1.2.0") implementation("androidx.preference:preference-ktx:1.2.0") // RootShell @@ -138,10 +139,6 @@ dependencies /* Annotations */ { // JCIP Annotations implementation("net.jcip:jcip-annotations:1.0") - // ButterKnife - kapt("com.jakewharton:butterknife-compiler:10.2.3") - implementation("com.jakewharton:butterknife:10.2.3") - // EventBus implementation("org.greenrobot:eventbus:3.3.1") } @@ -218,7 +215,7 @@ dependencies /* GitHub API */ { } dependencies /* MLKit */ { - implementation("com.google.mlkit:text-recognition-chinese:16.0.0-beta6") + implementation("com.google.mlkit:text-recognition-chinese:16.0.0") } dependencies /* Auto.js Extensions */ { @@ -319,21 +316,27 @@ android { } buildTypes { - arrayOf( + val proguardFiles = arrayOf( getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro", - ).let { proguardFiles -> - getByName("release") { - isMinifyEnabled = false - proguardFiles(*proguardFiles) - signingConfig = takeIf { sign.isValid }?.let { signingConfigs.getByName("release") } - } - getByName("debug") { - isMinifyEnabled = getByName("release").isMinifyEnabled - proguardFiles(*proguardFiles) - signingConfig = getByName("release").signingConfig - } + ) + val niceSigningConfig = takeIf { sign.isValid }?.let { + signingConfigs.getByName("release") } + getByName("release") { + isMinifyEnabled = false + proguardFiles(*proguardFiles) + niceSigningConfig?.let { signingConfig = it } + } + getByName("debug") { + isMinifyEnabled = getByName("release").isMinifyEnabled + proguardFiles(*proguardFiles) + niceSigningConfig?.let { signingConfig = it } + } + } + + buildFeatures { + viewBinding = true } defaultConfig { @@ -348,7 +351,7 @@ android { ).let { arguments(it) } } } - buildConfigField("String", "VERSION_DATE", "\"${Utils.getDateString("MMM dd, yyyy", "GMT+08:00")}\"") + buildConfigField("String", "VERSION_DATE", "\"${Utils.getDateString("MMM d, yyyy", "GMT+08:00")}\"") } applicationVariants.all { diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index e008cc79..685b2d6d 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -35,6 +35,7 @@ -keep class org.greenrobot.eventbus.** { *; } -keep class * extends c -keepattributes *Annotation* +-keepattributes SourceFile,LineNumberTable # Event bus -keepclassmembers class ** { @org.greenrobot.eventbus.Subscribe ; @@ -108,6 +109,7 @@ -keepclasseswithmembers class * { public (android.content.Context, android.util.AttributeSet, int); + public (android.content.Context, android.util.AttributeSet, int, int); } # Google Play Services library -keep class * extends java.util.ListResourceBundle { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e9e3f672..49bb126c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -61,6 +61,9 @@ + + + @@ -151,7 +154,7 @@ - + - + @@ -202,16 +205,16 @@ - + - + @@ -234,7 +237,7 @@ - + diff --git a/app/src/main/assets/doc/CHANGELOG.md b/app/src/main/assets/doc/CHANGELOG.md index ba61dbdf..d2599341 100644 --- a/app/src/main/assets/doc/CHANGELOG.md +++ b/app/src/main/assets/doc/CHANGELOG.md @@ -4,6 +4,42 @@ ****** +# v6.3.1 + +###### 2023/05/26 + +* `新增` 发布通知权限及主页抽屉开关 _[`issue #55`](http://issues.autojs6.com/55)_ +* `新增` UI 模式支持简单的 Android 布局解析 (参阅 示例代码 > 布局 > 简单安卓布局) +* `新增` UI 模式增加 console / imagebutton / ratingbar / switch / textclock / togglebutton 等控件 +* `新增` UI 模式控件的颜色色值支持 [OmniColor](https://docs.autojs6.com/#/omniTypes?id=omnicolor) 类型 (如 color="orange") +* `新增` UI 模式的控件完全支持 attr 方法设置控件属性 (如 ui.text.attr('color', 'blue')) +* `新增` UI 模式控件支持布尔类型属性值的缺省形式 (如 clickable="true" 可简写为 clickable 或 isClickable) +* `新增` button 控件支持 isColored 及 isBorderless 布尔类型属性 +* `新增` console.resetGlobalLogConfig 方法用于重置全局日志配置 +* `新增` web.newWebSocket 方法用于创建 Web Socket 实例 (参阅 项目文档 > [万维网](https://docs.autojs6.com/#/web?id=m-newwebsocket)) +* `修复` 文件管理器的文件夹排序异常 +* `修复` floaty 模块构建的浮动窗口无法调节样式及位置的问题 _[`issue #60`](http://issues.autojs6.com/60)_ +* `修复` floaty 模块构建的浮动窗口与系统状态栏重叠的问题 +* `修复` http.postMultipart 方法功能异常 _[`issue #56`](http://issues.autojs6.com/56)_ +* `修复` Android 7.x 无法运行任何脚本的问题 _[`issue #61`](http://issues.autojs6.com/61)_ +* `修复` sign.property 文件不存在时无法构建项目的问题 +* `修复` 高版本系统 AutoJs6 置于后台时可能因无前台通知权限而崩溃的问题 (API >= 33) +* `修复` 调用 console.show 方法后日志窗口点击 FAB 按钮无法清空日志的问题 +* `修复` 脚本编辑器调试时出现的 prototype 空指针异常 +* `修复` 脚本编辑器运行脚本时在缓存文件夹运行临时脚本而非先保存再在原始位置运行以避免可能的脚本内容丢失问题 +* `修复` 调整布局层次分析的层级色条宽度避免层级过多时控件名称无法显示的问题 _[`issue #46`](http://issues.autojs6.com/46)_ +* `优化` 布局分析浮动窗口增加退出按钮以关闭窗口 _[`issue #63`](http://issues.autojs6.com/63)_ +* `优化` 脚本绝对路径使用简称形式以缩减文本长度并增加可读性 +* `优化` 将 Error 替换为 Exception 避免出现异常时 AutoJs6 应用崩溃 +* `优化` 视图 (View) 绑定方式由 ButterKnife 迁移至 View Binding _[`issue #48`](http://issues.autojs6.com/48)_ +* `优化` 服务端模式非正常关闭时将于 AutoJs6 启动时自动开启 _[`issue #64`](http://issues.autojs6.com/64)_ +* `优化` 客户端模式非正常关闭时将于 AutoJs6 启动时按最近一次的历史地址自动连接 +* `优化` 升级 Leakcanary 版本 2.10 -> 2.11 +* `优化` 升级 Android Material 版本 1.8.0 -> 1.9.0 +* `优化` 升级 Androidx WebKit 版本 1.6.1 -> 1.7.0 +* `优化` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.9 -> 5.0.0-alpha.11 +* `优化` 升级 MLKit Text Recognition Chinese 版本 16.0.0-beta6 -> 16.0.0 + # v6.3.0 ###### 2023/04/29 @@ -347,7 +383,7 @@ * `新增` 主页抽屉底部增加重启应用按钮 * `新增` 主页抽屉增加忽略电池优化/显示在其他应用上层等开关 * `修复` 应用初始安装后部分区域主题颜色渲染异常的问题 -* `修复` sign.property 不存在时无法 build 的问题 +* `修复` sign.property 文件不存在时无法构建项目的问题 * `修复` 定时任务面板一次性任务的月份存取错误 * `修复` 应用设置页面开关颜色不随主题变更的问题 * `修复` 无法识别打包插件及打包插件下载地址无效的问题 diff --git a/app/src/main/assets/docs/all.html b/app/src/main/assets/docs/all.html index 971fa2cc..53693bf2 100644 --- a/app/src/main/assets/docs/all.html +++ b/app/src/main/assets/docs/all.html @@ -1532,6 +1532,10 @@
  • setGlobalLogConfig(config)
  • +
  • [m] resetGlobalLogConfig +
  • [m] input @@ -2017,6 +2021,10 @@
  • newInjectableWebClient()
  • +
  • [m] newWebSocket +
  • HTTP
      @@ -2541,7 +2549,7 @@ console.log(UiObject.bounds()); /* 访问的是类 UiObject 的静态方法 boun

      OCR 特性#

      AutoJs6 的 OCR 特性是基于 Google ML Kit文字识别 API 实现的.

      -

      注: AutoJs6 的 OCR 实现源码 参考自 TonyJiangWJ 的开源项目.

      +

      注: AutoJs6 的 OCR 实现源码 参考自 TonyJiangWJ开源项目.

      参阅: 光学字符识别 (OCR) 模块

      @@ -7615,7 +7623,7 @@ ocr.recognizeText(img, [ 0, 0, 100, 150 ]).filter(text => text.includes('
      ocr.recognizeText('./picture.jpg'); /* 获取本地图像文件中的所有文本. */
       

      recognizeText(imgPath, region)#

      -

      6.3.0 Overload [4-5]/6

      +

      6.3.0 Overload 6/6

      • imgPath { string } - 图像路径
      • region { OmniRegion } - OCR 识别区域
      • @@ -10278,6 +10286,14 @@ console.timeEnd('fruit'); maxFileSize: 384 << 10, /* 384 KB. */ }); +

        [m] resetGlobalLogConfig#

        +

        resetGlobalLogConfig()#

        +

        6.3.1

        +
          +
        • returns { void }
        • +
        +

        重置全局日志写入配置.

        +

        此方法可重置 setGlobalLogConfig 的全部选项配置.

        [m] input#

        input(data, ...args)#

        ABANDONED

        @@ -10286,7 +10302,7 @@ console.timeEnd('fruit');
      • args { ...any[] } - 占位符替换参数
      • returns { void }
      -

      此方法已于 6.3.0 版本被废弃, 使用后将无任何效果.

      +

      此方法已于 6.3.1 版本被废弃, 使用后将无任何效果.

      [m] rawInput#

      rawInput(data, ...args)#

      ABANDONED

      @@ -10295,7 +10311,7 @@ console.timeEnd('fruit');
    • args { ...any[] } - 占位符替换参数
    • returns { void }
    -

    此方法已于 6.3.0 版本被废弃, 使用后将无任何效果. +

    此方法已于 6.3.1 版本被废弃, 使用后将无任何效果.

    Shell#

    @@ -13433,6 +13449,73 @@ settings.setDisplayZoomControls(false);
    /* 为 webView 对象重新设置一个新的客户端. */
     webView.setWebViewClient(newInjectableWebClient());
     
    +

    [m] newWebSocket#

    +

    newWebSocket(url)#

    +

    6.3.1 Global

    + +

    新建并返回一个 WebSocket 实例.

    +
    console.setExitOnClose(7e3).show();
    +
    +let ws = web.newWebSocket('wss://echo.websocket.events');
    +
    +ws
    +    .on('open', (res, ws) => {
    +        console.log('WebSocket 已连接');
    +    })
    +    .on('message', (message, ws) => {
    +        console.log('接收到消息');
    +        // if (message instanceof okio.ByteString) {
    +        //     console.log(`消息类型: ByteString`);
    +        // } else if (typeof message === 'string') {
    +        //     console.log(`消息类型: String`);
    +        // } else {
    +        //     throw TypeError('Should never happen');
    +        // }
    +    })
    +    .on('text', (text, ws) => {
    +        console.info('接收到文本消息:');
    +        console.info(`text: ${text}`);
    +    })
    +    .on('bytes', (bytes, ws) => {
    +        console.info('接收到字节数组消息:');
    +        console.info(`utf8: ${bytes.utf8()}`);
    +        console.info(`base64: ${bytes.base64()}`);
    +        console.info(`md5: ${bytes.md5()}`);
    +        console.info(`hex: ${bytes.hex()}`);
    +    })
    +    .on('closing', (code, reason, ws) => {
    +        console.log('WebSocket 关闭中');
    +    })
    +    .on('closed', (code, reason, ws) => {
    +        console.log('WebSocket 已关闭');
    +        console.log(`code: ${code}`);
    +        if (reason) console.log(`reason: ${reason}`);
    +    })
    +    .on('failure', (err, res, ws) => {
    +        console.error('WebSocket 连接失败');
    +        console.error(err);
    +    });
    +
    +/* 发送文本消息. */
    +ws.send('Hello WebSocket');
    +
    +/* 发送字节数组消息. */
    +ws.send(new okio.ByteString(new java.lang.String('Hello WebSocket').getBytes()));
    +
    +setTimeout(() => {
    +    console.log('断开 WebSocket');
    +
    +    /* code 支持的范围 [1000,5000). */
    +    /* 1000 表示成功操作或常规的 Socket 关闭操作. */
    +    /* 参阅 https://github.com/Luka967/websocket-close-codes */
    +    ws.close(1000, 'Closed by user');
    +}, 8e3);
    +
    +setTimeout(() => console.log('Exit'), 9e3);
    +

    HTTP#

    @@ -13441,7 +13524,7 @@ webView.setWebViewClient(newInjectableWebClient());

    Marked by SuperMonster003 on Mar 21, 2023.


    -

    http模块提供一些进行http请求的函数.

    +

    http 模块主要用于发送 HTTP 请求, 获取并解析 HTTP 响应.

    注: 与 web 模块不同, web 模块主要用于 WebView 网页的注入及客户端构建.

    @@ -13578,11 +13661,11 @@ log(res.body.string());

    选项options可以包含以下属性:

    • headers { Object } 键值对形式的HTTP头部信息. 有关HTTP头部信息, 参见菜鸟教程:HTTP响应头信息.
    • -
    • method { string } HTTP请求方法. 包括"GET", "POST", "PUT", "DELET", "PATCH".
    • +
    • method { string } HTTP请求方法. 包括"GET", "POST", "PUT", "DELETE", "PATCH".
    • contentType { string } HTTP头部信息中的"Content-Type", 表示HTTP请求的内容类型. 例如"text/plain", "application/json". 更多信息参见菜鸟教程:HTTP contentType.
    • body { string } | { Array } | { Function } HTTP请求的内容. 可以是一个字符串, 也可以是一个字节数组;或者是一个以BufferedSink为参数的函数.
    -

    该函数是get, post, postJson等函数的基础函数. 因此除非是PUT, DELET等请求, 或者需要更高定制的HTTP请求, 否则直接使用get, post, postJson等函数会更加方便.

    +

    该函数是get, post, postJson等函数的基础函数. 因此除非是PUT, DELETE等请求, 或者需要更高定制的HTTP请求, 否则直接使用get, post, postJson等函数会更加方便.

    [m] buildRequest#

    buildRequest(url, options)#

    ... ... diff --git a/app/src/main/assets/docs/apiLevel.html b/app/src/main/assets/docs/apiLevel.html index 6c89e771..4af8c999 100644 --- a/app/src/main/assets/docs/apiLevel.html +++ b/app/src/main/assets/docs/apiLevel.html @@ -189,12 +189,20 @@ +35 (?) +Android 15 +VANILLA_ICE_CREAM +15 +Vanilla Ice Cream +Q3, 2024 (?) + + 34 Android 14 -? +UPSIDE_DOWN_CAKE 14 Upside Down Cake -Feb 8, 2023 +Q3, 2023 (?) 33 @@ -475,6 +483,7 @@

    要求设备 API 级别不低于指定值:

    /* 在 API 级别低于 30 的设备上将抛出异常. */
     runtime.requiresApi(30);
    +runtime.requiresApi(util.versionCodes.R); /* 效果同上. */
     

    注: AutoJs6 安装及使用需满足的最低 API 级别为 24 (7.0) [N].

    diff --git a/app/src/main/assets/docs/changelog.html b/app/src/main/assets/docs/changelog.html index 8bda12ee..8216ddf2 100644 --- a/app/src/main/assets/docs/changelog.html +++ b/app/src/main/assets/docs/changelog.html @@ -166,6 +166,7 @@

    目录

  • +
  • [m] resetGlobalLogConfig +
  • [m] input @@ -1174,6 +1178,14 @@ console.timeEnd('fruit'); maxFileSize: 384 << 10, /* 384 KB. */ }); +

    [m] resetGlobalLogConfig#

    +

    resetGlobalLogConfig()#

    +

    6.3.1

    +
      +
    • returns { void }
    • +
    +

    重置全局日志写入配置.

    +

    此方法可重置 setGlobalLogConfig 的全部选项配置.

    [m] input#

    input(data, ...args)#

    ABANDONED

    @@ -1182,7 +1194,7 @@ console.timeEnd('fruit');
  • args { ...any[] } - 占位符替换参数
  • returns { void }
  • -

    此方法已于 6.3.0 版本被废弃, 使用后将无任何效果.

    +

    此方法已于 6.3.1 版本被废弃, 使用后将无任何效果.

    [m] rawInput#

    rawInput(data, ...args)#

    ABANDONED

    @@ -1191,7 +1203,7 @@ console.timeEnd('fruit');
  • args { ...any[] } - 占位符替换参数
  • returns { void }
  • -

    此方法已于 6.3.0 版本被废弃, 使用后将无任何效果.

    +

    此方法已于 6.3.1 版本被废弃, 使用后将无任何效果.

    diff --git a/app/src/main/assets/docs/consoleBuildOptionsType.html b/app/src/main/assets/docs/consoleBuildOptionsType.html index 2d575ce0..e5a94486 100644 --- a/app/src/main/assets/docs/consoleBuildOptionsType.html +++ b/app/src/main/assets/docs/consoleBuildOptionsType.html @@ -309,7 +309,8 @@ console.build({ titleIconsTint: 'green' }).show(); console.build({ contentTextSize: 18 }).show();

    [p?] contentTextColor#

    -
      +

      Overload 1/2

      +
      • {{
      • -
      • } | OmniColor } - 浮动窗口日志文本字体颜色
      • +
      • }} - 浮动窗口日志文本字体颜色
      -

    设置控制台浮动窗口的日志文本字体颜色, 按日志等级设置一个或多个不同的字体颜色.

    +

    设置控制台浮动窗口的日志文本字体颜色, 按日志等级设置一个或多个不同的字体颜色.

    /* 设置 LOG 等级日志字体颜色为深橙色. */
     console.build({ contentTextColor: { log: 'dark-orange' } }).show();
     console.log('content text color test for console.log');
    @@ -344,7 +345,11 @@ console.build({
         console[fName].call(console, `content text color test for console.${fName}`);
     });
     
    -

    如果希望不区分日志等级, 统一设置所有日志的文本颜色, 可参考下述示例:

    +

    Overload 2/2

    +
      +
    • { OmniColor } - 浮动窗口日志文本统一字体颜色
    • +
    +

    使用 { contentTextColor: OmniColor } 时, 不区分日志等级, 统一设置所有日志的文本颜色:

    /* 所有日志本文的颜色统一设置为深绿色. */
     console.build({
         contentTextColor: 'dark-green',
    diff --git a/app/src/main/assets/docs/http.html b/app/src/main/assets/docs/http.html
    index 670594f7..9b0db242 100644
    --- a/app/src/main/assets/docs/http.html
    +++ b/app/src/main/assets/docs/http.html
    @@ -203,7 +203,7 @@
     

    Marked by SuperMonster003 on Mar 21, 2023.


    -

    http模块提供一些进行http请求的函数.

    +

    http 模块主要用于发送 HTTP 请求, 获取并解析 HTTP 响应.

    注: 与 web 模块不同, web 模块主要用于 WebView 网页的注入及客户端构建.

    @@ -340,11 +340,11 @@ log(res.body.string());

    选项options可以包含以下属性:

    • headers { Object } 键值对形式的HTTP头部信息. 有关HTTP头部信息, 参见菜鸟教程:HTTP响应头信息.
    • -
    • method { string } HTTP请求方法. 包括"GET", "POST", "PUT", "DELET", "PATCH".
    • +
    • method { string } HTTP请求方法. 包括"GET", "POST", "PUT", "DELETE", "PATCH".
    • contentType { string } HTTP头部信息中的"Content-Type", 表示HTTP请求的内容类型. 例如"text/plain", "application/json". 更多信息参见菜鸟教程:HTTP contentType.
    • body { string } | { Array } | { Function } HTTP请求的内容. 可以是一个字符串, 也可以是一个字节数组;或者是一个以BufferedSink为参数的函数.
    -

    该函数是get, post, postJson等函数的基础函数. 因此除非是PUT, DELET等请求, 或者需要更高定制的HTTP请求, 否则直接使用get, post, postJson等函数会更加方便.

    +

    该函数是get, post, postJson等函数的基础函数. 因此除非是PUT, DELETE等请求, 或者需要更高定制的HTTP请求, 否则直接使用get, post, postJson等函数会更加方便.

    [m] buildRequest#

    buildRequest(url, options)#

    ... ...

    diff --git a/app/src/main/assets/docs/ocr.html b/app/src/main/assets/docs/ocr.html index 930a541c..bcbe8676 100644 --- a/app/src/main/assets/docs/ocr.html +++ b/app/src/main/assets/docs/ocr.html @@ -316,7 +316,7 @@ ocr.recognizeText(img, [ 0, 0, 100, 150 ]).filter(text => text.includes('
    ocr.recognizeText('./picture.jpg'); /* 获取本地图像文件中的所有文本. */
     

    recognizeText(imgPath, region)#

    -

    6.3.0 Overload [4-5]/6

    +

    6.3.0 Overload 6/6

    • imgPath { string } - 图像路径
    • region { OmniRegion } - OCR 识别区域
    • diff --git a/app/src/main/assets/docs/omniTypes.html b/app/src/main/assets/docs/omniTypes.html index 5bd04e7f..161b0813 100644 --- a/app/src/main/assets/docs/omniTypes.html +++ b/app/src/main/assets/docs/omniTypes.html @@ -240,6 +240,35 @@ console.show(); /* 显示控制台悬浮窗. */ +

      OmniColor 不仅可用于参数传入方法中, 还可以作为 XML 元素的属性值:

      +
      'ui';
      +
      +ui.layout(<vertical>
      +    <button text="click to start" color="#006400"/>
      +</vertical>);
      +
      +

      上述示例设置按钮布局的文字颜色为深绿色, 使用了 ColorHex 作为颜色值.

      +

      使用 ColorName 作为颜色值也可达到相同的效果:

      +
      'ui';
      +
      +ui.layout(<vertical>
      +    <button text="click to start" color="dark-green"/>
      +</vertical>);
      +
      +

      使用 ColorInt 作为颜色值同样可以达到相同的效果:

      +
      'ui';
      +
      +ui.layout(<vertical>
      +    <button text="click to start" color="-16751616"/>
      +</vertical>);
      +
      +

      如需使用主题色作为颜色值, 需要使用一对花括号以及绑定全局作用域的表达式:

      +
      'ui';
      +
      +ui.layout(<vertical>
      +    <button text="click to start" color="{{autojs.themeColor}}"/>
      +</vertical>);
      +

      OmniIntent#

      Intent 聚合类型.

      diff --git a/app/src/main/assets/docs/qa.html b/app/src/main/assets/docs/qa.html index 29248eee..5c9b2c8d 100644 --- a/app/src/main/assets/docs/qa.html +++ b/app/src/main/assets/docs/qa.html @@ -275,7 +275,7 @@

      OCR 特性#

      AutoJs6 的 OCR 特性是基于 Google ML Kit文字识别 API 实现的.

      -

      注: AutoJs6 的 OCR 实现源码 参考自 TonyJiangWJ 的开源项目.

      +

      注: AutoJs6 的 OCR 实现源码 参考自 TonyJiangWJ开源项目.

      参阅: 光学字符识别 (OCR) 模块

      diff --git a/app/src/main/assets/docs/web.html b/app/src/main/assets/docs/web.html index abbd733e..095c2afb 100644 --- a/app/src/main/assets/docs/web.html +++ b/app/src/main/assets/docs/web.html @@ -175,6 +175,10 @@
    • newInjectableWebClient()
    • +
    • [m] newWebSocket +
    • @@ -287,6 +291,73 @@ settings.setDisplayZoomControls(false);

      新建并返回一个 InjectableWebClient (可 注入WebViewClient) 实例.

      /* 为 webView 对象重新设置一个新的客户端. */
       webView.setWebViewClient(newInjectableWebClient());
      +
      +

      [m] newWebSocket#

      +

      newWebSocket(url)#

      +

      6.3.1 Global

      + +

      新建并返回一个 WebSocket 实例.

      +
      console.setExitOnClose(7e3).show();
      +
      +let ws = web.newWebSocket('wss://echo.websocket.events');
      +
      +ws
      +    .on('open', (res, ws) => {
      +        console.log('WebSocket 已连接');
      +    })
      +    .on('message', (message, ws) => {
      +        console.log('接收到消息');
      +        // if (message instanceof okio.ByteString) {
      +        //     console.log(`消息类型: ByteString`);
      +        // } else if (typeof message === 'string') {
      +        //     console.log(`消息类型: String`);
      +        // } else {
      +        //     throw TypeError('Should never happen');
      +        // }
      +    })
      +    .on('text', (text, ws) => {
      +        console.info('接收到文本消息:');
      +        console.info(`text: ${text}`);
      +    })
      +    .on('bytes', (bytes, ws) => {
      +        console.info('接收到字节数组消息:');
      +        console.info(`utf8: ${bytes.utf8()}`);
      +        console.info(`base64: ${bytes.base64()}`);
      +        console.info(`md5: ${bytes.md5()}`);
      +        console.info(`hex: ${bytes.hex()}`);
      +    })
      +    .on('closing', (code, reason, ws) => {
      +        console.log('WebSocket 关闭中');
      +    })
      +    .on('closed', (code, reason, ws) => {
      +        console.log('WebSocket 已关闭');
      +        console.log(`code: ${code}`);
      +        if (reason) console.log(`reason: ${reason}`);
      +    })
      +    .on('failure', (err, res, ws) => {
      +        console.error('WebSocket 连接失败');
      +        console.error(err);
      +    });
      +
      +/* 发送文本消息. */
      +ws.send('Hello WebSocket');
      +
      +/* 发送字节数组消息. */
      +ws.send(new okio.ByteString(new java.lang.String('Hello WebSocket').getBytes()));
      +
      +setTimeout(() => {
      +    console.log('断开 WebSocket');
      +
      +    /* code 支持的范围 [1000,5000). */
      +    /* 1000 表示成功操作或常规的 Socket 关闭操作. */
      +    /* 参阅 https://github.com/Luka967/websocket-close-codes */
      +    ws.close(1000, 'Closed by user');
      +}, 8e3);
      +
      +setTimeout(() => console.log('Exit'), 9e3);
       
      diff --git a/app/src/main/assets/init.js b/app/src/main/assets/init.js index ce437e08..e4481916 100644 --- a/app/src/main/assets/init.js +++ b/app/src/main/assets/init.js @@ -1,7 +1,5 @@ // noinspection JSUnusedGlobalSymbols,NpmUsedModulesInstalled,JSUnusedLocalSymbols -'use strict'; - // @Caution by SuperMonster003 on Apr 19, 2022. // ! Do not declare with const because variable has already // ! declared globally in RhinoJavaScriptEngine.kt. @@ -15,9 +13,11 @@ let RootMode = org.autojs.autojs.util.RootUtils.RootMode; let Pref = org.autojs.autojs.pref.Pref; let Shell = org.autojs.autojs.runtime.api.Shell; let Intent = global.Intent = android.content.Intent; +let Context = global.Context = android.content.Context; let PendingIntent = android.app.PendingIntent; let Toast = android.widget.Toast; let KeyEvent = android.view.KeyEvent; +let MotionEvent = android.view.MotionEvent; let Version = Packages.io.github.g00fy2.versioncompare.Version; let Image = org.autojs.autojs.core.image.ImageWrapper; let ColorTable = org.autojs.autojs.core.image.ColorTable; @@ -40,17 +40,59 @@ let GlobalAppContext = org.autojs.autojs.app.GlobalAppContext; let DisplayUtils = org.autojs.autojs.util.DisplayUtils; let StringUtils = org.autojs.autojs.util.StringUtils; let ColorUtils = org.autojs.autojs.util.ColorUtils; +let TextUtils = org.autojs.autojs.util.TextUtils; let ProxyObject = org.autojs.autojs.rhino.ProxyObject; let ProxyJavaObject = org.autojs.autojs.rhino.ProxyJavaObject; let NotificationManager = android.app.NotificationManager; let NotificationCompat = Packages.androidx.core.app.NotificationCompat; +let SecurityException = java.lang.SecurityException; +let Locale = java.util.Locale; let URI = java.net.URI; let File = java.io.File; +/* Global View classes. */ + +let JsAppBarLayout = org.autojs.autojs.core.ui.widget.JsAppBarLayout; +let JsButton = org.autojs.autojs.core.ui.widget.JsButton; +let JsCanvasView = org.autojs.autojs.core.ui.widget.JsCanvasView; +let JsCardView = org.autojs.autojs.core.ui.widget.JsCardView; +let JsCheckBox = org.autojs.autojs.core.ui.widget.JsCheckBox; +let JsConsoleView = org.autojs.autojs.core.ui.widget.JsConsoleView; +let JsDatePicker = org.autojs.autojs.core.ui.widget.JsDatePicker; +let JsDrawerLayout = org.autojs.autojs.core.ui.widget.JsDrawerLayout; +let JsEditText = org.autojs.autojs.core.ui.widget.JsEditText; +let JsFloatingActionButton = org.autojs.autojs.core.ui.widget.JsFloatingActionButton; +let JsFrameLayout = org.autojs.autojs.core.ui.widget.JsFrameLayout; +let JsGridView = org.autojs.autojs.core.ui.widget.JsGridView; +let JsImageButton = org.autojs.autojs.core.ui.widget.JsImageButton; +let JsImageView = org.autojs.autojs.core.ui.widget.JsImageView; +let JsLinearLayout = org.autojs.autojs.core.ui.widget.JsLinearLayout; +let JsListView = org.autojs.autojs.core.ui.widget.JsListView; +let JsProgressBar = org.autojs.autojs.core.ui.widget.JsProgressBar; +let JsRadioButton = org.autojs.autojs.core.ui.widget.JsRadioButton; +let JsRadioGroup = org.autojs.autojs.core.ui.widget.JsRadioGroup; +let JsRatingBar = org.autojs.autojs.core.ui.widget.JsRatingBar; +let JsRelativeLayout = org.autojs.autojs.core.ui.widget.JsRelativeLayout; +let JsScrollView = org.autojs.autojs.core.ui.widget.JsScrollView; +let JsSeekBar = org.autojs.autojs.core.ui.widget.JsSeekBar; +let JsSpinner = org.autojs.autojs.core.ui.widget.JsSpinner; +let JsSwitch = org.autojs.autojs.core.ui.widget.JsSwitch; +let JsTabLayout = org.autojs.autojs.core.ui.widget.JsTabLayout; +let JsTextClock = org.autojs.autojs.core.ui.widget.JsTextClock; +let JsTextView = android.os.Build.VERSION.SDK_INT < 26 /* Android API 26 (8.0) [O] */ + ? org.autojs.autojs.core.ui.widget.JsTextViewLegacy + : org.autojs.autojs.core.ui.widget.JsTextView; +let JsTimePicker = org.autojs.autojs.core.ui.widget.JsTimePicker; +let JsToggleButton = org.autojs.autojs.core.ui.widget.JsToggleButton; +let JsToolbar = org.autojs.autojs.core.ui.widget.JsToolbar; +let JsViewPager = org.autojs.autojs.core.ui.widget.JsViewPager; +let JsWebView = org.autojs.autojs.core.ui.widget.JsWebView; + /* Global assignment. */ Object.assign(this, { io: Packages.io, + okio: Packages.okio, de: Packages.de, ezy: Packages.ezy, kotlin: Packages.kotlin, @@ -264,8 +306,11 @@ Object.assign(this, { if (typeof global[module] === 'object') { if (!(Object.hasOwn(global[module], 'toString'))) { // noinspection JSPotentiallyInvalidConstructorUsage - if (typeof global[module].constructor.prototype.toString !== 'function') { - global[module].toString = () => module; + let prototype = global[module].constructor.prototype; + if (prototype !== undefined) /* For AutoJs6 debugger. */ { + if (typeof prototype.toString !== 'function') { + global[module].toString = () => module; + } } } } @@ -415,6 +460,9 @@ Object.assign(this, { [ 'engines', 'continuation', 'http' ], [ 'images', 'colors', 'dialogs' ], + /* ! http < web */ + [ 'web' ], + /* ! files < i18n */ /* ! i18n < selector */ [ 'i18n', 'selector' ], @@ -438,7 +486,7 @@ Object.assign(this, { /* Safe to put last regardless of the order, no guarantee ;). */ [ 'floaty', 'storages', 'device', 'recorder', 'toast' ], - [ 'media', 'sensors', 'web', 'events', 'base64', 'notice' ], + [ 'media', 'sensors', 'events', 'base64', 'notice' ], /* Last but not the least */ [ 'globals' ], diff --git a/app/src/main/assets/js-beautify/beautify.js b/app/src/main/assets/js-beautify/beautify.js index 7252bd6a..9d42fd4a 100644 --- a/app/src/main/assets/js-beautify/beautify.js +++ b/app/src/main/assets/js-beautify/beautify.js @@ -350,7 +350,6 @@ var MODE = { }; function Beautifier(js_source_text, options) { - "use strict"; var output; var tokens = [], token_pos; diff --git a/app/src/main/assets/modules/__colors__.js b/app/src/main/assets/modules/__colors__.js index db6b1428..953d84bc 100644 --- a/app/src/main/assets/modules/__colors__.js +++ b/app/src/main/assets/modules/__colors__.js @@ -62,6 +62,9 @@ module.exports = function (scriptRuntime, scope) { Color.prototype = { constructor: Color, + toString() { + return this.digest(); + }, digest() { return colors.digest.apply(colors, [ this.color ].concat(Array.from(arguments))); }, @@ -78,6 +81,9 @@ module.exports = function (scriptRuntime, scope) { this.color = colors.setAlpha(this.color, alpha); return this; }, + setAlphaRelative(percentage) { + return this.setAlpha(this.getAlpha() * _.parseRelativePercentage(percentage)); + }, getAlpha() { return colors.alpha(this.color); }, @@ -98,6 +104,9 @@ module.exports = function (scriptRuntime, scope) { this.color = colors.setRed(this.color, red); return this; }, + setRedRelative(percentage) { + return this.setRed(this.getRed() * _.parseRelativePercentage(percentage)); + }, getRed() { return colors.red(this.color); }, @@ -118,6 +127,9 @@ module.exports = function (scriptRuntime, scope) { this.color = colors.setGreen(this.color, green); return this; }, + setGreenRelative(percentage) { + return this.setGreen(this.getGreen() * _.parseRelativePercentage(percentage)); + }, getGreen() { return colors.green(this.color); }, @@ -138,6 +150,9 @@ module.exports = function (scriptRuntime, scope) { this.color = colors.setBlue(this.color, blue); return this; }, + setBlueRelative(percentage) { + return this.setBlue(this.getBlue() * _.parseRelativePercentage(percentage)); + }, getBlue() { return colors.blue(this.color); }, @@ -267,6 +282,9 @@ module.exports = function (scriptRuntime, scope) { let [ r, g, b ] = this.toRgb(color); return this.toInt(this.argb(alpha, r, g, b)); }, + setAlphaRelative(color, percentage) { + return this.setAlpha(color, this.getAlpha(color) * _.parseRelativePercentage(percentage)); + }, removeAlpha(color) { return this.setAlpha(color, 0); }, @@ -293,6 +311,9 @@ module.exports = function (scriptRuntime, scope) { let [ a, , g, b ] = this.toArgb(color); return this.toInt(this.argb(a, red, g, b)); }, + setRedRelative(color, percentage) { + return this.setRed(color, this.getRed(color) * _.parseRelativePercentage(percentage)); + }, removeRed(color) { return this.setRed(color, 0); }, @@ -319,6 +340,9 @@ module.exports = function (scriptRuntime, scope) { let [ a, r, , b ] = this.toArgb(color); return this.toInt(this.argb(a, r, green, b)); }, + setGreenRelative(color, percentage) { + return this.getGreen(color, this.getGreen(color) * _.parseRelativePercentage(percentage)); + }, removeGreen(color) { return this.setGreen(color, 0); }, @@ -345,75 +369,27 @@ module.exports = function (scriptRuntime, scope) { let [ a, r, g ] = this.toArgb(color); return this.toInt(this.argb(a, r, g, blue)); }, + setBlueRelative(color, percentage) { + return this.setBlue(color, this.getBlue(color) * _.parseRelativePercentage(percentage)); + }, removeBlue(color) { return this.setBlue(color, 0); }, toInt(color) { - try { - return _.parseColor(typeof color === 'number' ? _.toJavaIntegerRange(color) : this.toFullHex(color)); - } catch (e) { - scriptRuntime.console.error(`Passed color: ${color}`); - throw Error(e + '\n' + e.stack); + if (color instanceof _.Color) { + color = color.color; } + return ColorUtils.toInt.apply(ColorUtils, [ color ]); }, toHex(color, alphaOrLength) { - let [ _ignoredArg0, arg1 /* alpha | length */ ] = arguments; - - if (color instanceof _.Color) { - return this.toHex.apply(this, [ color.color ].concat(Array.from(arguments).slice(1))); - } - if (color instanceof ThemeColor) { - return this.toHex.apply(this, [ color.getColorPrimary() ].concat(Array.from(arguments).slice(1))); - } - if (typeof color === 'number') { - color = rtColors.toString(_.toJavaIntegerRange(color)); + if (isNullish(alphaOrLength)) { + return ColorUtils.toHex.apply(ColorUtils, [ color ]); } else { - color = String(color); + return ColorUtils.toHex.apply(ColorUtils, [ color, alphaOrLength ]); } - if (color.startsWith('#')) { - if (color.length === 4) { - color = color.replace(/(#)(\w)(\w)(\w)/, '$1$2$2$3$3$4$4'); - } - } else { - if (color === parseInt(color).toString()) { - return this.toHex.apply(this, [ parseInt(color) ].concat(Array.from(arguments).slice(1))); - } - let colorByName = ColorTable.getColorByName(color, true); - if (colorByName !== null) { - return this.toHex.apply(this, [ colorByName.intValue() ].concat(Array.from(arguments).slice(1))); - } - } - if (!/^#[A-F\d]{3}([A-F\d]{3}([A-F\d]{2})?)?$/i.test(color)) { - throw TypeError(`Invalid color string format: ${color}`); - } - return ( /* @IIFE(toColorHex) */ () => { - if (arg1 /* alpha */ === true || arg1 /* alpha */ === 'keep' || arg1 /* length */ === 8) { - if (color.length === 7) { - color = `#FF${color.slice(1)}`; - } - return color; - } - if (arg1 /* alpha */ === false || arg1 /* alpha */ === 'none' || arg1 /* length */ === 6) { - return `#${color.slice(-6)}`; - } - if (arg1 /* length */ === 3) { - if (!/^#(?:([A-F\d]){2})?([A-F\d])\2([A-F\d])\3([A-F\d])\4$/i.test(color)) { - throw TypeError(`Can't convert color ${color} to #RGB with unexpected color format.`); - } - let [ r, g, b ] = [ color.slice(-6, -5), color.slice(-4, -3), color.slice(-2, -1) ]; - return `#${r}${g}${b}`; - } - if (arg1 /* alpha */ === undefined || arg1 /* alpha */ === 'auto') { - return /^#FF([A-F\d]){6}$/i.test(color) ? `#${color.slice(3)}` : color; - } - throw TypeError('Unknown type of alpha for colors.toString()'); - })().toUpperCase(); }, - /** - * Color to full hex like '#BF110523'. - */ toFullHex(color) { - return this.toHex(color, 8); + return ColorUtils.toFullHex.apply(ColorUtils, [ color ]); }, /** * Get hex code string of a color. @@ -870,15 +846,12 @@ module.exports = function (scriptRuntime, scope) { parseNumber(num, def) { return typeof num === 'number' ? num : typeof def === 'function' ? def() : def || 0; }, - /** - * @param {number|string} color - * @returns {number} - */ - parseColor(color) { - if (typeof color === 'string') { - return rtColors.parseColor(color); + parseRelativePercentage(percentage) { + let p = Numberx.parseAny(percentage); + if (isNaN(p) || p < 0) { + throw TypeError(`Relative percentage must be in range 0..255, instead of ${percentage}`) } - return color; + return p; }, }; diff --git a/app/src/main/assets/modules/__console__.js b/app/src/main/assets/modules/__console__.js index c4646c55..cc605737 100644 --- a/app/src/main/assets/modules/__console__.js +++ b/app/src/main/assets/modules/__console__.js @@ -11,8 +11,9 @@ let { files, util, s13n } = global; module.exports = function (scriptRuntime, scope) { const Log = android.util.Log; const Level = org.apache.log4j.Level; - const ConsoleUtils = org.autojs.autojs.util.ConsoleUtils; + const LogManager = org.apache.log4j.LogManager; const LogConfigurator = de.mindpipe.android.logging.log4j.LogConfigurator; + const ConsoleUtils = org.autojs.autojs.util.ConsoleUtils; // noinspection JSValidateTypes /** @type {org.autojs.autojs.core.console.GlobalConsole} */ @@ -92,8 +93,14 @@ module.exports = function (scriptRuntime, scope) { Boolean(typeof value === 'function' ? value() : value), message || util.getClassName(java.lang.AssertionError)); }, - input(data, param) { - return eval(String(this.rawInput(data, param))); + input() { + // @Abandoned by SuperMonster003 as of May 3, 2023. + // return eval(String(this.rawInput(data, param))); + throw Error(context.getString(R.strings.error_abandoned_method, 'console.input')); + }, + rawInput() { + // @Abandoned by SuperMonster003 as of May 3, 2023. + throw Error(context.getString(R.strings.error_abandoned_method, 'console.rawInput')); }, log() { rtConsole.log(util.format.apply(util, arguments)); @@ -247,6 +254,9 @@ module.exports = function (scriptRuntime, scope) { configurator.setResetConfiguration(_.parseOption(config.resetConfiguration, true)); configurator.configure(); }, + resetGlobalLogConfig() { + LogManager.getLoggerRepository().resetConfiguration(); + }, launch() { ConsoleUtils.launch(); }, diff --git a/app/src/main/assets/modules/__globals__.js b/app/src/main/assets/modules/__globals__.js index ee4e63e2..6841a509 100644 --- a/app/src/main/assets/modules/__globals__.js +++ b/app/src/main/assets/modules/__globals__.js @@ -484,6 +484,11 @@ module.exports = function (runtime, scope) { delete this.$appropriateProtect; }, }, + legacies: { + isObjectSpecies(o) { + return species.isObject(o); + }, + }, ensureNonUiThread() { if (ui.isUiThread()) { throw Error('不能在ui线程执行阻塞操作,请在子线程或子脚本执行,或者使用setInterval循环检测当前activity和package.'); @@ -533,7 +538,7 @@ module.exports = function (runtime, scope) { }, }; - Object.assign(scope, _.extensions); + Object.assign(scope, _.extensions, _.legacies); // Object.keys(_.extensions) // .filter(key => !key.startsWith('$')) diff --git a/app/src/main/assets/modules/__http__.js b/app/src/main/assets/modules/__http__.js index 34a52bab..5b7dd10f 100644 --- a/app/src/main/assets/modules/__http__.js +++ b/app/src/main/assets/modules/__http__.js @@ -1,4 +1,4 @@ -// noinspection JSUnusedGlobalSymbols +// noinspection JSUnusedGlobalSymbols,JSUnusedLocalSymbols,UnnecessaryLocalVariableJS /* Overwritten protection. */ @@ -10,7 +10,8 @@ let { ui } = global; * @return {Internal.Http} */ module.exports = function (scriptRuntime, scope) { - const PFile = org.autojs.pio.PFile; + + const PFile = org.autojs.autojs.pio.PFile; const Request = okhttp3.Request; const RequestBody = okhttp3.RequestBody; const MultipartBody = okhttp3.MultipartBody; @@ -31,6 +32,13 @@ module.exports = function (scriptRuntime, scope) { Http.prototype = { constructor: Http, __okhttp__: new MutableOkHttp(), + /** + * @example + * http.client() === http.client(); // true + */ + client() { + return this.__okhttp__.client(); + }, /** * @param {string} url * @param {Http.RequestBuilderOptions} [options] @@ -83,6 +91,7 @@ module.exports = function (scriptRuntime, scope) { return body; } if (typeof body === 'string') { + // noinspection JSDeprecatedSymbols return RequestBody.create(MediaType.parse(this.options.contentType), body); } if (typeof body === 'function') { @@ -119,6 +128,7 @@ module.exports = function (scriptRuntime, scope) { let file = new PFile(path); fileName = fileName || file.getName(); mimeType = mimeType || this.parseMimeType(file.getExtension()); + // noinspection JSDeprecatedSymbols let requestBody = RequestBody.create(MediaType.parse(mimeType), file); builder.addFormDataPart(key, fileName, requestBody); }); diff --git a/app/src/main/assets/modules/__notice__.js b/app/src/main/assets/modules/__notice__.js index 1e478fb2..d5adcb91 100644 --- a/app/src/main/assets/modules/__notice__.js +++ b/app/src/main/assets/modules/__notice__.js @@ -14,7 +14,13 @@ module.exports = function (scriptRuntime, scope) { const BigTextStyle = androidx.core.app.NotificationCompat.BigTextStyle; const Notification = android.app.Notification; const NotificationManager = android.app.NotificationManager; - const NotificationManagerCompat = androidx.core.app.NotificationManagerCompat; + + // @Caution by SuperMonster003 on May 6, 2023. + // ! On device running with Android 7.x, + // ! importing NotificationManagerCompat will cause java.lang.ClassNotFoundException: + // ! Didn't find class "android.app.NotificationChannel" on path: DexPathList ... + + // const NotificationManagerCompat = androidx.core.app.NotificationManagerCompat; const configDefaults = { /** @@ -511,7 +517,9 @@ module.exports = function (scriptRuntime, scope) { if (!isNullish(id)) { let niceId = Number(id); if (!isNaN(niceId)) { - NotificationManagerCompat.from(context).cancel(niceId); + if (util.version.sdkInt >= util.versionCodes.O) { + androidx.core.app.NotificationManagerCompat.from(context).cancel(niceId); + } } } }, diff --git a/app/src/main/assets/modules/__timers__.js b/app/src/main/assets/modules/__timers__.js index 391b52ab..e4bc6c37 100644 --- a/app/src/main/assets/modules/__timers__.js +++ b/app/src/main/assets/modules/__timers__.js @@ -65,11 +65,11 @@ module.exports = function (scriptRuntime, scope) { __asGlobal__(scriptRuntime.timers, methods, scope); Object.assign(scope, { - /** - * @global - */ + /** @global */ loop() { - return scriptRuntime.console.warn('Method loop() is deprecated and has no effect.'); + // @Abandoned by SuperMonster003 as of May 3, 2023. + // scriptRuntime.console.warn('Method loop() is deprecated and has no effect.'); + throw Error(context.getString(R.strings.error_abandoned_method, 'global.loop')); }, }); }, diff --git a/app/src/main/assets/modules/__ui__.js b/app/src/main/assets/modules/__ui__.js index 1ce49bc3..f00e25f5 100644 --- a/app/src/main/assets/modules/__ui__.js +++ b/app/src/main/assets/modules/__ui__.js @@ -12,17 +12,20 @@ let { files } = global; module.exports = function (scriptRuntime, scope) { const Looper = android.os.Looper; const Runnable = java.lang.Runnable; - const Color = android.graphics.Color; const ContextThemeWrapper = android.view.ContextThemeWrapper; const ViewExtras = org.autojs.autojs.core.ui.ViewExtras; const JsListView = org.autojs.autojs.core.ui.widget.JsListView; const JsGridView = org.autojs.autojs.core.ui.widget.JsGridView; const JsViewHelper = org.autojs.autojs.core.ui.JsViewHelper; + const ThemeColor = org.autojs.autojs.theme.ThemeColor; const DynamicLayoutInflater = org.autojs.autojs.core.ui.inflater.DynamicLayoutInflater; + const ColorDrawable = android.graphics.drawable.ColorDrawable; require('object-observe-lite.min').call(scope); require('array-observe.min').call(scope); + let isAndroidLayout = null; + // noinspection JSValidateTypes let _ = { // @Coerce by SuperMonster003 on Nov 9, 2022. @@ -142,6 +145,15 @@ module.exports = function (scriptRuntime, scope) { : activity); return layoutInflater.inflate(_.toXMLString(xml), parent || null, Boolean(isAttachedToParent)); }, + useAndroidLayout(b) { + if (typeof b === 'boolean') { + isAndroidLayout = b; + } else if (b === undefined) { + isAndroidLayout = true; + } else { + isAndroidLayout = null; + } + }, run(action) { if (this.isUiThread()) { return action(); @@ -175,11 +187,16 @@ module.exports = function (scriptRuntime, scope) { scriptRuntime.getUiHandler().postDelayed(_.wrapUiAction(action), delay); } }, - layout(layout) { + layout(xml) { _.ensureActivity(); - layoutInflater.setContext(activity); // noinspection JSCheckFunctionSignatures - this.setContentView(layoutInflater.inflate(layout, activity.window.decorView, false)); + layoutInflater.setContext(activity); + // noinspection JSCheckFunctionSignatures,JSTypeOfValues + this.setContentView(layoutInflater.inflate( + typeof xml === 'xml' ? xml.toXMLString() : String(xml), + activity.window.decorView, + false, + )); }, layoutFile(path) { this.layout(files.read(path)); @@ -200,18 +217,13 @@ module.exports = function (scriptRuntime, scope) { }, statusBarColor(color) { _.ensureActivity(); - let colorInt = (/* @IIFE */ () => { - if (typeof color === 'string') { - if (Number(color).toString() === color) { - color = Number(color); - } - } - if (typeof color === 'number') { - return color; - } - return scriptRuntime.colors.parseColor(String(color)); - })(); - this.run(() => activity.window.setStatusBarColor(colorInt)); + this.run(() => activity.window.setStatusBarColor(colors.toInt(color))); + }, + backgroundColor(color) { + _.ensureActivity(); + this.run(() => activity.window.setBackgroundDrawable(new ColorDrawable( + Color(color).setAlpha(1.0).toInt(), + ))); }, findById(id) { return this.view ? this.findByStringId(this.view, id) : null; @@ -235,28 +247,19 @@ module.exports = function (scriptRuntime, scope) { */ layoutInflaterDelegate: { beforeConvertXml(context, xml) { + if (isAndroidLayout === true || isAndroidLayout === null && /\bxmlns:\w+="\w+:\/\/|\b(android|app):\w+=".+"/.test(xml)) { + // noinspection JSTypeOfValues + return typeof xml === 'xml' ? xml.toXMLString() : String(xml); + } return null; }, afterConvertXml(context, xml) { return xml; }, - beforeInflation(context, xml, parent) { - return null; - }, - afterInflation(context, result, xml, parent) { - return result; - }, beforeInflateView(context, node, parent, attachToParent) { return null; }, - afterInflateView(context, view, node, parent, attachToParent) { - let { widget } = view; - if (widget && context.get('root') !== widget) { - widget.notifyAfterInflation(view); - } - return view; - }, - beforeCreateView(context, node, viewName, parent, attrs) { + beforeCreateView(context, node, viewName, parent) { if (uiProxy.__widgets__.hasOwnProperty(viewName)) { let Widget = uiProxy.__widgets__[viewName]; let widget = new Widget(); @@ -267,7 +270,13 @@ module.exports = function (scriptRuntime, scope) { } return null; }, - afterCreateView(context, view, node, viewName, parent, attrs) { + beforeInflation(context, xml, parent) { + return null; + }, + afterInflation(context, result, xml, parent) { + return result; + }, + afterCreateView(context, view, node, viewName, parent) { if (view instanceof JsListView || view instanceof JsGridView) { _.initListView(view); } @@ -275,11 +284,13 @@ module.exports = function (scriptRuntime, scope) { if (widget !== null) { widget.view = view; view.widget = widget; - ViewExtras.getViewAttributes(view, layoutInflater.getResourceParser()).setViewAttributeDelegate({ - has: name => widget.hasAttr(name), - get: (view, name, getter) => widget.getAttr(view, name, getter), - set: (view, name, value, setter) => widget.setAttr(view, name, value, setter), - }); + ViewExtras + .getViewAttributes(view, layoutInflater.getResourceParser()) + .setViewAttributeDelegate({ + has: name => widget.hasAttr(name), + get: (view, name, getter) => widget.getAttr(view, name, getter), + set: (view, name, value, setter) => widget.setAttr(view, name, value, setter), + }); widget.notifyViewCreated(view); } return view; @@ -287,6 +298,27 @@ module.exports = function (scriptRuntime, scope) { beforeApplyAttributes(context, view, inflater, attrs, parent) { return false; }, + beforeApplyAttribute(context, inflater, view, ns, attrName, value, parent) { + let isDynamic = layoutInflater.isDynamicValue(value); + return isDynamic && layoutInflater.getInflateFlags() === DynamicLayoutInflater.FLAG_IGNORES_DYNAMIC_ATTRS + || !isDynamic && layoutInflater.getInflateFlags() === DynamicLayoutInflater.FLAG_JUST_DYNAMIC_ATTRS + || (/* @IIFE */ () => { + value = _.bind(value); + let widget = context.get('widget'); + if (widget !== null && widget.hasAttr(attrName)) { + widget.setAttr(view, attrName, value, (view, attrName, value) => { + inflater.setAttr(view, ns, attrName, value, parent); + }); + } else { + inflater.setAttr(view, ns, attrName, value, parent); + } + this.afterApplyAttribute(context, inflater, view, ns, attrName, value, parent); + return true; + })(); + }, + afterApplyAttribute(context, inflater, view, ns, attrName, value, parent) { + // Empty method body + }, afterApplyAttributes(context, view, inflater, attrs, parent) { context.remove('widget'); }, @@ -302,26 +334,12 @@ module.exports = function (scriptRuntime, scope) { afterApplyPendingAttributesOfChildren(context, inflater, view) { // Empty method body }, - beforeApplyAttribute(context, inflater, view, ns, attrName, value, parent, attrs) { - let isDynamic = layoutInflater.isDynamicValue(value); - return isDynamic && layoutInflater.getInflateFlags() === DynamicLayoutInflater.FLAG_IGNORES_DYNAMIC_ATTRS - || !isDynamic && layoutInflater.getInflateFlags() === DynamicLayoutInflater.FLAG_JUST_DYNAMIC_ATTRS - || (/* @IIFE */ () => { - value = _.bind(value); - let widget = context.get('widget'); - if (widget !== null && widget.hasAttr(attrName)) { - widget.setAttr(view, attrName, value, (view, attrName, value) => { - inflater.setAttr(view, ns, attrName, value, parent, attrs); - }); - } else { - inflater.setAttr(view, ns, attrName, value, parent, attrs); - } - this.afterApplyAttribute(context, inflater, view, ns, attrName, value, parent, attrs); - return true; - })(); - }, - afterApplyAttribute(context, inflater, view, ns, attrName, value, parent, attrs) { - // Empty method body + afterInflateView(context, view, node, parent, attachToParent) { + let { widget } = view; + if (widget && context.get('root') !== widget) { + widget.notifyAfterInflation(view); + } + return view; }, }, bind(value) { @@ -333,7 +351,8 @@ module.exports = function (scriptRuntime, scope) { if (j < 0) { return value; } - value = value.slice(0, i) + _.evalInContext(value.slice(i + 2, j), ctx) + value.slice(j + 2); + let evaluated = _.evalInContext(value.slice(i + 2, j), ctx); + value = value.slice(0, i) + _.attrValueConvert(evaluated) + value.slice(j + 2); i = j + 1; } return value; @@ -401,6 +420,18 @@ module.exports = function (scriptRuntime, scope) { setLayoutInflaterDelegate() { layoutInflater.setLayoutInflaterDelegate(this.layoutInflaterDelegate); }, + attrValueConvert(o) { + if (typeof o === 'string') { + return o; + } + if (o instanceof scope.Color) { + return o.toHex(); + } + if (o instanceof ThemeColor) { + return o.getColorPrimary(); + } + return o; + }, }; /** diff --git a/app/src/main/assets/modules/__web__.js b/app/src/main/assets/modules/__web__.js index 4c78e310..6d685e2d 100644 --- a/app/src/main/assets/modules/__web__.js +++ b/app/src/main/assets/modules/__web__.js @@ -1,5 +1,9 @@ // noinspection JSUnusedGlobalSymbols +/* Overwritten protection. */ + +let { http } = global; + /** * @param {org.autojs.autojs.runtime.ScriptRuntime} scriptRuntime * @param {org.mozilla.javascript.Scriptable | global} scope @@ -38,6 +42,9 @@ module.exports = function (scriptRuntime, scope) { newInjectableWebClient() { return new InjectableWebClient(Context.getCurrentContext(), scope); }, + newWebSocket(url) { + return new org.autojs.autojs.core.web.WebSocket(http.__okhttp__, url); + }, }; return Web; @@ -46,7 +53,7 @@ module.exports = function (scriptRuntime, scope) { /** * @type {(keyof Internal.Web)[]} */ - let methods = [ 'newInjectableWebView', 'newInjectableWebClient' ]; + let methods = [ 'newInjectableWebView', 'newInjectableWebClient', 'newWebSocket' ]; __asGlobal__(web, methods, scope); }, }; diff --git a/app/src/main/assets/modules/array-observe.min.js b/app/src/main/assets/modules/array-observe.min.js index bfbb5104..1f449198 100644 --- a/app/src/main/assets/modules/array-observe.min.js +++ b/app/src/main/assets/modules/array-observe.min.js @@ -1,3 +1,3 @@ module.exports = function(){ - Object.observe&&!Array.observe&&function(t,e){"use strict";var n=t.getNotifier,r="performChange",i="_original",o="splice";var u={push:function h(t){var e=arguments,u=h[i].apply(this,e);n(this)[r](o,function(){return{index:u-e.length,addedCount:e.length,removed:[]}});return u},unshift:function d(t){var e=arguments,u=d[i].apply(this,e);n(this)[r](o,function(){return{index:0,addedCount:e.length,removed:[]}});return u},pop:function a(){var t=this.length,e=a[i].call(this);if(this.length!==t)n(this)[r](o,function(){return{index:this.length,addedCount:0,removed:[e]}},this);return e},shift:function l(){var t=this.length,e=l[i].call(this);if(this.length!==t)n(this)[r](o,function(){return{index:0,addedCount:0,removed:[e]}},this);return e},splice:function f(t,e){var u=arguments,s=f[i].apply(this,u);if(s.length||u.length>2)n(this)[r](o,function(){return{index:t,addedCount:u.length-2,removed:s}},this);return s}};for(var s in u){u[s][i]=e.prototype[s];e.prototype[s]=u[s]}e.observe=function(e,n){return t.observe(e,n,["add","update","delete",o])};e.unobserve=t.unobserve}(Object,Array); + Object.observe&&!Array.observe&&function(t,e){var n=t.getNotifier,r="performChange",i="_original",o="splice";var u={push:function h(t){var e=arguments,u=h[i].apply(this,e);n(this)[r](o,function(){return{index:u-e.length,addedCount:e.length,removed:[]}});return u},unshift:function d(t){var e=arguments,u=d[i].apply(this,e);n(this)[r](o,function(){return{index:0,addedCount:e.length,removed:[]}});return u},pop:function a(){var t=this.length,e=a[i].call(this);if(this.length!==t)n(this)[r](o,function(){return{index:this.length,addedCount:0,removed:[e]}},this);return e},shift:function l(){var t=this.length,e=l[i].call(this);if(this.length!==t)n(this)[r](o,function(){return{index:0,addedCount:0,removed:[e]}},this);return e},splice:function f(t,e){var u=arguments,s=f[i].apply(this,u);if(s.length||u.length>2)n(this)[r](o,function(){return{index:t,addedCount:u.length-2,removed:s}},this);return s}};for(var s in u){u[s][i]=e.prototype[s];e.prototype[s]=u[s]}e.observe=function(e,n){return t.observe(e,n,["add","update","delete",o])};e.unobserve=t.unobserve}(Object,Array); } \ No newline at end of file diff --git a/app/src/main/assets/modules/banana-i18n.js b/app/src/main/assets/modules/banana-i18n.js index 8cee4ba2..5ad0b7c1 100644 --- a/app/src/main/assets/modules/banana-i18n.js +++ b/app/src/main/assets/modules/banana-i18n.js @@ -1,7 +1,5 @@ ( /* @ModuleIIFE */ () => { - "use strict"; - var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { diff --git a/app/src/main/assets/modules/promise.js b/app/src/main/assets/modules/promise.js index 086dccfc..04bfca66 100644 --- a/app/src/main/assets/modules/promise.js +++ b/app/src/main/assets/modules/promise.js @@ -5,8 +5,6 @@ * @see https://raw.githubusercontent.com/taylorhakes/promise-polyfill/master/dist/polyfill.js */ -'use strict'; - /** * @type {PromiseConstructorLike} */ diff --git a/app/src/main/assets/sample/调用Java API/liveConnect.js b/app/src/main/assets/sample/Java API/liveConnect.js similarity index 100% rename from app/src/main/assets/sample/调用Java API/liveConnect.js rename to app/src/main/assets/sample/Java API/liveConnect.js diff --git a/app/src/main/assets/sample/Shell命令/冻结网易云音乐.js b/app/src/main/assets/sample/Shell/冻结网易云音乐.js similarity index 100% rename from app/src/main/assets/sample/Shell命令/冻结网易云音乐.js rename to app/src/main/assets/sample/Shell/冻结网易云音乐.js diff --git a/app/src/main/assets/sample/Shell命令/结束所有后台进程.js b/app/src/main/assets/sample/Shell/结束所有后台进程.js similarity index 100% rename from app/src/main/assets/sample/Shell命令/结束所有后台进程.js rename to app/src/main/assets/sample/Shell/结束所有后台进程.js diff --git a/app/src/main/assets/sample/Shell命令/解冻并打开网易云音乐.js b/app/src/main/assets/sample/Shell/解冻并打开网易云音乐.js similarity index 100% rename from app/src/main/assets/sample/Shell命令/解冻并打开网易云音乐.js rename to app/src/main/assets/sample/Shell/解冻并打开网易云音乐.js diff --git a/app/src/main/assets/sample/Shell命令/锁屏.js b/app/src/main/assets/sample/Shell/锁屏.js similarity index 100% rename from app/src/main/assets/sample/Shell命令/锁屏.js rename to app/src/main/assets/sample/Shell/锁屏.js diff --git a/app/src/main/assets/sample/复杂界面/WannaCry (仅为娱乐).js b/app/src/main/assets/sample/布局/WannaCry (仅为娱乐).js similarity index 100% rename from app/src/main/assets/sample/复杂界面/WannaCry (仅为娱乐).js rename to app/src/main/assets/sample/布局/WannaCry (仅为娱乐).js diff --git a/app/src/main/assets/sample/复杂界面/应用浏览器 [v6.2.0+].js b/app/src/main/assets/sample/布局/应用浏览器 [v6.2.0+].js similarity index 100% rename from app/src/main/assets/sample/复杂界面/应用浏览器 [v6.2.0+].js rename to app/src/main/assets/sample/布局/应用浏览器 [v6.2.0+].js diff --git a/app/src/main/assets/sample/复杂界面/待办事项 [v6.2.0+].js b/app/src/main/assets/sample/布局/待办事项 [v6.2.0+].js similarity index 100% rename from app/src/main/assets/sample/复杂界面/待办事项 [v6.2.0+].js rename to app/src/main/assets/sample/布局/待办事项 [v6.2.0+].js diff --git a/app/src/main/assets/sample/布局/待办事项 [v6.3.1+].js b/app/src/main/assets/sample/布局/待办事项 [v6.3.1+].js new file mode 100644 index 00000000..bd8a9b12 --- /dev/null +++ b/app/src/main/assets/sample/布局/待办事项 [v6.3.1+].js @@ -0,0 +1,142 @@ +'ui'; + +let themeColor = 'orange-800'; + +let materialColors = [ + 'amber-500', + 'blue-500', + 'blue-grey-500', + 'brown-500', + 'cyan-500', + 'deep-orange-500', + 'deep-purple-500', + 'green-500', + 'grey-500', + 'indigo-500', + 'light-blue-500', + 'light-green-500', + 'lime-500', + 'orange-500', + 'pink-500', + 'purple-500', + 'red-500', + 'teal-500', + 'yellow-500', +]; + +let storage = storages.create('todoList'); + +storage.clear(); + +ui.layout( + + + + + +