diff --git a/README.md b/README.md index b9589c1f..7c39580b 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,39 @@ [comment]: <> "Version history only shows last 3 versions" +# v6.0.3 + +###### 2022/03/19 + +* `新增` 多语言切换功能 (尚不完善) +* `新增` recorder 模块 (参阅 示例代码 > 计时器 > *.js × 4) +* `新增` 使用 "修改安全设置权限" 自动启用无障碍服务及开关设置 +* `修复` 点击 "快速设置" 中相关图标后面板未自动收起的问题 (试修) _[`issue #7`](https://github.com/SuperMonster003/AutoJs6/issues/7)_ +* `修复` toast 使用强制显示参数时可能导致 AutoJs6 崩溃的问题 +* `修复` Socket 传输数据头部信息不完整时可能导致 AutoJs6 崩溃的问题 +* `优化` 启动或重启 AutoJs6 时根据选项设置自动开启无障碍服务 +* `优化` 开启悬浮窗显示时尝试自动开启无障碍服务 +* `优化` 所有资源文件补全元素对应的英文翻译 +* `优化` 微调主页抽屉布局 减小项目排列间距 +* `优化` 主页抽屉增加前台服务状态开关的同步 +* `优化` 主页抽屉展开时立即按需同步开关状态 +* `优化` 显示指针位置增加状态检测及结果提示 +* `优化` 支持 64 位操作系统 (Ref to TonyJiangWJ) +* `优化` 悬浮窗初始化时同时应用透明度设置 (无需点击后再应用透明度) +* `优化` 重置文件内容时增加是否为示例代码文件的检测并增加结果提示 +* `优化` 转移打包插件下载地址 GitHub -> JsDelivr +* `优化` 附加 Zeugma Solutions LocaleHelper 版本 1.5.1 +* `优化` 降级 Android Material 版本 1.6.0-alpha02 -> 1.5.0 +* `优化` 升级 Kotlinx Coroutines 版本 1.6.0-native-mt -> 1.6.0 +* `优化` 升级 OpenCV 版本 3.4.3 -> 4.5.4 -> 4.5.5 (Ref to TonyJiangWJ) +* `优化` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.4 -> 5.0.0-alpha.6 +* `优化` 升级 Android Gradle 插件版本 7.2.0-beta01 -> 7.3.0-alpha06 +* `优化` 升级 Auto.js-ApkBuilder 版本 1.0.1 -> 1.0.3 +* `优化` 升级 Glide Compiler 版本 4.12.0 -> 4.13.1 +* `优化` 升级 Gradle 发行版本 7.4-rc-2 -> 7.4.1 +* `优化` 升级 Gradle Compile 版本 31 -> 32 +* `优化` 升级 Gson 版本 2.8.9 -> 2.9.0 + # v6.0.2 ###### 2022/02/05 @@ -112,7 +145,7 @@ * `修复` toast.dismiss() 可能无效的问题 * `修复` 客户端模式及服务端模式开关可能无法正常工作的问题 * `修复` 客户端模式及服务端模式开关状态不能正常刷新的问题 -* `修复` Android 7 解析 UI 模式 text 元素异常 (Ref to TonyJiangWJ) _[`issue #4`](https://github.com/SuperMonster003/AutoJs6/issues/4)_ +* `修复` Android 7 解析 UI 模式 text 元素异常 (Ref to TonyJiangWJ) _[`issue #4`](https://github.com/SuperMonster003/AutoJs6/issues/4)_ _[`#9`](https://github.com/SuperMonster003/AutoJs6/issues/9)_ * `优化` 忽略 sleep() 的 ScriptInterruptedException 异常 * `优化` 附加 Androidx AppCompat (Legacy) 版本 1.0.2 * `优化` 升级 Androidx AppCompat 版本 1.4.0 -> 1.4.1 @@ -140,69 +173,6 @@ * `优化` 升级 Kotlin Gradle 插件版本 1.6.0 -> 1.6.10 * `优化` 升级 Gradle 发行版本 7.3 -> 7.3.3 -# v6.0.0 - -###### 2021/12/01 - -* `新增` 主页抽屉底部增加重启应用按钮 -* `新增` 主页抽屉增加忽略电池优化/显示在其他应用上层等开关 -* `修复` 应用初始安装后部分区域主题颜色渲染异常的问题 -* `修复` sign.property 不存在时无法 build 的问题 -* `修复` 定时任务面板一次性任务的月份存取错误 -* `修复` 应用设置页面开关颜色不随主题变更的问题 -* `修复` 无法识别打包插件及打包插件下载地址无效的问题 -* `修复` 首页抽屉 "查看使用情况权限" 开关状态可能不同步的问题 -* `修复` TemplateMatching.fastTemplateMatching 潜在的 Mat 内存泄漏问题 -* `优化` 升级 Rhino 引擎版本 1.7.7.2 -> 1.7.13 -> 1.7.14-snapshot -* `优化` 升级 OpenCV 版本 3.4.3 -> 4.5.4 -* `优化` ViewUtil.getStatusBarHeight 提升兼容性 -* `优化` 主页抽屉移除用户登录相关模块并移除布局占位 -* `优化` 主页移除社区及市场标签页面并优化布局对其方式 -* `优化` 修改一些设置选项的默认开关状态 -* `优化` 关于页面增加 SinceDate 并优化 Copyright 显示 -* `优化` 升级 JSON 模块至 2017-06-12 版本并整合 cycle.js -* `优化` 移除 Activity 前置时的自动检查更新功能并移除检查更新相关按钮 -* `优化` AppOpsKt#isOpPermissionGranted 内部代码逻辑 -* `优化` ResourceMonitor 使用 ReentrantLock 增强安全性 (Ref to TonyJiangWJ) -* `优化` 使用 Maven Central 等仓库替换 JCenter 仓库 -* `优化` 抽离并移除重复的本地库文件 -* `优化` 本地化 CrashReport 版本 2.6.6 -* `优化` 本地化 MutableTheme 版本 1.0.0 -* `优化` 附加 Androidx Preference 版本 1.1.1 -* `优化` 附加 SwipeRefreshLayout 版本 1.1.0 -* `优化` 升级 Android Analytics 版本 7.0.0 -> 13.1.0 -* `优化` 升级 Android Annotations 版本 4.5.2 -> 4.8.0 -* `优化` 升级 Android Gradle 插件版本 3.2.1 -> 4.1.0 -> 7.0.3 -> 7.2.0-alpha04 -* `优化` 升级 Android Job 版本 1.2.6 -> 1.4.2 -* `优化` 升级 Android Material 版本 1.1.0-alpha01 -> 1.5.0-beta01 -* `优化` 升级 Androidx MultiDex 版本 2.0.0 -> 2.0.1 -* `优化` 升级 Apache Commons Lang3 版本 3.6 -> 3.12.0 -* `优化` 升级 Appcompat 版本 1.0.2 -> 1.4.0 -* `优化` 升级 ButterKnife Gradle 插件版本 9.0.0-rc2 -> 10.2.1 -> 10.2.3 -* `优化` 升级 ColorPicker 版本 2.1.5 -> 2.1.7 -* `优化` 升级 Espresso Core 版本 3.1.1-alpha01 -> 3.5.0-alpha03 -* `优化` 升级 Eventbus 版本 3.0.0 -> 3.2.0 -* `优化` 升级 Glide Compiler 版本 4.8.0 -> 4.12.0 -> 4.12.0 -* `优化` 升级 Gradle Build Tool 版本 29.0.2 -> 30.0.2 -* `优化` 升级 Gradle Compile 版本 28 -> 30 -> 31 -* `优化` 升级 Gradle 发行版本 4.10.2 -> 6.5 -> 7.0.2 -> 7.3 -* `优化` 升级 Groovy-Json 插件版本 3.0.7 -> 3.0.8 -* `优化` 升级 Gson 版本 2.8.2 -> 2.8.9 -* `优化` 升级 JavaVersion 版本 1.8 -> 11 -> 16 -* `优化` 升级 Joda Time 版本 2.9.9 -> 2.10.13 -* `优化` 升级 Junit 版本 4.12 -> 4.13.2 -* `优化` 升级 Kotlin Gradle 插件版本 1.3.10 -> 1.4.10 -> 1.6.0 -* `优化` 升级 Kotlinx Coroutines 版本 1.0.1 -> 1.5.2-native-mt -* `优化` 升级 Leakcanary 版本 1.6.1 -> 2.7 -* `优化` 升级 LicensesDialog 版本 1.8.1 -> 2.2.0 -* `优化` 升级 Material Dialogs 版本 0.9.2.3 -> 0.9.6.0 -* `优化` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.2 -> 5.0.0-alpha.3 -* `优化` 升级 Reactivex RxJava2 RxAndroid 版本 2.0.1 -> 2.1.1 -* `优化` 升级 Reactivex RxJava2 版本 2.1.2 -> 2.2.21 -* `优化` 升级 Retrofit2 Converter Gson 版本 2.3.0 -> 2.9.0 -* `优化` 升级 Retrofit2 Retrofit 版本 2.3.0 -> 2.9.0 -* `优化` 升级 Zip4j 版本 1.3.2 -> 2.9.1 - ##### 更多版本历史可参阅 * [CHANGELOG.md](https://github.com/SuperMonster003/AutoJs6/blob/master/app/src/main/assets/doc/CHANGELOG.md) @@ -213,11 +183,14 @@ ****** -* [AutoJs6-VSCode-Extension](https://github.com/SuperMonster003/AutoJs6-VSCode-Extension) { author: [SuperMonster003](https://github.com/SuperMonster003) } - - `适用于 VSCode 的桌面开发插件 (二次开发项目)` - +* [Auto.js](https://github.com/TonyJiangWJ/Auto.js) { author: [TonyJiangWJ](https://github.com/TonyJiangWJ) } + - `安卓平台 JavaScript 自动化工具 (二次开发项目)` + * [AutoX](https://github.com/kkevsekk1/AutoX) { author: [kkevsekk1](https://github.com/kkevsekk1) } - `安卓平台 JavaScript 自动化工具 (二次开发项目)` +* [AutoJs6-VSCode-Extension](https://github.com/SuperMonster003/AutoJs6-VSCode-Extension) { author: [SuperMonster003](https://github.com/SuperMonster003) } + - `适用于 VSCode 的桌面开发插件 (二次开发项目)` + [comment]: <> (* [Auto.js-TypeScript-Declarations](https://github.com/SuperMonster003/Auto.js-TypeScript-Declarations) { author: [SuperMonster003](https://github.com/SuperMonster003) }) [comment]: <> ( - `Auto.js 声明文件 (.d.ts)`) diff --git a/app/build.gradle b/app/build.gradle index 13fdffe5..3785fd0b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -97,10 +97,10 @@ android { reset() // Specifies a list of ABIs that Gradle should create APKs for. - include 'x86', 'armeabi-v7a' + include 'x86', 'armeabi-v7a', 'arm64-v8a', 'x86_64' // Specifies that we do not want to also generate a universal APK that includes all ABIs. - universalApk false + universalApk true } } productFlavors { @@ -110,6 +110,17 @@ android { } } applicationVariants.all { variant -> + variant.outputs.all { output -> + def aj = "AutoJs6" + def ver = versionName.replaceAll(/\s/, "-") + + // FIXME by SuperMonster003 as of Mar 19, 2022. + // ! Interface com.android.build.OutputFile is deprecated. + // ! Another way of getting ABI is needed. + def abi = getFilter(com.android.build.OutputFile.ABI) + + output.outputFileName = "${aj}-v${ver}-${abi ? "${abi}" : "universal"}.apk".toLowerCase() + } variant.mergeAssetsProvider.configure { doLast { delete(fileTree(dir: outputDir, includes: ['declarations/**'])) @@ -130,7 +141,7 @@ dependencies { debugImplementation "com.squareup.leakcanary:leakcanary-android:${versions.leakcanary}" // Kotlin - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0-native-mt' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0' // Android Annotations kapt "org.androidannotations:androidannotations:${versions.annotations}" @@ -174,11 +185,7 @@ dependencies { // Expandable RecyclerView implementation 'com.thoughtbot:expandablerecyclerview:1.3' - implementation 'com.github.hyb1996:Auto.js-ApkBuilder:1.0.1' - - // RxJava - implementation 'io.reactivex.rxjava2:rxjava:2.2.21' - implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' + implementation 'com.github.hyb1996:Auto.js-ApkBuilder:1.0.3' // Retrofit implementation 'com.squareup.retrofit2:retrofit:2.9.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 84c00630..78616f31 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="org.autojs.autojs"> + @@ -29,7 +30,7 @@ @@ -56,13 +56,12 @@ @@ -84,41 +83,34 @@ - + - + - + android:name="org.autojs.autojs.external.tasker.TaskerScriptEditActivity_" + android:configChanges="orientation|screenSize|locale" /> + + android:name="org.autojs.autojs.ui.project.BuildActivity_" + android:configChanges="orientation|screenSize|locale" /> + + + + + - - - - - - - - @@ -130,46 +122,46 @@ - - + + - + + android:exported="true"> + android:value="true" /> + android:exported="true"> + android:value="true" /> @@ -234,7 +226,7 @@ @@ -252,7 +244,7 @@ @@ -314,7 +306,7 @@ diff --git a/app/src/main/assets/doc/CHANGELOG.md b/app/src/main/assets/doc/CHANGELOG.md index 17fb8a35..dc7b5044 100644 --- a/app/src/main/assets/doc/CHANGELOG.md +++ b/app/src/main/assets/doc/CHANGELOG.md @@ -4,6 +4,39 @@ ****** +# v6.0.3 + +###### 2022/03/19 + +* `新增` 多语言切换功能 (尚不完善) +* `新增` recorder 模块 (参阅 示例代码 > 计时器 > *.js × 4) +* `新增` 使用 "修改安全设置权限" 自动启用无障碍服务及开关设置 +* `修复` 点击 "快速设置" 中相关图标后面板未自动收起的问题 (试修) _[`issue #7`](https://github.com/SuperMonster003/AutoJs6/issues/7)_ +* `修复` toast 使用强制显示参数时可能导致 AutoJs6 崩溃的问题 +* `修复` Socket 传输数据头部信息不完整时可能导致 AutoJs6 崩溃的问题 +* `优化` 启动或重启 AutoJs6 时根据选项设置自动开启无障碍服务 +* `优化` 开启悬浮窗显示时尝试自动开启无障碍服务 +* `优化` 所有资源文件补全元素对应的英文翻译 +* `优化` 微调主页抽屉布局 减小项目排列间距 +* `优化` 主页抽屉增加前台服务状态开关的同步 +* `优化` 主页抽屉展开时立即按需同步开关状态 +* `优化` 显示指针位置增加状态检测及结果提示 +* `优化` 支持 64 位操作系统 (Ref to TonyJiangWJ) +* `优化` 悬浮窗初始化时同时应用透明度设置 (无需点击后再应用透明度) +* `优化` 重置文件内容时增加是否为示例代码文件的检测并增加结果提示 +* `优化` 转移打包插件下载地址 GitHub -> JsDelivr +* `优化` 附加 Zeugma Solutions LocaleHelper 版本 1.5.1 +* `优化` 降级 Android Material 版本 1.6.0-alpha02 -> 1.5.0 +* `优化` 升级 Kotlinx Coroutines 版本 1.6.0-native-mt -> 1.6.0 +* `优化` 升级 OpenCV 版本 3.4.3 -> 4.5.4 -> 4.5.5 (Ref to TonyJiangWJ) +* `优化` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.4 -> 5.0.0-alpha.6 +* `优化` 升级 Android Gradle 插件版本 7.2.0-beta01 -> 7.3.0-alpha06 +* `优化` 升级 Auto.js-ApkBuilder 版本 1.0.1 -> 1.0.3 +* `优化` 升级 Glide Compiler 版本 4.12.0 -> 4.13.1 +* `优化` 升级 Gradle 发行版本 7.4-rc-2 -> 7.4.1 +* `优化` 升级 Gradle Compile 版本 31 -> 32 +* `优化` 升级 Gson 版本 2.8.9 -> 2.9.0 + # v6.0.2 ###### 2022/02/05 @@ -13,7 +46,7 @@ * `修复` toast.dismiss() 可能无效的问题 * `修复` 客户端模式及服务端模式开关可能无法正常工作的问题 * `修复` 客户端模式及服务端模式开关状态不能正常刷新的问题 -* `修复` Android 7 解析 UI 模式 text 元素异常 (Ref to TonyJiangWJ) _[`issue #4`](https://github.com/SuperMonster003/AutoJs6/issues/4)_ +* `修复` Android 7 解析 UI 模式 text 元素异常 (Ref to TonyJiangWJ) _[`issue #4`](https://github.com/SuperMonster003/AutoJs6/issues/4)_ _[`#9`](https://github.com/SuperMonster003/AutoJs6/issues/9)_ * `优化` 忽略 sleep() 的 ScriptInterruptedException 异常 * `优化` 附加 Androidx AppCompat (Legacy) 版本 1.0.2 * `优化` 升级 Androidx AppCompat 版本 1.4.0 -> 1.4.1 diff --git a/app/src/main/java/com/stardust/theme/preference/ThemeColorPreferenceFragment.java b/app/src/main/java/com/stardust/theme/preference/ThemeColorPreferenceFragment.java index d7488a8c..e5c9c55f 100644 --- a/app/src/main/java/com/stardust/theme/preference/ThemeColorPreferenceFragment.java +++ b/app/src/main/java/com/stardust/theme/preference/ThemeColorPreferenceFragment.java @@ -1,10 +1,13 @@ package com.stardust.theme.preference; +import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.os.Build; import android.preference.PreferenceFragment; import android.widget.ListView; +import androidx.annotation.Nullable; + import com.stardust.theme.ThemeColor; import com.stardust.theme.internal.ScrollingViewEdgeGlowColorHelper; import com.stardust.theme.ThemeColorManager; @@ -15,9 +18,12 @@ import java.lang.reflect.Field; /** * Created by Stardust on 2016/8/14. */ +@SuppressWarnings({"deprecation", "JavaReflectionMemberAccess"}) +@SuppressLint("SoonBlockedPrivateApi") @TargetApi(Build.VERSION_CODES.HONEYCOMB) public class ThemeColorPreferenceFragment extends PreferenceFragment implements ThemeColorMutable { + @Nullable private static Field LIST_VIEW; private int mThemeColor; private boolean hasAppliedThemeColor = false; @@ -34,11 +40,13 @@ public class ThemeColorPreferenceFragment extends PreferenceFragment implements private ListView getListView() { try { - return (ListView) LIST_VIEW.get(this); + if (LIST_VIEW != null) { + return (ListView) LIST_VIEW.get(this); + } } catch (Exception e) { e.printStackTrace(); - return null; } + return null; } public void addPreferencesFromResource(int resId) { diff --git a/app/src/main/java/org/autojs/autojs/Pref.java b/app/src/main/java/org/autojs/autojs/Pref.java index 8b68d34a..87301ad1 100644 --- a/app/src/main/java/org/autojs/autojs/Pref.java +++ b/app/src/main/java/org/autojs/autojs/Pref.java @@ -3,6 +3,7 @@ package org.autojs.autojs; import android.content.Context; import android.content.SharedPreferences; import android.os.Environment; + import androidx.preference.PreferenceManager; import com.stardust.app.GlobalAppContext; @@ -21,6 +22,7 @@ public class Pref { private static final SharedPreferences DISPOSABLE_BOOLEAN = GlobalAppContext.get().getSharedPreferences("DISPOSABLE_BOOLEAN", Context.MODE_PRIVATE); private static final String KEY_SERVER_ADDRESS = "KEY_SERVER_ADDRESS"; private static final String KEY_FLOATING_MENU_SHOWN = "KEY_FLOATING_MENU_SHOWN"; + private static final String KEY_APP_LANG_INDEX = "KEY_APP_LANG_INDEX"; private static final String KEY_EDITOR_THEME = "editor.theme"; private static final String KEY_EDITOR_TEXT_SIZE = "editor.textSize"; @@ -62,7 +64,11 @@ public class Pref { } public static boolean shouldEnableAccessibilityServiceByRoot() { - return def().getBoolean(getString(R.string.key_enable_accessibility_service_by_root), true); + return def().getBoolean(getString(R.string.key_enable_a11y_service_with_root_access), true); + } + + public static boolean shouldEnableAccessibilityServiceBySecureSettings() { + return def().getBoolean(getString(R.string.key_enable_a11y_service_with_secure_settings), true); } private static String getString(int id) { @@ -90,7 +96,7 @@ public class Pref { } public static boolean rootRecordGeneratesBinary() { - return Objects.equals(def().getString(getString(R.string.key_root_record_out_file_type), "binary"), "binary"); + return Objects.equals(def().getString(getString(R.string.key_root_record_out_file_type), getString(R.string.default_value_binary)), getString(R.string.value_root_record_out_file_type_binary)); } public static boolean isStableModeEnabled() { @@ -99,7 +105,7 @@ public class Pref { public static String getDocumentationUrl() { String docSource = def().getString(getString(R.string.key_documentation_source), null); - if (docSource == null || docSource.equals("Local")) { + if (docSource == null || docSource.equals(getString(R.string.value_documentation_source_local))) { return "file:///android_asset/docs/"; } else { return "https://www.autojs.org/assets/autojs/docs/"; @@ -122,6 +128,10 @@ public class Pref { def().edit().putString(KEY_EDITOR_THEME, theme).apply(); } + public static void setAppLanguageIndex(int index) { + def().edit().putInt(KEY_APP_LANG_INDEX, index).apply(); + } + public static void setEditorTextSize(int value) { def().edit().putInt(KEY_EDITOR_TEXT_SIZE, value).apply(); } @@ -139,4 +149,8 @@ public class Pref { public static boolean isForegroundServiceEnabled() { return def().getBoolean(getString(R.string.key_foreground_service), false); } + + public static int getAppLanguageIndex() { + return def().getInt(KEY_APP_LANG_INDEX, 0); + } } diff --git a/app/src/main/java/org/autojs/autojs/accessibility/AccessibilityEventHelper.java b/app/src/main/java/org/autojs/autojs/accessibility/AccessibilityEventHelper.java deleted file mode 100644 index 57d3e2e0..00000000 --- a/app/src/main/java/org/autojs/autojs/accessibility/AccessibilityEventHelper.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.autojs.autojs.accessibility; - -import android.util.SparseArray; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityNodeInfo; - -import org.autojs.autojs.R; -import com.stardust.util.SparseArrayEntries; - -import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED; -import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_LONG_CLICKED; -import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SCROLLED; -import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED; -import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD; -import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SCROLL_FORWARD; - -/** - * Created by Stardust on 2017/3/16. - */ - -public class AccessibilityEventHelper { - - private static final SparseArray EVENT_ACTION_RES_ID_MAP = new SparseArrayEntries() - .entry(TYPE_VIEW_CLICKED, R.string.text_clicked) - .entry(TYPE_VIEW_LONG_CLICKED, R.string.text_long_clicked) - .entry(TYPE_VIEW_SCROLLED, R.string.text_scrolled) - .entry(TYPE_VIEW_TEXT_CHANGED, R.string.text_text_changed) - .sparseArray(); - - public static int getEventTypeNameResId(AccessibilityEvent event) { - return EVENT_ACTION_RES_ID_MAP.get(event.getEventType()); - } -} diff --git a/app/src/main/java/org/autojs/autojs/autojs/AutoJs.java b/app/src/main/java/org/autojs/autojs/autojs/AutoJs.java index ea86c983..197a0e5b 100644 --- a/app/src/main/java/org/autojs/autojs/autojs/AutoJs.java +++ b/app/src/main/java/org/autojs/autojs/autojs/AutoJs.java @@ -7,9 +7,11 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Looper; +import androidx.annotation.Nullable; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import com.stardust.app.GlobalAppContext; +import com.stardust.autojs.core.accessibility.AccessibilityServiceTool; import com.stardust.autojs.core.console.GlobalConsole; import com.stardust.autojs.runtime.ScriptRuntime; import com.stardust.autojs.runtime.accessibility.AccessibilityConfig; @@ -20,11 +22,9 @@ import com.stardust.view.accessibility.AccessibilityService; import com.stardust.view.accessibility.LayoutInspector; import com.stardust.view.accessibility.NodeInfo; -import org.autojs.autojs.Pref; import org.autojs.autojs.R; import org.autojs.autojs.external.fileprovider.AppFileProvider; import org.autojs.autojs.pluginclient.DevPluginService; -import org.autojs.autojs.tool.AccessibilityServiceTool; import org.autojs.autojs.ui.floating.FloatyWindowManger; import org.autojs.autojs.ui.floating.FullScreenFloatyWindow; import org.autojs.autojs.ui.floating.layoutinspector.LayoutBoundsFloatyWindow; @@ -44,6 +44,8 @@ public class AutoJs extends com.stardust.autojs.AutoJs { private static AutoJs instance; + private final Application appContext; + // @Thank to Zen2H private final ExecutorService printExecutor = Executors.newSingleThreadExecutor(); @@ -64,6 +66,7 @@ public class AutoJs extends com.stardust.autojs.AutoJs { private AutoJs(final Application application) { super(application); + appContext = application; getScriptEngineService().registerGlobalScriptExecutionListener(new ScriptExecutionGlobalListener()); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(LayoutBoundsFloatyWindow.class.getName()); @@ -119,7 +122,7 @@ public class AutoJs extends com.stardust.autojs.AutoJs { public String println(int level, CharSequence charSequence) { String log = super.println(level, charSequence); - // FIXME by SuperMonster003 on Feb 2, 2022 + // FIXME by SuperMonster003 as of Feb 2, 2022. // ! When running in 'ui' thread (`ui.run`, `ui.post`), // ! android.os.NetworkOnMainThreadException may happen. // ! Further more, dunno if a thread executor is a good idea. @@ -134,20 +137,9 @@ public class AutoJs extends com.stardust.autojs.AutoJs { if (AccessibilityService.Companion.getInstance() != null) { return; } - String errorMessage = null; - if (AccessibilityServiceTool.isAccessibilityServiceEnabled(GlobalAppContext.get())) { - errorMessage = GlobalAppContext.getString(R.string.text_auto_operate_service_enabled_but_not_running); - } else { - if (Pref.shouldEnableAccessibilityServiceByRoot()) { - if (!AccessibilityServiceTool.enableAccessibilityServiceByRootAndWaitFor(2000)) { - errorMessage = GlobalAppContext.getString(R.string.text_enable_accessibility_service_by_root_timeout); - } - } else { - errorMessage = GlobalAppContext.getString(R.string.text_no_accessibility_permission); - } - } + String errorMessage = tryEnableAccessibilityService(); if (errorMessage != null) { - AccessibilityServiceTool.goToAccessibilitySetting(); + getAccessibilityTool().goToAccessibilitySetting(); throw new ScriptException(errorMessage); } } @@ -157,26 +149,26 @@ public class AutoJs extends com.stardust.autojs.AutoJs { if (AccessibilityService.Companion.getInstance() != null) { return; } - String errorMessage = null; - if (AccessibilityServiceTool.isAccessibilityServiceEnabled(GlobalAppContext.get())) { - errorMessage = GlobalAppContext.getString(R.string.text_auto_operate_service_enabled_but_not_running); - } else { - if (Pref.shouldEnableAccessibilityServiceByRoot()) { - if (!AccessibilityServiceTool.enableAccessibilityServiceByRootAndWaitFor(2000)) { - errorMessage = GlobalAppContext.getString(R.string.text_enable_accessibility_service_by_root_timeout); - } - } else { - errorMessage = GlobalAppContext.getString(R.string.text_no_accessibility_permission); - } - } + String errorMessage = tryEnableAccessibilityService(); if (errorMessage != null) { - AccessibilityServiceTool.goToAccessibilitySetting(); + getAccessibilityTool().goToAccessibilitySetting(); if (!AccessibilityService.Companion.waitForEnabled(-1)) { throw new ScriptInterruptedException(); } } } + @Nullable + private String tryEnableAccessibilityService() { + if (getAccessibilityTool().isAccessibilityServiceEnabled()) { + return GlobalAppContext.getString(R.string.text_auto_operate_service_enabled_but_not_working); + } + if (!getAccessibilityTool().enableAccessibilityServiceAutomaticallyIfNeededAndWaitFor(2000)) { + return GlobalAppContext.getString(R.string.text_no_accessibility_permission); + } + return null; + } + @Override protected AccessibilityConfig createAccessibilityConfig() { return super.createAccessibilityConfig(); @@ -192,4 +184,8 @@ public class AutoJs extends com.stardust.autojs.AutoJs { return runtime; } + private AccessibilityServiceTool getAccessibilityTool() { + return new AccessibilityServiceTool(appContext); + } + } diff --git a/app/src/main/java/org/autojs/autojs/autojs/build/ApkBuilder.java b/app/src/main/java/org/autojs/autojs/autojs/build/ApkBuilder.java index bd083751..87db41e3 100644 --- a/app/src/main/java/org/autojs/autojs/autojs/build/ApkBuilder.java +++ b/app/src/main/java/org/autojs/autojs/autojs/build/ApkBuilder.java @@ -26,7 +26,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.concurrent.Callable; -import java.util.regex.Pattern; import pxb.android.StringItem; import pxb.android.axml.AxmlWriter; @@ -189,8 +188,7 @@ public class ApkBuilder { if (child.getName().endsWith(".js")) { encrypt(toDir, child); } else { - StreamUtils.write(new FileInputStream(child), - new FileOutputStream(new File(toDir, child.getName()))); + StreamUtils.write(new FileInputStream(child), new FileOutputStream(new File(toDir, child.getName()))); } } else { if (!mAppConfig.ignoredDirs.contains(child)) { diff --git a/app/src/main/java/org/autojs/autojs/build/TinySign.java b/app/src/main/java/org/autojs/autojs/build/TinySign.java index 83ad992b..82e3cd88 100644 --- a/app/src/main/java/org/autojs/autojs/build/TinySign.java +++ b/app/src/main/java/org/autojs/autojs/build/TinySign.java @@ -2,6 +2,8 @@ package org.autojs.autojs.build; import android.util.Base64; +import com.stardust.autojs.apkbuilder.util.StreamUtils; + import java.io.File; import java.io.FileInputStream; import java.io.FilterOutputStream; @@ -9,6 +11,7 @@ import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.security.DigestOutputStream; import java.security.KeyFactory; import java.security.MessageDigest; @@ -17,36 +20,34 @@ import java.security.PrivateKey; import java.security.Signature; import java.security.SignatureException; import java.security.spec.PKCS8EncodedKeySpec; -import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.jar.Attributes; import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; public class TinySign { public TinySign() { } - private static byte[] dBase64(String data) throws UnsupportedEncodingException { - return Base64.decode(data.getBytes("UTF-8"), Base64.NO_WRAP); + private static byte[] dBase64(String data) { + return Base64.decode(data.getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP); } private static void doDir(String prefix, File dir, ZipOutputStream zos, DigestOutputStream dos, Manifest m) throws IOException { zos.putNextEntry(new ZipEntry(prefix)); zos.closeEntry(); File[] arr$ = dir.listFiles(); - int len$ = arr$.length; - for(int i$ = 0; i$ < len$; ++i$) { - File f = arr$[i$]; - if (f.isFile()) { - doFile(prefix + f.getName(), f, zos, dos, m); - } else { - doDir(prefix + f.getName() + "/", f, zos, dos, m); + if (arr$ != null) { + for (File f : arr$) { + if (f.isFile()) { + doFile(prefix + f.getName(), f, zos, dos, m); + } else { + doDir(prefix + f.getName() + "/", f, zos, dos, m); + } } } @@ -54,13 +55,13 @@ public class TinySign { private static void doFile(String name, File f, ZipOutputStream zos, DigestOutputStream dos, Manifest m) throws IOException { zos.putNextEntry(new ZipEntry(name)); - FileInputStream fis = FileUtils.openInputStream(f); - IOUtils.copy(fis, dos); - IOUtils.closeQuietly(fis); - byte[] digets = dos.getMessageDigest().digest(); + FileInputStream fis = new FileInputStream(f); + StreamUtils.write(fis, dos); + fis.close(); + byte[] digest = dos.getMessageDigest().digest(); zos.closeEntry(); Attributes attr = new Attributes(); - attr.putValue("SHA1-Digest", eBase64(digets)); + attr.putValue("SHA1-Digest", eBase64(digest)); m.getEntries().put(name, attr); } @@ -82,15 +83,11 @@ public class TinySign { }, md), true, "UTF-8"); Manifest sf = new Manifest(); Map entries = manifest.getEntries(); - Iterator> iterator = entries.entrySet().iterator(); - while(iterator.hasNext()) { - Entry entry = iterator.next(); + for (Entry entry : entries.entrySet()) { print.print("Name: " + entry.getKey() + "\r\n"); - Iterator> iter = entry.getValue().entrySet().iterator(); - while(iter.hasNext()) { - Entry att = iter.next(); + for (Entry att : entry.getValue().entrySet()) { print.print(att.getKey() + ": " + att.getValue() + "\r\n"); } @@ -104,8 +101,14 @@ public class TinySign { return sf; } + @SuppressWarnings("SpellCheckingInspection") + private static class Constants { + static String privateKey = "MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAoiZSqWnFDHA5sXKoDiUUO9JuL7cm/2dCck5MKumVvv+WfSg0jsovnywsFN0pifmdRSLmOdUkh0d0J+tOnSgtsQIDAQABAkEAihag5u3Qhds9BsViIUmqhZebhr8vUuqZR8cuTo1GnbSoOHIPbAgD3J8TDbC/CVqae8NrgwLp325Pem1Tuof/0QIhAN1hqft1K307bsljgw3iYKopGVZBHRXsjRnNL4edV9QrAiEAu4F+XtS1wohGLz5QtfuMFsQNo4l31mCjt6WpBDmSi5MCIQCB++YijxmJ3mueM5+vd0vqnVcTHghF5y6yB5fwuKHpIQIgInnS1Hjj2prX3MPmby+LOHxfzZvvDtnCAHhTNVWonkUCIQCvV8l+SpL6Vh1nQ/2EKFJo2dbZB3wKG/BEYsFkPFbn9w=="; + static String sigPrefix = "MIIB5gYJKoZIhvcNAQcCoIIB1zCCAdMCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCATYwggEyMIHdoAMCAQICBCunMokwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAxMEVGVzdDAeFw0xMjA0MjIwODQ1NDdaFw0xMzA0MjIwODQ1NDdaMA8xDTALBgNVBAMTBFRlc3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAoiZSqWnFDHA5sXKoDiUUO9JuL7cm/2dCck5MKumVvv+WfSg0jsovnywsFN0pifmdRSLmOdUkh0d0J+tOnSgtsQIDAQABoyEwHzAdBgNVHQ4EFgQUVL2yOinUwpARE1tOPxc1bf4WrTgwDQYJKoZIhvcNAQELBQADQQAnj/eZwhqwb2tgSYNvgRo5bBNNCpJbQ4alEeP/MLSIWf2nZpAix8T3oS9X2affQtAgctPATcKQaiH2B4L7FKlVMXoweAIBATAXMA8xDTALBgNVBAMTBFRlc3QCBCunMokwCQYFKw4DAhoFADANBgkqhkiG9w0BAQEFAARA"; + } + private static Signature instanceSignature() throws Exception { - byte[] data = dBase64("MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAoiZSqWnFDHA5sXKoDiUUO9JuL7cm/2dCck5MKumVvv+WfSg0jsovnywsFN0pifmdRSLmOdUkh0d0J+tOnSgtsQIDAQABAkEAihag5u3Qhds9BsViIUmqhZebhr8vUuqZR8cuTo1GnbSoOHIPbAgD3J8TDbC/CVqae8NrgwLp325Pem1Tuof/0QIhAN1hqft1K307bsljgw3iYKopGVZBHRXsjRnNL4edV9QrAiEAu4F+XtS1wohGLz5QtfuMFsQNo4l31mCjt6WpBDmSi5MCIQCB++YijxmJ3mueM5+vd0vqnVcTHghF5y6yB5fwuKHpIQIgInnS1Hjj2prX3MPmby+LOHxfzZvvDtnCAHhTNVWonkUCIQCvV8l+SpL6Vh1nQ/2EKFJo2dbZB3wKG/BEYsFkPFbn9w=="); + byte[] data = dBase64(Constants.privateKey); KeyFactory rSAKeyFactory = KeyFactory.getInstance("RSA"); PrivateKey privateKey = rSAKeyFactory.generatePrivate(new PKCS8EncodedKeySpec(data)); Signature signature = Signature.getInstance("SHA1withRSA"); @@ -122,7 +125,7 @@ public class TinySign { Manifest sf = generateSF(manifest); byte[] sign = writeSF(zos, sf, sha1Manifest); writeRSA(zos, sign); - IOUtils.closeQuietly(zos); + zos.close(); } private static String writeMF(File dir, Manifest manifest, ZipOutputStream zos) throws NoSuchAlgorithmException, IOException { @@ -140,7 +143,7 @@ public class TinySign { private static void writeRSA(ZipOutputStream zos, byte[] sign) throws IOException { zos.putNextEntry(new ZipEntry("META-INF/CERT.RSA")); - zos.write(dBase64("MIIB5gYJKoZIhvcNAQcCoIIB1zCCAdMCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCATYwggEyMIHdoAMCAQICBCunMokwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAxMEVGVzdDAeFw0xMjA0MjIwODQ1NDdaFw0xMzA0MjIwODQ1NDdaMA8xDTALBgNVBAMTBFRlc3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAoiZSqWnFDHA5sXKoDiUUO9JuL7cm/2dCck5MKumVvv+WfSg0jsovnywsFN0pifmdRSLmOdUkh0d0J+tOnSgtsQIDAQABoyEwHzAdBgNVHQ4EFgQUVL2yOinUwpARE1tOPxc1bf4WrTgwDQYJKoZIhvcNAQELBQADQQAnj/eZwhqwb2tgSYNvgRo5bBNNCpJbQ4alEeP/MLSIWf2nZpAix8T3oS9X2affQtAgctPATcKQaiH2B4L7FKlVMXoweAIBATAXMA8xDTALBgNVBAMTBFRlc3QCBCunMokwCQYFKw4DAhoFADANBgkqhkiG9w0BAQEFAARA")); + zos.write(dBase64(Constants.sigPrefix)); zos.write(sign); zos.closeEntry(); } @@ -149,10 +152,10 @@ public class TinySign { Signature signature = instanceSignature(); zos.putNextEntry(new ZipEntry("META-INF/CERT.SF")); TinySign.SignatureOutputStream out = new TinySign.SignatureOutputStream(zos, signature); - out.write("Signature-Version: 1.0\r\n".getBytes("UTF-8")); - out.write(("Created-By: tiny-sign-" + TinySign.class.getPackage().getImplementationVersion() + "\r\n").getBytes("UTF-8")); - out.write("SHA1-Digest-Manifest: ".getBytes("UTF-8")); - out.write(sha1Manifest.getBytes("UTF-8")); + out.write("Signature-Version: 1.0\r\n".getBytes(StandardCharsets.UTF_8)); + out.write(("Created-By: tiny-sign-" + Objects.requireNonNull(TinySign.class.getPackage()).getImplementationVersion() + "\r\n").getBytes(StandardCharsets.UTF_8)); + out.write("SHA1-Digest-Manifest: ".getBytes(StandardCharsets.UTF_8)); + out.write(sha1Manifest.getBytes(StandardCharsets.UTF_8)); out.write(13); out.write(10); sf.write(out); @@ -160,17 +163,17 @@ public class TinySign { return signature.sign(); } - private static void zipAndSha1(File dir, ZipOutputStream zos, DigestOutputStream dos, Manifest m) throws NoSuchAlgorithmException, IOException { + private static void zipAndSha1(File dir, ZipOutputStream zos, DigestOutputStream dos, Manifest m) throws IOException { File[] arr$ = dir.listFiles(); - int len$ = arr$.length; - for(int i$ = 0; i$ < len$; ++i$) { - File f = arr$[i$]; - if (!f.getName().startsWith("META-INF")) { - if (f.isFile()) { - doFile(f.getName(), f, zos, dos, m); - } else { - doDir(f.getName() + "/", f, zos, dos, m); + if (arr$ != null) { + for (File f : arr$) { + if (!f.getName().startsWith("META-INF")) { + if (f.isFile()) { + doFile(f.getName(), f, zos, dos, m); + } else { + doDir(f.getName() + "/", f, zos, dos, m); + } } } } @@ -178,7 +181,7 @@ public class TinySign { } private static class SignatureOutputStream extends FilterOutputStream { - private Signature mSignature; + private final Signature mSignature; public SignatureOutputStream(OutputStream out, Signature sig) { super(out); @@ -207,7 +210,7 @@ public class TinySign { public void write(int b) throws IOException { try { - this.mSignature.update((byte)b); + this.mSignature.update((byte) b); } catch (SignatureException var3) { throw new IOException("SignatureException: " + var3); } diff --git a/app/src/main/java/org/autojs/autojs/external/foreground/ForegroundService.java b/app/src/main/java/org/autojs/autojs/external/foreground/ForegroundService.java index 33f3bcba..1f107ce9 100644 --- a/app/src/main/java/org/autojs/autojs/external/foreground/ForegroundService.java +++ b/app/src/main/java/org/autojs/autojs/external/foreground/ForegroundService.java @@ -1,5 +1,6 @@ package org.autojs.autojs.external.foreground; +import android.app.ActivityManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -20,7 +21,7 @@ public class ForegroundService extends Service { private static final int NOTIFICATION_ID = 1; - private static final String CHANEL_ID = ForegroundService.class.getName() + ".foreground"; + private static final String CHANNEL_ID = ForegroundService.class.getName() + ".foreground"; public static void start(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @@ -34,6 +35,16 @@ public class ForegroundService extends Service { context.stopService(new Intent(context, ForegroundService.class)); } + public static boolean isRunning(Context context) { + ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { + if (ForegroundService.class.getName().equals(service.service.getClassName())) { + return service.foreground; + } + } + return false; + } + @Override public void onCreate() { super.onCreate(); @@ -55,13 +66,13 @@ public class ForegroundService extends Service { createNotificationChannel(); } PendingIntent contentIntent = PendingIntent.getActivity(this, 0, MainActivity_.intent(this).get(), 0); - return new NotificationCompat.Builder(this, CHANEL_ID) + return new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle(getString(R.string.foreground_notification_title)) .setContentText(getString(R.string.foreground_notification_text)) .setSmallIcon(R.drawable.autojs_material) .setWhen(System.currentTimeMillis()) .setContentIntent(contentIntent) - .setChannelId(CHANEL_ID) + .setChannelId(CHANNEL_ID) .setVibrate(new long[0]) .build(); } @@ -72,7 +83,7 @@ public class ForegroundService extends Service { assert manager != null; CharSequence name = getString(R.string.foreground_notification_channel_name); String description = getString(R.string.foreground_notification_channel_name); - NotificationChannel channel = new NotificationChannel(CHANEL_ID, name, NotificationManager.IMPORTANCE_DEFAULT); + NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_DEFAULT); channel.setDescription(description); channel.enableLights(false); manager.createNotificationChannel(channel); diff --git a/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java b/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java index 0d9dab6d..d0999c3d 100644 --- a/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java +++ b/app/src/main/java/org/autojs/autojs/external/receiver/BaseBroadcastReceiver.java @@ -15,6 +15,8 @@ import org.autojs.autojs.model.script.ScriptFile; import org.autojs.autojs.timing.IntentTask; import org.autojs.autojs.timing.TimedTaskManager; +import java.util.Objects; + import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; @@ -22,6 +24,7 @@ public class BaseBroadcastReceiver extends BroadcastReceiver { private static final String LOG_TAG = "BaseBroadcastReceiver"; + @SuppressWarnings("ResultOfMethodCallIgnored") @SuppressLint("CheckResult") public void onReceive(Context context, Intent intent) { Log.d(LOG_TAG, "onReceive: intent = " + intent + ", this = " + this); @@ -31,7 +34,7 @@ public class BaseBroadcastReceiver extends BroadcastReceiver { .observeOn(AndroidSchedulers.mainThread()) .subscribe(intentTask -> runTask(context, intent, intentTask), Throwable::printStackTrace); } catch (Exception e) { - GlobalAppContext.toast(e.getMessage()); + GlobalAppContext.toast(e.getMessage(), Toast.LENGTH_LONG); } } @@ -40,7 +43,7 @@ public class BaseBroadcastReceiver extends BroadcastReceiver { ScriptFile file = new ScriptFile(task.getScriptPath()); ExecutionConfig config = new ExecutionConfig(); config.setArgument("intent", intent.clone()); - config.setWorkingDirectory(file.getParent()); + config.setWorkingDirectory(Objects.requireNonNull(file.getParent())); try { AutoJs.getInstance().getScriptEngineService().execute(file.toSource(), config); } catch (Exception e) { diff --git a/app/src/main/java/org/autojs/autojs/external/receiver/StaticBroadcastReceiver.java b/app/src/main/java/org/autojs/autojs/external/receiver/StaticBroadcastReceiver.java index 31ee2ba9..5c6cc8e4 100644 --- a/app/src/main/java/org/autojs/autojs/external/receiver/StaticBroadcastReceiver.java +++ b/app/src/main/java/org/autojs/autojs/external/receiver/StaticBroadcastReceiver.java @@ -25,7 +25,6 @@ public class StaticBroadcastReceiver extends BaseBroadcastReceiver { "android.intent.action.DREAMING_STOPPED", "android.intent.action.HEADSET_PLUG", "android.intent.action.INPUT_METHOD_CHANGED", - "android.intent.action.LOCALE_CHANGED", "android.intent.action.MEDIA_BUTTON", "android.intent.action.MEDIA_CHECKING", "android.intent.action.MEDIA_MOUNTED", diff --git a/app/src/main/java/org/autojs/autojs/external/tile/LayoutBoundsTile.java b/app/src/main/java/org/autojs/autojs/external/tile/LayoutBoundsTile.java index fa0b3f0b..b20db16e 100644 --- a/app/src/main/java/org/autojs/autojs/external/tile/LayoutBoundsTile.java +++ b/app/src/main/java/org/autojs/autojs/external/tile/LayoutBoundsTile.java @@ -1,6 +1,9 @@ package org.autojs.autojs.external.tile; +import android.content.Intent; import android.os.Build; +import android.service.quicksettings.Tile; + import androidx.annotation.RequiresApi; import com.stardust.view.accessibility.NodeInfo; @@ -16,7 +19,7 @@ public class LayoutBoundsTile extends LayoutInspectTileService { @Override public void close() { super.close(); - inactive(); + updateTile(); } }; } diff --git a/app/src/main/java/org/autojs/autojs/external/tile/LayoutHierarchyTile.java b/app/src/main/java/org/autojs/autojs/external/tile/LayoutHierarchyTile.java index 8efc553b..a93943aa 100644 --- a/app/src/main/java/org/autojs/autojs/external/tile/LayoutHierarchyTile.java +++ b/app/src/main/java/org/autojs/autojs/external/tile/LayoutHierarchyTile.java @@ -1,6 +1,8 @@ package org.autojs.autojs.external.tile; import android.os.Build; +import android.service.quicksettings.Tile; + import androidx.annotation.RequiresApi; import com.stardust.view.accessibility.NodeInfo; @@ -16,7 +18,7 @@ public class LayoutHierarchyTile extends LayoutInspectTileService { @Override public void close() { super.close(); - inactive(); + updateTile(); } }; } diff --git a/app/src/main/java/org/autojs/autojs/external/tile/LayoutInspectTileService.java b/app/src/main/java/org/autojs/autojs/external/tile/LayoutInspectTileService.java index 5fcd085e..521ab20c 100644 --- a/app/src/main/java/org/autojs/autojs/external/tile/LayoutInspectTileService.java +++ b/app/src/main/java/org/autojs/autojs/external/tile/LayoutInspectTileService.java @@ -4,18 +4,21 @@ import android.content.Intent; import android.os.Build; import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; + +import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; + import android.util.Log; import android.widget.Toast; import com.stardust.app.GlobalAppContext; +import com.stardust.autojs.core.accessibility.AccessibilityServiceTool; import com.stardust.view.accessibility.AccessibilityService; import com.stardust.view.accessibility.LayoutInspector; import com.stardust.view.accessibility.NodeInfo; import org.autojs.autojs.R; import org.autojs.autojs.autojs.AutoJs; -import org.autojs.autojs.tool.AccessibilityServiceTool; import org.autojs.autojs.ui.floating.FloatyWindowManger; import org.autojs.autojs.ui.floating.FullScreenFloatyWindow; @@ -29,13 +32,14 @@ public abstract class LayoutInspectTileService extends TileService implements La super.onCreate(); Log.d(getClass().getName(), "onCreate"); AutoJs.getInstance().getLayoutInspector().addCaptureAvailableListener(this); + activeTile(); } @Override public void onStartListening() { super.onStartListening(); Log.d(getClass().getName(), "onStartListening"); - inactive(); + updateTile(); } @Override @@ -47,27 +51,50 @@ public abstract class LayoutInspectTileService extends TileService implements La @Override public void onClick() { + // FIXME by SuperMonster003 as of Mar 19, 2022. + // ! Collapse quick settings panel. + // ! Sometimes, there'll be a delay for a few seconds. + // ! Dunno whether a better way exists. + sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + super.onClick(); Log.d(getClass().getName(), "onClick"); - // sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); if (AccessibilityService.Companion.getInstance() == null) { Toast.makeText(this, R.string.text_no_accessibility_permission_to_capture, Toast.LENGTH_SHORT).show(); - AccessibilityServiceTool.goToAccessibilitySetting(); - inactive(); - return; + if (!getAccessibilityServiceTool().enableAccessibilityServiceAutomaticallyIfNeeded()) { + getAccessibilityServiceTool().goToAccessibilitySetting(); + } + updateTile(); + } else { + mCapturing = true; + GlobalAppContext.postDelayed(() -> AutoJs.getInstance().getLayoutInspector().captureCurrentWindow(), 1000); } - mCapturing = true; - GlobalAppContext.postDelayed(() -> - AutoJs.getInstance().getLayoutInspector().captureCurrentWindow() - , 1000); } - protected void inactive() { + @NonNull + private AccessibilityServiceTool getAccessibilityServiceTool() { + return new AccessibilityServiceTool(this); + } + + protected void updateTile() { Tile qsTile = getQsTile(); - if (qsTile == null) - return; - qsTile.setState(Tile.STATE_INACTIVE); - qsTile.updateTile(); + if (qsTile != null) { + qsTile.updateTile(); + } + } + + public void activeTile() { + Tile qsTile = getQsTile(); + if (qsTile != null) { + qsTile.setState(Tile.STATE_ACTIVE); + } + } + + public void inactiveTile() { + Tile qsTile = getQsTile(); + if (qsTile != null) { + qsTile.setState(Tile.STATE_INACTIVE); + } } @Override @@ -80,7 +107,7 @@ public abstract class LayoutInspectTileService extends TileService implements La GlobalAppContext.post(() -> { FullScreenFloatyWindow window = onCreateWindow(capture); if (!FloatyWindowManger.addWindow(getApplicationContext(), window)) { - inactive(); + updateTile(); } }); } diff --git a/app/src/main/java/org/autojs/autojs/model/explorer/WorkspaceFileProvider.java b/app/src/main/java/org/autojs/autojs/model/explorer/WorkspaceFileProvider.java index fe0398ea..ad7fe37c 100644 --- a/app/src/main/java/org/autojs/autojs/model/explorer/WorkspaceFileProvider.java +++ b/app/src/main/java/org/autojs/autojs/model/explorer/WorkspaceFileProvider.java @@ -3,6 +3,8 @@ package org.autojs.autojs.model.explorer; import android.content.Context; import android.content.res.AssetManager; +import androidx.annotation.Nullable; + import com.stardust.autojs.project.ProjectConfig; import com.stardust.pio.PFile; import com.stardust.pio.PFiles; @@ -16,7 +18,6 @@ import java.io.FileNotFoundException; import java.io.InputStream; import io.reactivex.Observable; -import io.reactivex.Scheduler; import io.reactivex.Single; import io.reactivex.schedulers.Schedulers; @@ -26,11 +27,9 @@ public class WorkspaceFileProvider extends ExplorerFileProvider { private final PFile mSampleDir; private final AssetManager mAssetManager; - private final Context mContext; public WorkspaceFileProvider(Context context, FileFilter fileFilter) { super(fileFilter); - mContext = context; mAssetManager = context.getAssets(); mSampleDir = new PFile(context.getFilesDir(), SAMPLE_PATH); } @@ -100,17 +99,22 @@ public class WorkspaceFileProvider extends ExplorerFileProvider { }); } + @Nullable public Observable resetSample(ScriptFile file) { if (file.getPath().length() <= mSampleDir.getPath().length() + 1) { return null; } String pathOfSample = file.getPath().substring(mSampleDir.getPath().length()); String pathOfAsset = SAMPLE_PATH + pathOfSample; - return Observable.fromCallable(() -> { - InputStream stream = mAssetManager.open(pathOfAsset); - PFiles.copyStream(stream, file.getPath()); - return file; - }) + return Observable + .fromCallable(() -> { + try (InputStream stream = mAssetManager.open(pathOfAsset)) { + PFiles.copyStream(stream, file.getPath()); + } catch (FileNotFoundException ignored) { + return new ScriptFile(System.currentTimeMillis() + "\ufeff" + Math.random()); + } + return file; + }) .subscribeOn(Schedulers.io()); } diff --git a/app/src/main/java/org/autojs/autojs/model/script/PathChecker.java b/app/src/main/java/org/autojs/autojs/model/script/PathChecker.java index 401b6be5..585f65fa 100644 --- a/app/src/main/java/org/autojs/autojs/model/script/PathChecker.java +++ b/app/src/main/java/org/autojs/autojs/model/script/PathChecker.java @@ -44,17 +44,13 @@ public class PathChecker { private int checkWithStoragePermission(String path) { if (mContext instanceof Activity && !hasStorageReadPermission((Activity) mContext)) { - return com.stardust.autojs.R.string.text_no_file_rw_permission; + return com.stardust.autojs.R.string.text_no_storage_rw_permission; } return check(path); } private static boolean hasStorageReadPermission(Activity activity) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || - activity.checkSelfPermission(READ_EXTERNAL_STORAGE) == PERMISSION_GRANTED; - } - return true; + return activity.checkSelfPermission(READ_EXTERNAL_STORAGE) == PERMISSION_GRANTED; } diff --git a/app/src/main/java/org/autojs/autojs/network/NodeBB.java b/app/src/main/java/org/autojs/autojs/network/NodeBB.java deleted file mode 100644 index 24a4806c..00000000 --- a/app/src/main/java/org/autojs/autojs/network/NodeBB.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.autojs.autojs.network; - -import android.content.Context; -import android.util.Log; - -import com.google.gson.GsonBuilder; -import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory; -import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; -import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; -import org.autojs.autojs.R; -import org.autojs.autojs.network.api.ConfigApi; -import org.autojs.autojs.network.util.WebkitCookieManagerProxy; - -import java.io.IOException; -import java.util.Collections; -import java.util.Map; - -import io.reactivex.Observable; -import okhttp3.OkHttpClient; -import okhttp3.ResponseBody; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; - -/** - * Created by Stardust on 2017/9/20. - */ - -public class NodeBB { - - public static final String BASE_URL = "https://www.autojs.org/"; - private static final NodeBB sInstance = new NodeBB(); - private static final String LOG_TAG = "NodeBB"; - private Map mXCsrfToken; - - private Retrofit mRetrofit; - - NodeBB() { - mRetrofit = new Retrofit.Builder() - .baseUrl(BASE_URL) - .addConverterFactory(GsonConverterFactory.create(new GsonBuilder() - .setLenient() - .create())) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .addCallAdapterFactory(CoroutineCallAdapterFactory.create()) - .client(new OkHttpClient.Builder() - .cookieJar(new WebkitCookieManagerProxy()) - .build()) - .build(); - } - - public static NodeBB getInstance() { - return sInstance; - } - - public Retrofit getRetrofit() { - return mRetrofit; - } - - - public Observable> getXCsrfToken() { - if (mXCsrfToken != null) - return Observable.just(mXCsrfToken); - return mRetrofit.create(ConfigApi.class) - .getConfig() - .map(config -> mXCsrfToken = Collections.singletonMap("x-csrf-token", config.getCsrfToken())); - } - - public void invalidateXCsrfToken() { - mXCsrfToken = null; - } - - public static String getErrorMessage(Throwable e, Context context, String defaultMsg) { - if (!(e instanceof HttpException)) { - return defaultMsg; - } - HttpException httpException = (HttpException) e; - ResponseBody body = httpException.response().errorBody(); - if (body == null) - return defaultMsg; - try { - String errorMessage = getErrorMessage(context, httpException, body.string()); - return errorMessage == null ? defaultMsg : errorMessage; - } catch (IOException e1) { - e1.printStackTrace(); - return defaultMsg; - } - } - - private static String getErrorMessage(Context context, HttpException error, String errorBody) { - if (errorBody == null) - return null; - if (errorBody.contains("invalid-login-credentials")) { - return context.getString(R.string.nodebb_error_invalid_login_credentials); - } - if (errorBody.contains("change_password_error_match")) { - return context.getString(R.string.nodebb_error_change_password_error_match); - - } - if (errorBody.contains("change_password_error_length")) { - return context.getString(R.string.nodebb_error_change_password_error_length); - } - if (errorBody.contains("email-taken")) { - return context.getString(R.string.nodebb_error_email_taken); - } - if (error.code() == 403) { - return context.getString(R.string.nodebb_error_forbidden); - } - Log.d(LOG_TAG, "unknown error: " + errorBody, error); - return null; - } - - public static String url(String relativePath) { - return BASE_URL + relativePath; - } - - public static CharSequence getErrorMessage(Throwable error, Context context, int defaultMsg) { - return getErrorMessage(error, context, context.getString(defaultMsg)); - } -} diff --git a/app/src/main/java/org/autojs/autojs/network/TopicService.kt b/app/src/main/java/org/autojs/autojs/network/TopicService.kt deleted file mode 100644 index b5f960d6..00000000 --- a/app/src/main/java/org/autojs/autojs/network/TopicService.kt +++ /dev/null @@ -1,30 +0,0 @@ -package org.autojs.autojs.network - -import org.autojs.autojs.network.api.TopicApi -import org.autojs.autojs.network.entity.topic.Post -import org.autojs.autojs.network.entity.topic.Topic - -object TopicService { - - private const val CID_SCRIPTS = 9L - private val mRetrofit = NodeBB.getInstance().retrofit - private val mTopicApi = mRetrofit.create(TopicApi::class.java) - - suspend fun getTopics(cid: Long): List { - val category = mTopicApi.getCategory(cid).await() - return category.topics.filter { - it.appInfo != null - } - } - - suspend fun getMainPost(topic: Topic): Post { - val fullTopic = mTopicApi.getTopic(topic.tid.toLong()).await() - topic.mainPost = fullTopic.posts.first { post -> post.pid == topic.mainPid } - return topic.mainPost - } - - suspend fun getScriptsTopics(): List { - return getTopics(CID_SCRIPTS) - } - -} \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/network/UserService.java b/app/src/main/java/org/autojs/autojs/network/UserService.java deleted file mode 100644 index c2f8bebd..00000000 --- a/app/src/main/java/org/autojs/autojs/network/UserService.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.autojs.autojs.network; - -import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; -import org.autojs.autojs.network.api.UserApi; -import org.autojs.autojs.network.entity.notification.Notification; -import org.autojs.autojs.network.entity.notification.NotificationResponse; -import org.autojs.autojs.network.entity.user.User; -import com.stardust.util.Objects; -import com.tencent.bugly.crashreport.CrashReport; - -import org.greenrobot.eventbus.EventBus; - -import java.util.List; - -import io.reactivex.Observable; -import io.reactivex.schedulers.Schedulers; -import io.reactivex.subjects.PublishSubject; -import okhttp3.ResponseBody; -import retrofit2.Retrofit; - -/** - * Created by Stardust on 2017/9/20. - */ - -public class UserService { - - public static class LoginStateChange { - private final boolean mOnline; - - public LoginStateChange(boolean online) { - mOnline = online; - } - - public boolean isOnline() { - return mOnline; - } - } - - private static final UserService sInstance = new UserService(); - private final Retrofit mRetrofit; - private UserApi mUserApi; - private volatile User mUser; - - UserService() { - mRetrofit = NodeBB.getInstance().getRetrofit(); - mUserApi = mRetrofit.create(UserApi.class); - } - - public static UserService getInstance() { - return sInstance; - } - - public Observable login(String userName, final String password) { - return NodeBB.getInstance() - .getXCsrfToken() - .flatMap(token -> - mUserApi.login(token, userName, password) - .doOnError(error -> { - if (error instanceof HttpException && ((HttpException) error).code() == 403) { - NodeBB.getInstance().invalidateXCsrfToken(); - } - })) - .doOnComplete(this::refreshOnlineStatus); - - } - - - public Observable register(String email, String userName, String password) { - return NodeBB.getInstance() - .getXCsrfToken() - .flatMap(token -> mUserApi.register(token, email, userName, password, password)); - } - - public boolean isOnline() { - return mUser != null; - } - - private void setUser(User user) { - User old = mUser; - mUser = user; - if(mUser != null){ - CrashReport.setUserId(mUser.getUid()); - } - if (!Objects.equals(old, mUser)) { - if (user == null) { - NodeBB.getInstance().invalidateXCsrfToken(); - } - EventBus.getDefault().post(new LoginStateChange(user != null)); - } - } - - public Observable refreshOnlineStatus() { - PublishSubject online = PublishSubject.create(); - mRetrofit.create(UserApi.class) - .me() - .subscribeOn(Schedulers.io()) - .subscribe(user -> { - setUser(user); - online.onNext(true); - online.onComplete(); - }, error -> { - setUser(null); - online.onNext(false); - online.onComplete(); - }); - return online; - } - - public Observable logout() { - return NodeBB.getInstance() - .getXCsrfToken() - .flatMap(mUserApi::logout) - .doOnError(Throwable::printStackTrace) - .doOnComplete(this::refreshOnlineStatus); - } - - public Observable me() { - return NodeBB.getInstance().getRetrofit() - .create(UserApi.class) - .me() - .doOnNext(this::setUser) - .doOnError(error -> setUser(null)); - } - - - public Observable> getNotifications() { - return NodeBB.getInstance().getRetrofit() - .create(UserApi.class) - .getNotifications() - .map(NotificationResponse::getNotifications); - } - -} diff --git a/app/src/main/java/org/autojs/autojs/network/VersionService.java b/app/src/main/java/org/autojs/autojs/network/VersionService.java new file mode 100644 index 00000000..f29aea4f --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/network/VersionService.java @@ -0,0 +1,48 @@ +package org.autojs.autojs.network; + +import androidx.annotation.NonNull; + +import com.google.gson.GsonBuilder; +import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; +import com.stardust.app.GlobalAppContext; + +import org.autojs.autojs.R; +import org.autojs.autojs.network.api.UpdateCheckApi; +import org.autojs.autojs.network.entity.VersionInfo; + +import io.reactivex.Observable; +import io.reactivex.schedulers.Schedulers; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +/** + * Created by Stardust on 2017/9/20. + * Modified by SuperMonster003 as of Feb 26, 2022. + */ + +public class VersionService { + + private static final String baseUrl = "https://raw.githubusercontent.com/"; + + private static Retrofit mRetrofit; + + public static Observable checkForUpdates() { + Retrofit mRetrofit = getRetrofit(); + return mRetrofit.create(UpdateCheckApi.class) + .checkForUpdates() + .subscribeOn(Schedulers.io()); + } + + @NonNull + private static Retrofit getRetrofit() { + if (mRetrofit == null) { + mRetrofit = new Retrofit.Builder() + .baseUrl(baseUrl) + .addConverterFactory(GsonConverterFactory.create(new GsonBuilder().setLenient().create())) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .build(); + } + return mRetrofit; + } + +} diff --git a/app/src/main/java/org/autojs/autojs/network/api/ConfigApi.java b/app/src/main/java/org/autojs/autojs/network/api/ConfigApi.java deleted file mode 100644 index 74b54964..00000000 --- a/app/src/main/java/org/autojs/autojs/network/api/ConfigApi.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.autojs.autojs.network.api; - -import org.autojs.autojs.network.entity.config.Config; - -import io.reactivex.Observable; -import retrofit2.http.GET; - -/** - * Created by Stardust on 2017/10/26. - */ - -public interface ConfigApi { - - @GET("/api/config") - Observable getConfig(); - -} diff --git a/app/src/main/java/org/autojs/autojs/network/api/TopicApi.kt b/app/src/main/java/org/autojs/autojs/network/api/TopicApi.kt deleted file mode 100644 index 78784854..00000000 --- a/app/src/main/java/org/autojs/autojs/network/api/TopicApi.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.autojs.autojs.network.api - -import kotlinx.coroutines.Deferred -import org.autojs.autojs.network.entity.topic.Category -import org.autojs.autojs.network.entity.topic.Post -import org.autojs.autojs.network.entity.topic.Topic -import retrofit2.http.GET -import retrofit2.http.Path - -interface TopicApi { - - @GET("/api/category/{cid}") - fun getCategory(@Path("cid") cid: Long): Deferred - - @GET("/api/topic/{tid}") - fun getTopic(@Path("tid") pid: Long): Deferred - - -} \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/network/api/UpdateCheckApi.java b/app/src/main/java/org/autojs/autojs/network/api/UpdateCheckApi.java new file mode 100644 index 00000000..7a59e277 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/network/api/UpdateCheckApi.java @@ -0,0 +1,20 @@ +package org.autojs.autojs.network.api; + +import org.autojs.autojs.network.entity.VersionInfo; + +import io.reactivex.Observable; +import retrofit2.http.GET; +import retrofit2.http.Headers; + +/** + * Created by Stardust on 2017/9/20. + * Modified by SuperMonster003 as of Feb 28, 2022. + */ + +public interface UpdateCheckApi { + + @GET("/SuperMonster003/AutoJs6/master/project-versions.json") + @Headers("Cache-Control: no-cache") + Observable checkForUpdates(); + +} diff --git a/app/src/main/java/org/autojs/autojs/network/api/UserApi.java b/app/src/main/java/org/autojs/autojs/network/api/UserApi.java deleted file mode 100644 index 01f09aa9..00000000 --- a/app/src/main/java/org/autojs/autojs/network/api/UserApi.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.autojs.autojs.network.api; - -import org.autojs.autojs.network.entity.notification.NotificationResponse; -import org.autojs.autojs.network.entity.user.User; - -import java.util.Map; - -import io.reactivex.Observable; -import okhttp3.ResponseBody; -import retrofit2.http.Field; -import retrofit2.http.FormUrlEncoded; -import retrofit2.http.GET; -import retrofit2.http.HeaderMap; -import retrofit2.http.POST; - -/** - * Created by Stardust on 2017/9/20. - */ - -public interface UserApi { - - @GET("/api/me") - Observable me(); - - @FormUrlEncoded - @POST("/login") - Observable login(@HeaderMap Map csrfToken, @Field("username") String userName, @Field("password") String password); - - @FormUrlEncoded - @POST("/register") - Observable register(@HeaderMap Map csrfToken, @Field("email") String email, - @Field("username") String userName, @Field("password") String password, @Field("password-confirm") String repeatPassword); - - - @POST("/logout") - Observable logout(@HeaderMap Map csrfToken); - - @GET("/api/notifications") - Observable getNotifications(); -} diff --git a/app/src/main/java/org/autojs/autojs/network/download/DownloadManager.java b/app/src/main/java/org/autojs/autojs/network/download/DownloadManager.java index 88b28c57..e078b0da 100644 --- a/app/src/main/java/org/autojs/autojs/network/download/DownloadManager.java +++ b/app/src/main/java/org/autojs/autojs/network/download/DownloadManager.java @@ -1,5 +1,8 @@ package org.autojs.autojs.network.download; +import com.stardust.app.GlobalAppContext; + +import android.annotation.SuppressLint; import android.content.Context; import android.util.Log; @@ -9,8 +12,6 @@ import com.stardust.concurrent.VolatileBox; import com.stardust.pio.PFiles; import org.autojs.autojs.R; -import org.autojs.autojs.model.script.ScriptFile; -import org.autojs.autojs.network.NodeBB; import org.autojs.autojs.network.api.DownloadApi; import org.autojs.autojs.tool.SimpleObserver; @@ -18,7 +19,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.SocketTimeoutException; +import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.concurrent.ConcurrentHashMap; @@ -42,13 +43,12 @@ public class DownloadManager { private static DownloadManager sInstance; private static final int RETRY_COUNT = 3; - private Retrofit mRetrofit; - private DownloadApi mDownloadApi; - private ConcurrentHashMap> mDownloadStatuses = new ConcurrentHashMap<>(); + private final DownloadApi mDownloadApi; + private final ConcurrentHashMap> mDownloadStatuses = new ConcurrentHashMap<>(); public DownloadManager() { - mRetrofit = new Retrofit.Builder() - .baseUrl(NodeBB.BASE_URL) + Retrofit mRetrofit = new Retrofit.Builder() + .baseUrl("https://www.autojs.org") .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(new OkHttpClient.Builder() .addInterceptor(chain -> { @@ -81,9 +81,15 @@ public class DownloadManager { if (i < 0) { i = url.lastIndexOf('/'); } - return URLDecoder.decode(url.substring(i + 1)); + try { + return URLDecoder.decode(url.substring(i + 1), "UTF-8"); + } catch (UnsupportedEncodingException e) { + return GlobalAppContext.getString(R.string.text_should_never_happen); + } } + @SuppressWarnings("ResultOfMethodCallIgnored") + @SuppressLint("CheckResult") public Observable download(String url, String path) { DownloadTask task = new DownloadTask(url, path); mDownloadApi.download(url) @@ -112,7 +118,7 @@ public class DownloadManager { DownloadManager.getInstance().download(url, path) .observeOn(AndroidSchedulers.mainThread()) .doOnNext(progressDialog::setProgress) - .subscribe(new SimpleObserver() { + .subscribe(new SimpleObserver<>() { @Override public void onComplete() { progressDialog.dismiss(); @@ -139,12 +145,12 @@ public class DownloadManager { private class DownloadTask { - private String mUrl; - private String mPath; - private VolatileBox mStatus; + private final String mUrl; + private final String mPath; + private final VolatileBox mStatus; private InputStream mInputStream; private FileOutputStream mFileOutputStream; - private PublishSubject mProgress; + private final PublishSubject mProgress; public DownloadTask(String url, String path) { mUrl = url; @@ -190,7 +196,7 @@ public class DownloadManager { } } - private void onCancel() throws IOException { + private void onCancel() { recycle(); // TODO: 2017/12/6 notify? } diff --git a/app/src/main/java/org/autojs/autojs/network/entity/VersionInfo.java b/app/src/main/java/org/autojs/autojs/network/entity/VersionInfo.java index ae023b01..6fd4cf8e 100644 --- a/app/src/main/java/org/autojs/autojs/network/entity/VersionInfo.java +++ b/app/src/main/java/org/autojs/autojs/network/entity/VersionInfo.java @@ -1,85 +1,29 @@ package org.autojs.autojs.network.entity; -import android.text.TextUtils; - +import androidx.annotation.NonNull; import org.autojs.autojs.BuildConfig; -import org.json.JSONObject; - -import java.util.List; - /** * Created by Stardust on 2017/9/20. */ public class VersionInfo { - public int versionCode; - public String releaseNotes; - public String versionName; - public List downloads; - public List oldVersions; - public int deprecated; - public String downloadUrl; - - public boolean isValid() { - return downloads != null && !downloads.isEmpty() && versionCode > 0 - && !TextUtils.isEmpty(versionName) && !TextUtils.isEmpty(releaseNotes); - } - - public OldVersion getOldVersion(int versionCode) { - for (OldVersion oldVersion : oldVersions) { - if (oldVersion.versionCode == versionCode) { - return oldVersion; - } - } - return null; - } + public int appVersionCode; + public String appVersionName; public boolean isNewer() { - return versionCode > BuildConfig.VERSION_CODE; + return appVersionCode > BuildConfig.VERSION_CODE; } + @NonNull @Override public String toString() { return "UpdateInfo{" + - "versionCode=" + versionCode + - ", releaseNotes='" + releaseNotes + '\'' + - ", versionName='" + versionName + '\'' + - ", downloads=" + downloads + - ", oldVersions=" + oldVersions + - ", deprecated=" + deprecated + - ", downloadUrl='" + downloadUrl + '\'' + + "appVersionCode=" + appVersionCode + + ", appVersionName='" + appVersionName + '\'' + '}'; } - - public static class OldVersion extends JSONObject { - - public int versionCode; - public String issues; - - @Override - public String toString() { - return "OldVersion{" + - "versionCode=" + versionCode + - ", issues='" + issues + '\'' + - '}'; - } - } - - public static class Download extends JSONObject { - - public String name; - public String url; - - @Override - public String toString() { - return "Download{" + - "name='" + name + '\'' + - ", url='" + url + '\'' + - '}'; - } - } } diff --git a/app/src/main/java/org/autojs/autojs/pluginclient/DevPluginResponseHandler.java b/app/src/main/java/org/autojs/autojs/pluginclient/DevPluginResponseHandler.java index 527bfa3e..38599083 100644 --- a/app/src/main/java/org/autojs/autojs/pluginclient/DevPluginResponseHandler.java +++ b/app/src/main/java/org/autojs/autojs/pluginclient/DevPluginResponseHandler.java @@ -2,6 +2,7 @@ package org.autojs.autojs.pluginclient; import android.annotation.SuppressLint; import android.text.TextUtils; +import android.widget.Toast; import com.google.gson.JsonElement; import com.google.gson.JsonNull; @@ -175,8 +176,8 @@ public class DevPluginResponseHandler implements Handler { }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(dest -> GlobalAppContext.toast(R.string.text_project_save_success, dest), - err -> GlobalAppContext.toast(R.string.text_project_save_error, err.getMessage()) + .subscribe(dest -> GlobalAppContext.toast(R.string.text_project_save_success + "\n" + dest, Toast.LENGTH_LONG), + err -> GlobalAppContext.toast(R.string.text_project_save_error + "\n" + err.getMessage(), Toast.LENGTH_LONG) ); } diff --git a/app/src/main/java/org/autojs/autojs/pluginclient/DevPluginService.java b/app/src/main/java/org/autojs/autojs/pluginclient/DevPluginService.java index d0ff97e1..19537e90 100644 --- a/app/src/main/java/org/autojs/autojs/pluginclient/DevPluginService.java +++ b/app/src/main/java/org/autojs/autojs/pluginclient/DevPluginService.java @@ -166,7 +166,7 @@ public class DevPluginService { } @AnyThread - // FIXME by SuperMonster003 on Dec 29, 2021 + // FIXME by SuperMonster003 as of Dec 29, 2021. // ! Would print double (may be even more times) the amount of // ! messages on VSCode when multi connection were established. public void print(String log) { diff --git a/app/src/main/java/org/autojs/autojs/pluginclient/JsonSocket.java b/app/src/main/java/org/autojs/autojs/pluginclient/JsonSocket.java index 1e6bb3f0..e6833af5 100644 --- a/app/src/main/java/org/autojs/autojs/pluginclient/JsonSocket.java +++ b/app/src/main/java/org/autojs/autojs/pluginclient/JsonSocket.java @@ -112,10 +112,30 @@ abstract public class JsonSocket extends Socket { private void onMessageDispatch(JsonSocket jsonSocket, String str) throws IOException { Log.d(TAG, "Input total str: " + str); Log.d(TAG, "Input total length: " + str.length()); - String header = str.substring(0, HEADER_SIZE); - Log.d(TAG, "Input data length: " + new Buffer(header.getBytes()).readInt32BE(0)); - Log.d(TAG, "Input data type: " + new Buffer(header.getBytes()).readInt32BE(4)); - String message = str.substring(HEADER_SIZE); + + if (str.length() < HEADER_SIZE) { + Log.w(TAG, "Message with length less than HEADER_SIZE has been adopted"); + return; + } + + int idxDataStart = str.indexOf("{"); + + if (idxDataStart < 0) { + Log.w(TAG, "Message without data has been adopted"); + return; + } + + String header = str.substring(0, idxDataStart); + + if (header.length() == 8) { + Log.d(TAG, "Input data length: " + new Buffer(header.getBytes()).readInt32BE(0)); + Log.d(TAG, "Input data type: " + new Buffer(header.getBytes()).readInt32BE(4)); + } else if (header.length() >= 4) { + Log.d(TAG, "Input data type: " + new Buffer(header.getBytes()).readInt32BE(header.length() - 4)); + } + + String message = str.substring(idxDataStart); + Log.d(TAG, "Input message length: " + message.length()); Log.d(TAG, "Input message: " + message); @@ -128,24 +148,29 @@ abstract public class JsonSocket extends Socket { private void writeMap(String type, Map map) { JsonObject data = new JsonObject(); for (Map.Entry entry : map.entrySet()) { - Object value = entry.getValue(); - if (value instanceof String) { - data.addProperty(entry.getKey(), (String) value); - } else if (value instanceof Character) { - data.addProperty(entry.getKey(), (Character) value); - } else if (value instanceof Number) { - data.addProperty(entry.getKey(), (Number) value); - } else if (value instanceof Boolean) { - data.addProperty(entry.getKey(), (Boolean) value); - } else if (value instanceof JsonElement) { - data.add(entry.getKey(), (JsonElement) value); - } else { - throw new IllegalArgumentException("cannot put value " + value + " into json"); - } + addProperty(entry, data); } writeData(type, data); } + private void addProperty(Map.Entry entry, JsonObject data) { + Object value = entry.getValue(); + String key = entry.getKey(); + if (value instanceof String) { + data.addProperty(key, (String) value); + } else if (value instanceof Character) { + data.addProperty(key, (Character) value); + } else if (value instanceof Number) { + data.addProperty(key, (Number) value); + } else if (value instanceof Boolean) { + data.addProperty(key, (Boolean) value); + } else if (value instanceof JsonElement) { + data.add(key, (JsonElement) value); + } else { + throw new IllegalArgumentException("cannot put value " + value + " into json"); + } + } + @SuppressWarnings("SameParameterValue") @AnyThread public void writePair(String type, Pair pair) { diff --git a/app/src/main/java/org/autojs/autojs/storage/file/FileObservable.java b/app/src/main/java/org/autojs/autojs/storage/file/FileObservable.java index 196b0048..6a1c8e2a 100644 --- a/app/src/main/java/org/autojs/autojs/storage/file/FileObservable.java +++ b/app/src/main/java/org/autojs/autojs/storage/file/FileObservable.java @@ -2,8 +2,6 @@ package org.autojs.autojs.storage.file; import com.stardust.pio.PFiles; -import org.apache.commons.io.FileUtils; - import java.io.File; import java.io.IOException; @@ -53,7 +51,7 @@ public class FileObservable { copyDir(fromFile, toFile, deleteOld, progress); } else { PFiles.ensureDir(toFile.getPath()); - FileUtils.copyFile(fromFile, toFile); + PFiles.copy(fromFile.getPath(), toFile.getPath()); } if (deleteOld) { fromFile.delete(); diff --git a/app/src/main/java/org/autojs/autojs/tool/AccessibilityServiceTool.java b/app/src/main/java/org/autojs/autojs/tool/AccessibilityServiceTool.java deleted file mode 100644 index adce4757..00000000 --- a/app/src/main/java/org/autojs/autojs/tool/AccessibilityServiceTool.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.autojs.autojs.tool; - -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.text.TextUtils; - -import com.stardust.app.GlobalAppContext; - -import org.autojs.autojs.Pref; -import org.autojs.autojs.R; - -import com.stardust.autojs.core.accessibility.AccessibilityService; -import com.stardust.autojs.core.util.ProcessShell; -import com.stardust.view.accessibility.AccessibilityServiceUtils; - -import java.util.Locale; - -/** - * Created by Stardust on 2017/1/26. - */ - -public class AccessibilityServiceTool { - - private static final Class sAccessibilityServiceClass = AccessibilityService.class; - - public static void enableAccessibilityService() { - if (Pref.shouldEnableAccessibilityServiceByRoot()) { - if (!enableAccessibilityServiceByRoot(sAccessibilityServiceClass)) { - goToAccessibilitySetting(); - } - } else { - goToAccessibilitySetting(); - } - } - - public static void goToAccessibilitySetting() { - Context context = GlobalAppContext.get(); - if (Pref.isFirstGoToAccessibilitySetting()) { - GlobalAppContext.toast(context.getString(R.string.text_please_choose) + " " + context.getString(R.string.app_name)); - } - try { - AccessibilityServiceUtils.INSTANCE.goToAccessibilitySetting(context); - } catch (ActivityNotFoundException e) { - GlobalAppContext.toast(context.getString(R.string.go_to_accessibility_settings) + context.getString(R.string.app_name)); - } - } - - private static final String cmd = """ - enabled=$(settings get secure enabled_accessibility_services) - pkg=%s - if [[ $enabled == *$pkg* ]] - then - echo already_enabled - else - enabled=$pkg:$enabled - settings put secure enabled_accessibility_services $enabled - fi - settings put secure accessibility_enabled 1 - """; - - public static boolean enableAccessibilityServiceByRoot(Class accessibilityService) { - String serviceName = GlobalAppContext.get().getPackageName() + "/" + accessibilityService.getName(); - try { - return TextUtils.isEmpty(ProcessShell.execCommand(String.format(Locale.getDefault(), cmd, serviceName), true).error); - } catch (Exception e) { - return false; - } - } - - public static boolean enableAccessibilityServiceByRootAndWaitFor(long timeOut) { - if (enableAccessibilityServiceByRoot(sAccessibilityServiceClass)) { - return AccessibilityService.Companion.waitForEnabled(timeOut); - } - return false; - } - - public static void enableAccessibilityServiceByRootIfNeeded() { - if (AccessibilityService.Companion.getInstance() == null) - if (Pref.shouldEnableAccessibilityServiceByRoot()) { - AccessibilityServiceTool.enableAccessibilityServiceByRoot(sAccessibilityServiceClass); - } - } - - public static boolean isAccessibilityServiceEnabled(Context context) { - return AccessibilityServiceUtils.INSTANCE.isAccessibilityServiceEnabled(context, sAccessibilityServiceClass); - } -} diff --git a/app/src/main/java/org/autojs/autojs/tool/CrashHandler.java b/app/src/main/java/org/autojs/autojs/tool/CrashHandler.java index 91d5f70b..a23a31a3 100644 --- a/app/src/main/java/org/autojs/autojs/tool/CrashHandler.java +++ b/app/src/main/java/org/autojs/autojs/tool/CrashHandler.java @@ -45,11 +45,11 @@ public class CrashHandler extends CrashReport.CrashHandleCallback implements Unc return; } AccessibilityService service = AccessibilityService.Companion.getInstance(); - if (service != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (service != null) { Log.d(TAG, "disable service: " + service); service.disableSelf(); } else { - BuglyLog.d(TAG, "cannot disable service: " + service); + BuglyLog.d(TAG, "cannot disable service: " + AccessibilityService.class.getSimpleName()); } if (BuildConfig.DEBUG) { mSystemHandler.uncaughtException(thread, ex); diff --git a/app/src/main/java/org/autojs/autojs/tool/Observers.java b/app/src/main/java/org/autojs/autojs/tool/Observers.java index 0a498878..16b442a0 100644 --- a/app/src/main/java/org/autojs/autojs/tool/Observers.java +++ b/app/src/main/java/org/autojs/autojs/tool/Observers.java @@ -2,14 +2,13 @@ package org.autojs.autojs.tool; import com.stardust.app.GlobalAppContext; -import org.autojs.autojs.model.explorer.ExplorerFileItem; - import io.reactivex.Observer; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Consumer; public class Observers { + @SuppressWarnings("rawtypes") private static final Consumer CONSUMER = ignored -> { }; @@ -30,7 +29,7 @@ public class Observers { } public static Observer emptyObserver() { - return new Observer() { + return new Observer<>() { @Override public void onSubscribe(Disposable d) { diff --git a/app/src/main/java/org/autojs/autojs/tool/RootTool.java b/app/src/main/java/org/autojs/autojs/tool/RootTool.java deleted file mode 100644 index 070508af..00000000 --- a/app/src/main/java/org/autojs/autojs/tool/RootTool.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.autojs.autojs.tool; - -import com.stardust.autojs.core.util.ProcessShell; -import com.stericson.RootShell.RootShell; - -/** - * Created by Stardust on 2018/1/26. - */ - -public class RootTool { - - public static boolean isRootAvailable() { - try { - return RootShell.isRootAvailable(); - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - private static final String cmd = """ - enabled=$(settings get system pointer_location) - if [[ $enabled == 1 ]] - then - settings put system pointer_location 0 - else - settings put system pointer_location 1 - fi - """; - - public static void togglePointerLocation() { - try { - ProcessShell.execCommand(cmd, true); - } catch (Exception ignored) { - } - } - - public static void setPointerLocationEnabled(boolean enabled) { - try { - ProcessShell.execCommand("settings put system pointer_location " + (enabled ? 1 : 0), true); - } catch (Exception ignored) { - - } - } -} diff --git a/app/src/main/java/org/autojs/autojs/tool/ThreadTool.java b/app/src/main/java/org/autojs/autojs/tool/ThreadTool.java index 82cbf392..17342276 100644 --- a/app/src/main/java/org/autojs/autojs/tool/ThreadTool.java +++ b/app/src/main/java/org/autojs/autojs/tool/ThreadTool.java @@ -13,7 +13,7 @@ public class ThreadTool { //noinspection BusyWait Thread.sleep(200); } catch (InterruptedException ignore) { - // ignored + // Ignored. } } result.set(true); diff --git a/app/src/main/java/org/autojs/autojs/ui/BaseActivity.java b/app/src/main/java/org/autojs/autojs/ui/BaseActivity.java index a47e4144..b70cfc62 100644 --- a/app/src/main/java/org/autojs/autojs/ui/BaseActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/BaseActivity.java @@ -1,45 +1,55 @@ package org.autojs.autojs.ui; +import static android.content.pm.PackageManager.PERMISSION_DENIED; + +import android.content.Context; +import android.content.res.Configuration; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; +import android.view.Menu; +import android.view.View; + import androidx.annotation.CallSuper; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; -import androidx.core.content.ContextCompat; +import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatDelegate; import androidx.appcompat.widget.Toolbar; -import android.view.Menu; -import android.view.View; +import androidx.core.content.ContextCompat; import com.stardust.app.GlobalAppContext; import com.stardust.theme.ThemeColorManager; +import com.zeugmasolutions.localehelper.LocaleHelper; +import com.zeugmasolutions.localehelper.LocaleHelperActivityDelegate; +import com.zeugmasolutions.localehelper.LocaleHelperActivityDelegateImpl; import org.autojs.autojs.Pref; import org.autojs.autojs.R; import java.util.ArrayList; import java.util.List; - -import static android.content.pm.PackageManager.PERMISSION_DENIED; +import java.util.Locale; /** * Created by Stardust on 2017/1/23. + * Modified by SuperMonster003 as of Feb 18, 2022. */ public abstract class BaseActivity extends AppCompatActivity { protected static final int PERMISSION_REQUEST_CODE = 11186; private boolean mShouldApplyDayNightModeForOptionsMenu = true; + private final LocaleHelperActivityDelegate localeDelegate = new LocaleHelperActivityDelegateImpl(); + private final LocaleHelper localeHelper = LocaleHelper.INSTANCE; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { - // Dunno how to disable the splash screen. T-T - // com.android.server.policy.PhoneWindowManager.SHOW_SPLASH_SCREENS = false; super.onCreate(savedInstanceState); + localeDelegate.onCreate(this); } protected void applyDayNightMode() { @@ -50,6 +60,20 @@ public abstract class BaseActivity extends AppCompatActivity { }); } + @NonNull + @Override + public AppCompatDelegate getDelegate() { + return localeDelegate.getAppCompatDelegate(super.getDelegate()); + } + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(localeDelegate.attachBaseContext(newBase)); + if (localeHelper.hasLocaleSelection(this)) { + localeHelper.setLocale(this, localeHelper.getLocale(this)); + } + } + public void setNightModeEnabled(boolean enabled) { if (enabled) { getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES); @@ -70,9 +94,45 @@ public abstract class BaseActivity extends AppCompatActivity { } - @SuppressWarnings("unchecked") + @Override + protected void onResume() { + super.onResume(); + localeDelegate.onResumed(this); + } + + @Override + protected void onPause() { + super.onPause(); + localeDelegate.onPaused(); + } + + @Override + public Context createConfigurationContext(Configuration overrideConfiguration) { + Context context = super.createConfigurationContext(overrideConfiguration); + return localeHelper.onAttach(context); + } + + @Override + public Context getApplicationContext() { + return localeDelegate.getApplicationContext(super.getApplicationContext()); + } + + public void updateLocale(Locale locale) { + localeDelegate.setLocale(this, locale); + } + + public void setLocaleFollowSystem() { + Locale systemLocale = localeHelper.getSystemLocale(); + Locale currentLocale = localeHelper.getLocale(this); + + if (currentLocale != systemLocale) { + localeDelegate.setLocale(this, systemLocale); + } + localeDelegate.clearLocaleSelection(this); + } + public T $(int resId) { - return (T) findViewById(resId); + return findViewById(resId); } protected void checkPermission(String... permissions) { @@ -82,7 +142,6 @@ public abstract class BaseActivity extends AppCompatActivity { } } - @RequiresApi(api = Build.VERSION_CODES.M) private String[] getRequestPermissions(String[] permissions) { List list = new ArrayList<>(); @@ -91,7 +150,7 @@ public abstract class BaseActivity extends AppCompatActivity { list.add(permission); } } - return list.toArray(new String[list.size()]); + return list.toArray(new String[0]); } public void setToolbarAsBack(String title) { @@ -102,12 +161,16 @@ public abstract class BaseActivity extends AppCompatActivity { Toolbar toolbar = activity.findViewById(id); toolbar.setTitle(title); activity.setSupportActionBar(toolbar); - if (activity.getSupportActionBar() != null) { + if (getSupportActionBar(activity) != null) { toolbar.setNavigationOnClickListener(v -> activity.finish()); - activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar(activity).setDisplayHomeAsUpEnabled(true); } } + private static ActionBar getSupportActionBar(AppCompatActivity activity) { + return activity.getSupportActionBar(); + } + @CallSuper @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { @@ -131,7 +194,6 @@ public abstract class BaseActivity extends AppCompatActivity { @Override public boolean onCreateOptionsMenu(Menu menu) { - return super.onCreateOptionsMenu(menu); } } diff --git a/app/src/main/java/org/autojs/autojs/ui/codegeneration/CodeGenerateDialog.java b/app/src/main/java/org/autojs/autojs/ui/codegeneration/CodeGenerateDialog.java index 3287dd16..c9eecc37 100644 --- a/app/src/main/java/org/autojs/autojs/ui/codegeneration/CodeGenerateDialog.java +++ b/app/src/main/java/org/autojs/autojs/ui/codegeneration/CodeGenerateDialog.java @@ -44,16 +44,16 @@ public class CodeGenerateDialog extends ThemeColorMaterialDialogBuilder { .addOption(R.string.text_using_text_selector, true) .addOption(R.string.text_using_desc_selector, true)) .add(new OptionGroup(R.string.text_select) - .addOption(R.string.text_find_one, true) - .addOption(R.string.text_until_find) - .addOption(R.string.text_wait_for) - .addOption(R.string.text_selector_exists)) + .addOption(R.string.text_select_by_find_one, true) + .addOption(R.string.text_select_by_until_find) + .addOption(R.string.text_select_by_wait_for) + .addOption(R.string.text_select_by_exists)) .add(new OptionGroup(R.string.text_action) - .addOption(R.string.text_click) - .addOption(R.string.text_long_click) - .addOption(R.string.text_set_text) - .addOption(R.string.text_scroll_forward) - .addOption(R.string.text_scroll_backward)) + .addOption(R.string.text_act_by_click) + .addOption(R.string.text_act_by_long_click) + .addOption(R.string.text_act_by_set_text) + .addOption(R.string.text_act_by_scroll_forward) + .addOption(R.string.text_act_by_scroll_backward)) .list(); @BindView(R.id.options) @@ -101,32 +101,32 @@ public class CodeGenerateDialog extends ThemeColorMaterialDialogBuilder { private void setAction(CodeGenerator generator) { OptionGroup action = getOptionGroup(R.string.text_action); - if (action.getOption(R.string.text_click).checked) { + if (action.getOption(R.string.text_act_by_click).checked) { generator.setAction(AccessibilityNodeInfoCompat.ACTION_CLICK); } - if (action.getOption(R.string.text_long_click).checked) { + if (action.getOption(R.string.text_act_by_long_click).checked) { generator.setAction(AccessibilityNodeInfoCompat.ACTION_LONG_CLICK); } - if (action.getOption(R.string.text_scroll_forward).checked) { + if (action.getOption(R.string.text_act_by_scroll_forward).checked) { generator.setAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD); } - if (action.getOption(R.string.text_scroll_backward).checked) { + if (action.getOption(R.string.text_act_by_scroll_backward).checked) { generator.setAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD); } } private int getSearchMode() { OptionGroup selectMode = getOptionGroup(R.string.text_select); - if (selectMode.getOption(R.string.text_find_one).checked) { + if (selectMode.getOption(R.string.text_select_by_find_one).checked) { return CodeGenerator.FIND_ONE; } - if (selectMode.getOption(R.string.text_until_find).checked) { + if (selectMode.getOption(R.string.text_select_by_until_find).checked) { return CodeGenerator.UNTIL_FIND; } - if (selectMode.getOption(R.string.text_wait_for).checked) { + if (selectMode.getOption(R.string.text_select_by_wait_for).checked) { return CodeGenerator.WAIT_FOR; } - if (selectMode.getOption(R.string.text_selector_exists).checked) { + if (selectMode.getOption(R.string.text_select_by_exists).checked) { return CodeGenerator.EXISTS; } return CodeGenerator.FIND_ONE; diff --git a/app/src/main/java/org/autojs/autojs/ui/common/NotAskAgainDialog.java b/app/src/main/java/org/autojs/autojs/ui/common/NotAskAgainDialog.java index e02b359c..98f9306a 100644 --- a/app/src/main/java/org/autojs/autojs/ui/common/NotAskAgainDialog.java +++ b/app/src/main/java/org/autojs/autojs/ui/common/NotAskAgainDialog.java @@ -35,7 +35,7 @@ public class NotAskAgainDialog extends MaterialDialog { super(context); mKeyRemind = key; readRemindStatus(); - checkBoxPrompt(context.getString(R.string.text_do_not_remind_again), false, (buttonView, isChecked) -> setRemindState(!isChecked)); + checkBoxPrompt(context.getString(R.string.text_do_not_show_again), false, (buttonView, isChecked) -> setRemindState(!isChecked)); } public MaterialDialog show() { diff --git a/app/src/main/java/org/autojs/autojs/ui/common/ProgressDialog.java b/app/src/main/java/org/autojs/autojs/ui/common/ProgressDialog.java index 54e2924f..be3a2a33 100644 --- a/app/src/main/java/org/autojs/autojs/ui/common/ProgressDialog.java +++ b/app/src/main/java/org/autojs/autojs/ui/common/ProgressDialog.java @@ -14,7 +14,7 @@ public class ProgressDialog { private MaterialDialog mDialog; public ProgressDialog(Context context) { - this(context, R.string.text_on_progress); + this(context, R.string.text_in_progress); } public ProgressDialog(Context context, int resId) { diff --git a/app/src/main/java/org/autojs/autojs/ui/common/RxDialogs.java b/app/src/main/java/org/autojs/autojs/ui/common/RxDialogs.java index 6990a32a..b1949ddf 100644 --- a/app/src/main/java/org/autojs/autojs/ui/common/RxDialogs.java +++ b/app/src/main/java/org/autojs/autojs/ui/common/RxDialogs.java @@ -18,8 +18,8 @@ public class RxDialogs { public static Observable confirm(Context context, String text) { PublishSubject subject = PublishSubject.create(); new ThemeColorMaterialDialogBuilder(context) - .positiveText(R.string.ok) - .negativeText(R.string.cancel) + .positiveText(R.string.text_ok) + .negativeText(R.string.text_cancel) .onPositive((dialog, which) -> subject.onNext(true)) .onNegative((dialog, which) -> subject.onNext(false)) .content(text) diff --git a/app/src/main/java/org/autojs/autojs/ui/common/ScriptLoopDialog.java b/app/src/main/java/org/autojs/autojs/ui/common/ScriptLoopDialog.java index ecf1a3b0..44ec93cf 100644 --- a/app/src/main/java/org/autojs/autojs/ui/common/ScriptLoopDialog.java +++ b/app/src/main/java/org/autojs/autojs/ui/common/ScriptLoopDialog.java @@ -1,12 +1,11 @@ package org.autojs.autojs.ui.common; import android.content.Context; -import androidx.annotation.NonNull; import android.view.View; import android.view.Window; import android.widget.EditText; +import android.widget.Toast; -import com.afollestad.materialdialogs.DialogAction; import com.afollestad.materialdialogs.MaterialDialog; import com.stardust.app.DialogUtils; import com.stardust.app.GlobalAppContext; @@ -43,7 +42,7 @@ public class ScriptLoopDialog { mDialog = new MaterialDialog.Builder(context) .title(R.string.text_run_repeatedly) .customView(view, true) - .positiveText(R.string.ok) + .positiveText(R.string.text_ok) .onPositive((dialog, which) -> startScriptRunningLoop()) .build(); ButterKnife.bind(this, view); @@ -56,7 +55,7 @@ public class ScriptLoopDialog { float loopDelay = Float.parseFloat(mLoopDelay.getText().toString()); Scripts.INSTANCE.runRepeatedly(mScriptFile, loopTimes, (long) (1000L * loopDelay), (long) (loopInterval * 1000L)); } catch (NumberFormatException e) { - GlobalAppContext.toast(R.string.text_number_format_error); + GlobalAppContext.toast(R.string.text_number_format_error, Toast.LENGTH_LONG); } } diff --git a/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java b/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java index af98d86b..7e2aca25 100644 --- a/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java +++ b/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java @@ -209,7 +209,7 @@ public class ScriptOperations { .subscribe(path -> { ScriptFile newDir = new ScriptFile(getCurrentDirectory(), path); if (newDir.mkdirs()) { - showMessage(R.string.text_already_create); + showMessage(R.string.text_already_created); notifyFileCreated(mCurrentDirectory, new ScriptFile(newDir)); } else { showMessage(R.string.text_create_fail); @@ -293,8 +293,8 @@ public class ScriptOperations { public void delete(final ScriptFile scriptFile) { DialogUtils.showDialog(new ThemeColorMaterialDialogBuilder(mContext) .title(mContext.getString(R.string.text_are_you_sure_to_delete, scriptFile.getName())) - .negativeText(R.string.cancel) - .positiveText(R.string.ok) + .negativeText(R.string.text_cancel) + .positiveText(R.string.text_ok) .onPositive((dialog, which) -> deleteWithoutConfirm(scriptFile)) .build()); @@ -308,7 +308,7 @@ public class ScriptOperations { .observeOn(AndroidSchedulers.mainThread()) .subscribe(deleted -> { if (deleted) { - showMessage(R.string.text_already_delete); + showMessage(R.string.text_already_deleted); notifyFileRemoved(isDir, scriptFile); } else { showMessage(R.string.text_delete_failed); @@ -329,7 +329,7 @@ public class ScriptOperations { BuglyLog.i(LOG_TAG, "dir = " + Pref.getScriptDirPath() + ", sdcard = " + Environment.getExternalStorageDirectory() + ", url = " + url); String fileName = DownloadManager.parseFileNameLocally(url); return new FileChooserDialogBuilder(mContext) - .title(R.string.text_select_save_path) + .title(R.string.text_save_to) .dir(Pref.getScriptDirPath()) .chooseDir() .singleChoice() @@ -367,7 +367,7 @@ public class ScriptOperations { .justScriptFile() .singleChoice(file -> importFile(file.getPath()).subscribe()) .title(R.string.text_select_file_to_import) - .positiveText(R.string.ok) + .positiveText(R.string.text_ok) .show(); } diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/EditActivity.java b/app/src/main/java/org/autojs/autojs/ui/edit/EditActivity.java index b1f85f37..f366e786 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/EditActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/EditActivity.java @@ -1,21 +1,24 @@ package org.autojs.autojs.ui.edit; +import static org.autojs.autojs.ui.edit.EditorView.EXTRA_CONTENT; +import static org.autojs.autojs.ui.edit.EditorView.EXTRA_NAME; +import static org.autojs.autojs.ui.edit.EditorView.EXTRA_PATH; +import static org.autojs.autojs.ui.edit.EditorView.EXTRA_READ_ONLY; + import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.os.Build; import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - import android.util.Log; import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.stardust.app.OnActivityResultDelegate; import com.stardust.autojs.core.permission.OnRequestPermissionsResultCallback; import com.stardust.autojs.core.permission.PermissionRequestProxyActivity; @@ -23,15 +26,14 @@ import com.stardust.autojs.core.permission.RequestPermissionCallbacks; import com.stardust.autojs.execution.ScriptExecution; import com.stardust.pio.PFiles; -import org.autojs.autojs.R; -import org.autojs.autojs.storage.file.TmpScriptFiles; -import org.autojs.autojs.tool.Observers; -import org.autojs.autojs.ui.BaseActivity; -import org.autojs.autojs.theme.dialog.ThemeColorMaterialDialogBuilder; - import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EActivity; import org.androidannotations.annotations.ViewById; +import org.autojs.autojs.R; +import org.autojs.autojs.storage.file.TmpScriptFiles; +import org.autojs.autojs.theme.dialog.ThemeColorMaterialDialogBuilder; +import org.autojs.autojs.tool.Observers; +import org.autojs.autojs.ui.BaseActivity; import org.autojs.autojs.ui.main.MainActivity_; import java.io.File; @@ -41,25 +43,20 @@ import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; -import static org.autojs.autojs.ui.edit.EditorView.EXTRA_CONTENT; -import static org.autojs.autojs.ui.edit.EditorView.EXTRA_NAME; -import static org.autojs.autojs.ui.edit.EditorView.EXTRA_PATH; -import static org.autojs.autojs.ui.edit.EditorView.EXTRA_READ_ONLY; - /** * Created by Stardust on 2017/1/29. */ @EActivity(R.layout.activity_edit) public class EditActivity extends BaseActivity implements OnActivityResultDelegate.DelegateHost, PermissionRequestProxyActivity { - private OnActivityResultDelegate.Mediator mMediator = new OnActivityResultDelegate.Mediator(); + private final OnActivityResultDelegate.Mediator mMediator = new OnActivityResultDelegate.Mediator(); private static final String LOG_TAG = "EditActivity"; @ViewById(R.id.editor_view) EditorView mEditorView; private EditorMenu mEditorMenu; - private RequestPermissionCallbacks mRequestPermissionCallbacks = new RequestPermissionCallbacks(); + private final RequestPermissionCallbacks mRequestPermissionCallbacks = new RequestPermissionCallbacks(); private boolean mNewTask; public static void editFile(Context context, String path, boolean newTask) { @@ -98,6 +95,7 @@ public class EditActivity extends BaseActivity implements OnActivityResultDelega mNewTask = (getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0; } + @SuppressWarnings("ResultOfMethodCallIgnored") @SuppressLint("CheckResult") @AfterViews void setUpViews() { @@ -207,11 +205,7 @@ public class EditActivity extends BaseActivity implements OnActivityResultDelega } private void finishAndRemoveFromRecents() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - finishAndRemoveTask(); - } else { - super.finish(); - } + finishAndRemoveTask(); if (mNewTask) { startActivity(new Intent(this, MainActivity_.class)); } @@ -219,7 +213,7 @@ public class EditActivity extends BaseActivity implements OnActivityResultDelega private void showExitConfirmDialog() { new ThemeColorMaterialDialogBuilder(this) - .title(R.string.text_alert) + .title(R.string.text_prompt) .content(R.string.edit_exit_without_save_warn) .positiveText(R.string.text_cancel) .negativeText(R.string.text_save_and_exit) @@ -244,13 +238,14 @@ public class EditActivity extends BaseActivity implements OnActivityResultDelega return mMediator; } + @SuppressLint("MissingSuperCall") @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { mMediator.onActivityResult(requestCode, resultCode, data); } @Override - protected void onSaveInstanceState(Bundle outState) { + protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); if (!mEditorView.isTextChanged()) { return; @@ -267,6 +262,8 @@ public class EditActivity extends BaseActivity implements OnActivityResultDelega } } + @SuppressWarnings("ResultOfMethodCallIgnored") + @SuppressLint("CheckResult") private File saveToTmpFile(String text) { try { File tmp = TmpScriptFiles.create(this); @@ -280,6 +277,8 @@ public class EditActivity extends BaseActivity implements OnActivityResultDelega } } + @SuppressWarnings("ResultOfMethodCallIgnored") + @SuppressLint("CheckResult") @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java b/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java index 7870e78e..909dc6d1 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java @@ -10,6 +10,8 @@ import android.text.TextUtils; import android.view.MenuItem; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.afollestad.materialdialogs.MaterialDialog; import com.stardust.autojs.script.JavaScriptSource; import com.stardust.pio.PFiles; @@ -36,12 +38,13 @@ import io.reactivex.android.schedulers.AndroidSchedulers; * Created by Stardust on 2017/9/28. */ +@SuppressWarnings("ResultOfMethodCallIgnored") @SuppressLint("CheckResult") public class EditorMenu { - private EditorView mEditorView; - private Context mContext; - private CodeEditor mEditor; + private final EditorView mEditorView; + private final Context mContext; + private final CodeEditor mEditor; public EditorMenu(EditorView editorView) { mEditorView = editorView; @@ -50,96 +53,98 @@ public class EditorMenu { } public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_log: - showLog(); - return true; - case R.id.action_force_stop: - forceStop(); - return true; - default: - if (onEditOptionsSelected(item)) { - return true; - } - if (onJumpOptionsSelected(item)) { - return true; - } - if (onMoreOptionsSelected(item)) { - return true; - } - if (onDebugOptionsSelected(item)) { - return true; - } + int itemId = item.getItemId(); + if (itemId == R.id.action_log) { + showLog(); + return true; } - return false; + if (itemId == R.id.action_force_stop) { + forceStop(); + return true; + } + return onEditOptionsSelected(item) + || onJumpOptionsSelected(item) + || onMoreOptionsSelected(item) + || onDebugOptionsSelected(item); } private boolean onDebugOptionsSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_breakpoint: - mEditor.addOrRemoveBreakpointAtCurrentLine(); - return true; - case R.id.action_launch_debugger: - new NotAskAgainDialog.Builder(mEditorView.getContext(), "editor.debug.long_click_hint") - .title(R.string.text_alert) - .content(R.string.hint_long_click_run_to_debug) - .positiveText(R.string.ok) - .show(); - mEditorView.debug(); - return true; - case R.id.action_remove_all_breakpoints: - mEditor.removeAllBreakpoints(); - return true; + int itemId = item.getItemId(); + if (itemId == R.id.action_breakpoint) { + mEditor.addOrRemoveBreakpointAtCurrentLine(); + return true; + } + if (itemId == R.id.action_launch_debugger) { + new NotAskAgainDialog.Builder(mEditorView.getContext(), "editor.debug.long_click_hint") + .title(R.string.text_prompt) + .content(R.string.hint_long_click_run_to_debug) + .positiveText(R.string.text_ok) + .show(); + mEditorView.debug(); + return true; + } + if (itemId == R.id.action_remove_all_breakpoints) { + mEditor.removeAllBreakpoints(); + return true; } return false; } private boolean onJumpOptionsSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_jump_to_line: - jumpToLine(); - return true; - case R.id.action_jump_to_start: - mEditor.jumpToStart(); - return true; - case R.id.action_jump_to_end: - mEditor.jumpToEnd(); - return true; - case R.id.action_jump_to_line_start: - mEditor.jumpToLineStart(); - return true; - case R.id.action_jump_to_line_end: - mEditor.jumpToLineEnd(); - return true; + int itemId = item.getItemId(); + if (itemId == R.id.action_jump_to_line) { + jumpToLine(); + return true; + } + if (itemId == R.id.action_jump_to_start) { + mEditor.jumpToStart(); + return true; + } + if (itemId == R.id.action_jump_to_end) { + mEditor.jumpToEnd(); + return true; + } + if (itemId == R.id.action_jump_to_line_start) { + mEditor.jumpToLineStart(); + return true; + } + if (itemId == R.id.action_jump_to_line_end) { + mEditor.jumpToLineEnd(); + return true; } return false; } private boolean onMoreOptionsSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_console: - showConsole(); - return true; - case R.id.action_import_java_class: - importJavaPackageOrClass(); - return true; - case R.id.action_editor_text_size: - mEditorView.selectTextSize(); - return true; - case R.id.action_editor_theme: - mEditorView.selectEditorTheme(); - return true; - case R.id.action_open_by_other_apps: - openByOtherApps(); - return true; - case R.id.action_info: - showInfo(); - return true; - case R.id.action_build_apk: - startBuildApkActivity(); - return true; - + int itemId = item.getItemId(); + if (itemId == R.id.action_console) { + showConsole(); + return true; + } + if (itemId == R.id.action_import_java_class) { + importJavaPackageOrClass(); + return true; + } + if (itemId == R.id.action_editor_text_size) { + mEditorView.selectTextSize(); + return true; + } + if (itemId == R.id.action_editor_theme) { + mEditorView.selectEditorTheme(); + return true; + } + if (itemId == R.id.action_open_by_other_apps) { + openByOtherApps(); + return true; + } + if (itemId == R.id.action_info) { + showInfo(); + return true; + } + if (itemId == R.id.action_build_apk) { + startBuildApkActivity(); + return true; } return false; } @@ -151,7 +156,7 @@ public class EditorMenu { new ClassSearchDialogBuilder(mContext) .setQuery(s) .itemClick((dialog, item, pos) -> showClassSearchingItem(dialog, item)) - .title(R.string.text_search_java_class) + .title(R.string.text_find_java_classes) .show() ); } @@ -198,25 +203,30 @@ public class EditorMenu { private boolean onEditOptionsSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_find_or_replace: - findOrReplace(); - return true; - case R.id.action_copy_all: - copyAll(); - return true; - case R.id.action_copy_line: - copyLine(); - return true; - case R.id.action_delete_line: - deleteLine(); - return true; - case R.id.action_clear: - mEditor.setText(""); - return true; - case R.id.action_beautify: - beautifyCode(); - return true; + int itemId = item.getItemId(); + if (itemId == R.id.action_find_or_replace) { + findOrReplace(); + return true; + } + if (itemId == R.id.action_copy_all) { + copyAll(); + return true; + } + if (itemId == R.id.action_copy_line) { + copyLine(); + return true; + } + if (itemId == R.id.action_delete_line) { + deleteLine(); + return true; + } + if (itemId == R.id.action_clear) { + mEditor.setText(""); + return true; + } + if (itemId == R.id.action_beautify) { + beautifyCode(); + return true; } return false; } @@ -273,7 +283,15 @@ public class EditorMenu { } private void paste() { - mEditor.insert(ClipboardUtil.getClip(mContext).toString()); + CharSequence clip = getClip(); + if (clip != null) { + mEditor.insert(clip.toString()); + } + } + + @Nullable + private CharSequence getClip() { + return ClipboardUtil.getClip(mContext); } private void findOrReplace() { diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.java b/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.java index 6b4c9d78..c0e9033a 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.java @@ -1,5 +1,10 @@ package org.autojs.autojs.ui.edit; +import static org.autojs.autojs.model.script.Scripts.ACTION_ON_EXECUTION_FINISHED; +import static org.autojs.autojs.model.script.Scripts.EXTRA_EXCEPTION_COLUMN_NUMBER; +import static org.autojs.autojs.model.script.Scripts.EXTRA_EXCEPTION_LINE_NUMBER; +import static org.autojs.autojs.model.script.Scripts.EXTRA_EXCEPTION_MESSAGE; + import android.annotation.SuppressLint; import android.app.Activity; import android.content.BroadcastReceiver; @@ -10,28 +15,24 @@ import android.content.IntentFilter; import android.net.Uri; import android.os.Bundle; import android.os.Parcelable; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.util.SparseBooleanArray; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.Toast; import androidx.annotation.Nullable; - -import com.google.android.material.snackbar.Snackbar; - import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Log; -import android.util.SparseBooleanArray; -import android.view.Gravity; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.Toast; - import com.afollestad.materialdialogs.MaterialDialog; +import com.google.android.material.snackbar.Snackbar; import com.stardust.autojs.engine.JavaScriptEngine; import com.stardust.autojs.engine.ScriptEngine; import com.stardust.autojs.execution.ScriptExecution; @@ -80,11 +81,6 @@ import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; -import static org.autojs.autojs.model.script.Scripts.ACTION_ON_EXECUTION_FINISHED; -import static org.autojs.autojs.model.script.Scripts.EXTRA_EXCEPTION_COLUMN_NUMBER; -import static org.autojs.autojs.model.script.Scripts.EXTRA_EXCEPTION_LINE_NUMBER; -import static org.autojs.autojs.model.script.Scripts.EXTRA_EXCEPTION_MESSAGE; - /** * Created by Stardust on 2017/9/28. */ @@ -245,14 +241,10 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC @SuppressLint("CheckResult") private Observable loadUri(final Uri uri) { - mEditor.setProgress(true); return Observable.fromCallable(() -> PFiles.read(getContext().getContentResolver().openInputStream(uri))) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .doOnNext(s -> { - setInitialText(s); - mEditor.setProgress(false); - }); + .doOnNext(this::setInitialText); } private void setInitialText(String text) { @@ -525,6 +517,7 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC mEditor.beautifyCode(); } + @SuppressLint("CheckResult") public void selectEditorTheme() { mEditor.setProgress(true); Themes.getAllThemes(getContext()) diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/FindOrReplaceDialogBuilder.java b/app/src/main/java/org/autojs/autojs/ui/edit/FindOrReplaceDialogBuilder.java index e54b6b00..ea0befff 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/FindOrReplaceDialogBuilder.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/FindOrReplaceDialogBuilder.java @@ -61,8 +61,8 @@ public class FindOrReplaceDialogBuilder extends ThemeColorMaterialDialogBuilder View view = View.inflate(context, R.layout.dialog_find_or_replace, null); ButterKnife.bind(this, view); customView(view, true); - positiveText(R.string.ok); - negativeText(R.string.cancel); + positiveText(R.string.text_ok); + negativeText(R.string.text_cancel); title(R.string.text_find_or_replace); } diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/TextSizeSettingDialogBuilder.java b/app/src/main/java/org/autojs/autojs/ui/edit/TextSizeSettingDialogBuilder.java index 3ffff96a..84d5df34 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/TextSizeSettingDialogBuilder.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/TextSizeSettingDialogBuilder.java @@ -41,8 +41,8 @@ public class TextSizeSettingDialogBuilder extends ThemeColorMaterialDialogBuilde View view = View.inflate(context, R.layout.dialog_text_size_setting, null); customView(view, false); title(R.string.text_text_size); - positiveText(R.string.ok); - negativeText(R.string.cancel); + positiveText(R.string.text_ok); + negativeText(R.string.text_cancel); ButterKnife.bind(this, view); mSeekBar.setOnSeekBarChangeListener(this); } diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/debug/DebugBar.java b/app/src/main/java/org/autojs/autojs/ui/edit/debug/DebugBar.java index 63dd608c..e76682d9 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/debug/DebugBar.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/debug/DebugBar.java @@ -85,7 +85,7 @@ public class DebugBar extends FrameLayout { private void showNewWatchingVariableDialog() { new ThemeColorMaterialDialogBuilder(getContext()) - .title(R.string.text_new_watching_variable) + .title(R.string.text_new_watching_variables) .input(getResources().getString(R.string.text_variable_or_expr), "", (dialog, input) -> { if (TextUtils.isEmpty(input)) { return; @@ -119,7 +119,7 @@ public class DebugBar extends FrameLayout { new ThemeColorMaterialDialogBuilder(getContext()) .title(variable.getDisplayName()) .content(variable.getValue()) - .positiveText(R.string.ok) + .positiveText(R.string.text_ok) .negativeText(R.string.text_copy_value) .autoDismiss(true) .onNegative((dialog, which) -> ClipboardUtil.setClip(getContext(), variable.getValue())) diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/keyboard/FunctionsKeyboardHelper.java b/app/src/main/java/org/autojs/autojs/ui/edit/keyboard/FunctionsKeyboardHelper.java index fce0c9d6..6a3b5cba 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/keyboard/FunctionsKeyboardHelper.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/keyboard/FunctionsKeyboardHelper.java @@ -153,10 +153,8 @@ public class FunctionsKeyboardHelper implements BackPressedHandler { mActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r); int screenHeight = mActivity.getWindow().getDecorView().getRootView().getHeight(); int softInputHeight = screenHeight - r.bottom; - if (Build.VERSION.SDK_INT >= 20) { - // When SDK Level >= 20 (Android L), the softInputHeight will contain the height of softButtonsBar (if has) - softInputHeight = softInputHeight - getSoftKeyButtonsHeight(); - } + // When SDK Level >= 20 (Android L), the softInputHeight will contain the height of softButtonsBar (if has) + softInputHeight = softInputHeight - getSoftKeyButtonsHeight(); if (softInputHeight > 0) { mPreferences.edit().putInt(SHARE_PREFERENCE_SOFT_INPUT_HEIGHT, softInputHeight).apply(); } diff --git a/app/src/main/java/org/autojs/autojs/ui/error/AbstractIssueReporterActivity.java b/app/src/main/java/org/autojs/autojs/ui/error/AbstractIssueReporterActivity.java index e0e9adcd..797b4bae 100644 --- a/app/src/main/java/org/autojs/autojs/ui/error/AbstractIssueReporterActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/error/AbstractIssueReporterActivity.java @@ -479,40 +479,32 @@ public abstract class AbstractIssueReporterActivity extends BaseActivity { if (context == null) return; switch (result) { - case RESULT_OK: + case RESULT_OK -> { mReportFailed = false; tryToFinishActivity(); - break; - case RESULT_BAD_CREDENTIALS: - new MaterialDialog.Builder(context) - .title(R.string.air_dialog_title_failed) - .content(R.string.air_dialog_description_failed_wrong_credentials) - .positiveText(R.string.air_dialog_action_failed) - .show(); - break; - case RESULT_INVALID_TOKEN: - new MaterialDialog.Builder(context) - .title(R.string.air_dialog_title_failed) - .content(R.string.air_dialog_description_failed_invalid_token) - .positiveText(R.string.air_dialog_action_failed) - .show(); - break; - case RESULT_ISSUES_NOT_ENABLED: - new MaterialDialog.Builder(context) - .title(R.string.air_dialog_title_failed) - .content(R.string.air_dialog_description_failed_issues_not_available) - .positiveText(R.string.air_dialog_action_failed) - .show(); - break; - default: - new MaterialDialog.Builder(context) - .title(R.string.air_dialog_title_failed) - .content(R.string.air_dialog_description_failed_unknown) - .positiveText(R.string.air_dialog_action_failed) - .onPositive((dialog, which) -> tryToFinishActivity()) - .cancelListener(dialog -> tryToFinishActivity()) - .show(); - break; + } + case RESULT_BAD_CREDENTIALS -> new MaterialDialog.Builder(context) + .title(R.string.air_dialog_title_failed) + .content(R.string.air_dialog_description_failed_wrong_credentials) + .positiveText(R.string.air_dialog_action_failed) + .show(); + case RESULT_INVALID_TOKEN -> new MaterialDialog.Builder(context) + .title(R.string.air_dialog_title_failed) + .content(R.string.air_dialog_description_failed_invalid_token) + .positiveText(R.string.air_dialog_action_failed) + .show(); + case RESULT_ISSUES_NOT_ENABLED -> new MaterialDialog.Builder(context) + .title(R.string.air_dialog_title_failed) + .content(R.string.air_dialog_description_failed_issues_not_available) + .positiveText(R.string.air_dialog_action_failed) + .show(); + default -> new MaterialDialog.Builder(context) + .title(R.string.air_dialog_title_failed) + .content(R.string.air_dialog_description_failed_unknown) + .positiveText(R.string.air_dialog_action_failed) + .onPositive((dialog, which) -> tryToFinishActivity()) + .cancelListener(dialog -> tryToFinishActivity()) + .show(); } } diff --git a/app/src/main/java/org/autojs/autojs/ui/error/ErrorReportActivity.java b/app/src/main/java/org/autojs/autojs/ui/error/ErrorReportActivity.java index df4917d1..27171905 100644 --- a/app/src/main/java/org/autojs/autojs/ui/error/ErrorReportActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/error/ErrorReportActivity.java @@ -5,11 +5,9 @@ import android.content.ClipboardManager; import android.os.Build; import android.os.Bundle; import android.util.Log; -import android.util.SparseIntArray; import android.widget.Toast; import androidx.appcompat.widget.Toolbar; -import androidx.preference.PreferenceManager; import org.autojs.autojs.BuildConfig; import org.autojs.autojs.R; @@ -17,6 +15,7 @@ import org.autojs.autojs.theme.dialog.ThemeColorMaterialDialogBuilder; import org.autojs.autojs.ui.BaseActivity; import java.util.Locale; +import java.util.Objects; import java.util.Timer; import java.util.TimerTask; @@ -27,22 +26,13 @@ import java.util.TimerTask; public class ErrorReportActivity extends BaseActivity { private static final String TAG = "ErrorReportActivity"; - private static final SparseIntArray CRASH_COUNT = new SparseIntArray(); - private static final String KEY_CRASH_COUNT = "crashCount"; - - static { - CRASH_COUNT.put(2, R.string.text_again); - CRASH_COUNT.put(3, R.string.text_again_and_again); - CRASH_COUNT.put(4, R.string.text_again_and_again_again); - CRASH_COUNT.put(5, R.string.text_again_and_again_again_again); - } private String mTitle; protected void onCreate(Bundle savedInstanceState) { try { super.onCreate(savedInstanceState); - mTitle = getCrashCountText() + getString(R.string.text_crash); + mTitle = getString(R.string.text_app_crashed); setUpUI(); handleIntent(); } catch (Throwable throwable) { @@ -52,23 +42,10 @@ public class ErrorReportActivity extends BaseActivity { } - private String getCrashCountText() { - int i = PreferenceManager.getDefaultSharedPreferences(this).getInt(KEY_CRASH_COUNT, 0); - i++; - PreferenceManager.getDefaultSharedPreferences(this).edit().putInt(KEY_CRASH_COUNT, i).apply(); - if (i < 2) - return ""; - if (i > 5) - i = 5; - return getString(CRASH_COUNT.get(i)); - } - - private void handleIntent() { String message = getIntent().getStringExtra("message"); final String errorDetail = getIntent().getStringExtra("error"); showErrorMessageByDialog(message, errorDetail); - //showErrorMessage(message, errorDetail); } private void showErrorMessageByDialog(String message, final String errorDetail) { @@ -80,7 +57,7 @@ public class ErrorReportActivity extends BaseActivity { .onPositive((dialog, which) -> exit()) .onNegative((dialog, which) -> { copyToClip(getDeviceMessage() + message + "\n" + errorDetail); - exitAfter(1000); + exitAfter(); }) .cancelable(false) .show(); @@ -90,13 +67,13 @@ public class ErrorReportActivity extends BaseActivity { return String.format(Locale.getDefault(), "Version: %s\nAndroid: %d\n", BuildConfig.VERSION_CODE, Build.VERSION.SDK_INT); } - private void exitAfter(long millis) { + private void exitAfter() { new Timer().schedule(new TimerTask() { @Override public void run() { exit(); } - }, millis); + }, 1000); } private void copyToClip(String text) { @@ -112,10 +89,10 @@ public class ErrorReportActivity extends BaseActivity { private void setUpToolbar() { Toolbar toolbar; - toolbar = (Toolbar) findViewById(R.id.toolbar); + toolbar = findViewById(R.id.toolbar); toolbar.setTitle(getString(R.string.text_error_report)); setSupportActionBar(toolbar); - getSupportActionBar().setHomeButtonEnabled(false); + Objects.requireNonNull(getSupportActionBar()).setHomeButtonEnabled(false); } @Override diff --git a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java index e4155f85..89ffa45b 100644 --- a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java +++ b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java @@ -3,13 +3,17 @@ package org.autojs.autojs.ui.explorer; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.drawable.GradientDrawable; + import androidx.annotation.Nullable; + import com.google.android.material.snackbar.Snackbar; + import androidx.core.content.ContextCompat; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; + import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; @@ -317,6 +321,7 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR return getCurrentPage().toScriptFile(); } + @SuppressLint("CheckResult") @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { @@ -370,11 +375,20 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR sort(ExplorerItemList.SORT_TYPE_SIZE, mDirSortMenuShowing); break; case R.id.reset: - Explorers.Providers.workspace().resetSample(mSelectedItem.toScriptFile()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(ignored -> { - Snackbar.make(this, R.string.text_reset_succeed, Snackbar.LENGTH_SHORT).show(); - }, Observers.toastMessage()); + Observable o = Explorers.Providers.workspace() + .resetSample(mSelectedItem.toScriptFile()); + if (o == null) { + resetFailed(); + } else { + o.observeOn(AndroidSchedulers.mainThread()) + .subscribe(file -> { + if (file.exists()) { + resetSucceeded(); + } else { + resetFailed(); + } + }, Observers.toastMessage()); + } break; default: return false; @@ -382,6 +396,14 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR return true; } + private void resetSucceeded() { + Snackbar.make(this, R.string.text_reset_succeed, Snackbar.LENGTH_SHORT).show(); + } + + private void resetFailed() { + Snackbar.make(this, R.string.text_reset_to_initial_content_only_for_assets, Snackbar.LENGTH_LONG).show(); + } + protected void notifyOperated() { if (mOnItemOperatedListener != null) { mOnItemOperatedListener.OnItemOperated(mSelectedItem); diff --git a/app/src/main/java/org/autojs/autojs/ui/filechooser/FileChooserDialogBuilder.java b/app/src/main/java/org/autojs/autojs/ui/filechooser/FileChooserDialogBuilder.java index a7652ffd..a0a25a5a 100644 --- a/app/src/main/java/org/autojs/autojs/ui/filechooser/FileChooserDialogBuilder.java +++ b/app/src/main/java/org/autojs/autojs/ui/filechooser/FileChooserDialogBuilder.java @@ -47,8 +47,8 @@ public class FileChooserDialogBuilder extends ThemeColorMaterialDialogBuilder { super(context); mFileChooseListView = new FileChooseListView(context); customView(mFileChooseListView, false); - positiveText(R.string.ok); - negativeText(R.string.cancel); + positiveText(R.string.text_ok); + negativeText(R.string.text_cancel); onPositive((dialog, which) -> notifySelected()); } diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java index f2aca0fe..4a3cb178 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java @@ -7,10 +7,13 @@ import android.view.ContextThemeWrapper; import android.view.View; import android.widget.Toast; +import androidx.annotation.NonNull; + import com.afollestad.materialdialogs.MaterialDialog; import com.makeramen.roundedimageview.RoundedImageView; import com.stardust.app.DialogUtils; import com.stardust.app.OperationDialogBuilder; +import com.stardust.autojs.core.accessibility.AccessibilityServiceTool; import com.stardust.autojs.core.record.Recorder; import com.stardust.enhancedfloaty.FloatyService; import com.stardust.enhancedfloaty.FloatyWindow; @@ -22,7 +25,6 @@ import org.autojs.autojs.autojs.record.GlobalActionRecorder; import org.autojs.autojs.model.explorer.ExplorerDirPage; import org.autojs.autojs.model.explorer.Explorers; import org.autojs.autojs.model.script.Scripts; -import org.autojs.autojs.tool.AccessibilityServiceTool; import org.autojs.autojs.tool.RootTool; import org.autojs.autojs.ui.common.NotAskAgainDialog; import org.autojs.autojs.ui.floating.layoutinspector.LayoutBoundsFloatyWindow; @@ -41,6 +43,8 @@ import org.greenrobot.eventbus.EventBus; import org.jdeferred.Deferred; import org.jdeferred.impl.DeferredObject; +import java.text.MessageFormat; + import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Optional; @@ -52,9 +56,9 @@ import butterknife.Optional; public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInspector.CaptureAvailableListener { - public static class StateChangeEvent { - private int currentState; - private int previousState; + public static final class StateChangeEvent { + private final int currentState; + private final int previousState; public StateChangeEvent(int currentState, int previousState) { this.currentState = currentState; @@ -74,13 +78,11 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp public static final int STATE_NORMAL = 0; public static final int STATE_RECORDING = 1; - private static final int IC_ACTION_VIEW = R.drawable.ic_android_eat_js; - CircularMenuWindow mWindow; private int mState; private RoundedImageView mActionViewIcon; - private Context mContext; - private GlobalActionRecorder mRecorder; + private final Context mContext; + private final GlobalActionRecorder mRecorder; private MaterialDialog mSettingsDialog; private MaterialDialog mLayoutInspectDialog; private String mRunningPackage, mRunningActivity; @@ -141,7 +143,7 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp final MaterialDialog dialog = new ThemeColorMaterialDialogBuilder(mContext) .title(R.string.text_run_script) .customView(explorerView, false) - .positiveText(R.string.cancel) + .positiveText(R.string.text_cancel) .build(); explorerView.setOnItemOperatedListener(file -> dialog.dismiss()); explorerView.setOnItemClickListener((view, item) -> Scripts.INSTANCE.run(item.toScriptFile())); @@ -157,9 +159,7 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp DialogUtils.showDialog(new NotAskAgainDialog.Builder(mContext, "CircularMenu.root") .title(R.string.text_no_root_access) .content(R.string.no_root_access_for_record) - .negativeText(R.string.text_quit) - .positiveText(R.string.text_insist_on_record) - .onPositive(((dialog, which) -> mRecorder.start())) + .positiveText(R.string.text_quit) .build()); } else { mRecorder.start(); @@ -169,14 +169,15 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp private void setState(int state) { int previousState = mState; mState = state; - mActionViewIcon.setImageResource(mState == STATE_RECORDING ? R.drawable.ic_ali_record : - IC_ACTION_VIEW); - // mActionViewIcon.setBackgroundColor(mState == STATE_RECORDING ? mContext.getResources().getColor(R.color.color_red) : - // Color.WHITE); - mActionViewIcon.setBackgroundResource(mState == STATE_RECORDING ? R.drawable.circle_red : - R.drawable.circle_white); - int padding = (int) mContext.getResources().getDimension(mState == STATE_RECORDING ? - R.dimen.padding_circular_menu_recording : R.dimen.padding_circular_menu_normal); + mActionViewIcon.setImageResource(mState == STATE_RECORDING + ? R.drawable.ic_ali_record + : R.drawable.ic_android_eat_js); + mActionViewIcon.setBackgroundResource(mState == STATE_RECORDING + ? R.drawable.circle_red + : R.drawable.circle_white); + int padding = (int) mContext.getResources().getDimension(mState == STATE_RECORDING + ? R.dimen.padding_circular_menu_recording + : R.dimen.padding_circular_menu_normal); mActionViewIcon.setPadding(padding, padding, padding, padding); EventBus.getDefault().post(new StateChangeEvent(mState, previousState)); @@ -206,7 +207,6 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp inspectLayout(LayoutBoundsFloatyWindow::new); } - @Optional @OnClick(R.id.layout_hierarchy) void showLayoutHierarchy() { @@ -220,7 +220,7 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp } if (AccessibilityService.Companion.getInstance() == null) { Toast.makeText(mContext, R.string.text_no_accessibility_permission_to_capture, Toast.LENGTH_SHORT).show(); - AccessibilityServiceTool.goToAccessibilitySetting(); + getAccessibilityServiceTool().goToAccessibilitySetting(); return; } MaterialDialog progress = DialogUtils.showDialog(new ThemeColorMaterialDialogBuilder(mContext) @@ -240,6 +240,9 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp }, err -> mActionViewIcon.post(progress::dismiss)); } + private AccessibilityServiceTool getAccessibilityServiceTool() { + return new AccessibilityServiceTool(mContext); + } @Optional @OnClick(R.id.stop_all_scripts) @@ -248,14 +251,12 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp AutoJs.getInstance().getScriptEngineService().stopAllAndToast(); } - @Override public void onCaptureAvailable(NodeInfo capture) { if (mCaptureDeferred != null && mCaptureDeferred.isPending()) mCaptureDeferred.resolve(capture); } - @Optional @OnClick(R.id.settings) void settings() { @@ -263,13 +264,11 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp mRunningPackage = AutoJs.getInstance().getInfoProvider().getLatestPackageByUsageStatsIfGranted(); mRunningActivity = AutoJs.getInstance().getInfoProvider().getLatestActivity(); mSettingsDialog = new OperationDialogBuilder(mContext) - .item(R.id.accessibility_service, R.drawable.ic_service_green, R.string.text_accessibility_settings) - .item(R.id.package_name, R.drawable.ic_ali_app, - mContext.getString(R.string.text_current_package) + mRunningPackage) - .item(R.id.class_name, R.drawable.ic_ali_android, - mContext.getString(R.string.text_current_activity) + mRunningActivity) + .item(R.id.accessibility_service, R.drawable.ic_accessibility_black_48dp, R.string.text_enable_a11y_service) + .item(R.id.package_name, R.drawable.ic_ali_app, mContext.getString(R.string.text_latest_package) + ":\n" + getRunningPackage()) + .item(R.id.class_name, R.drawable.ic_ali_android, mContext.getString(R.string.text_latest_activity) + ":\n" + getRunningActivity()) .item(R.id.open_launcher, R.drawable.ic_android_eat_js, R.string.text_open_main_activity) - .item(R.id.pointer_location, R.drawable.ic_zoom_out_map_white_24dp, R.string.text_pointer_location) + .item(R.id.pointer_location, R.drawable.ic_control_point_black_48dp, R.string.text_pointer_location) .item(R.id.exit, R.drawable.ic_close_white_48dp, R.string.text_exit_floating_window) .bindItemClick(this) .title(R.string.text_more) @@ -277,40 +276,65 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp DialogUtils.showDialog(mSettingsDialog); } + private String getRunningPackage() { + if (!TextUtils.isEmpty(mRunningPackage)) { + return mRunningPackage; + } + return getEmptyInfoHint(); + } + + private String getRunningActivity() { + if (!TextUtils.isEmpty(mRunningActivity)) { + return mRunningActivity; + } + return getEmptyInfoHint(); + } + + private String getEmptyInfoHint() { + return MessageFormat.format("{0} ({1})", + mContext.getString(R.string.text_null).toLowerCase(), + mContext.getString(R.string.text_a11y_service_may_be_needed).toLowerCase()); + } @Optional @OnClick(R.id.accessibility_service) void enableAccessibilityService() { dismissSettingsDialog(); - AccessibilityServiceTool.enableAccessibilityService(); + getAccessibilityServiceTool().enableAccessibilityService(); } - private void dismissSettingsDialog() { - if (mSettingsDialog == null) - return; - mSettingsDialog.dismiss(); - mSettingsDialog = null; + if (mSettingsDialog != null) { + mSettingsDialog.dismiss(); + mSettingsDialog = null; + } } @Optional @OnClick(R.id.package_name) void copyPackageName() { dismissSettingsDialog(); - if (TextUtils.isEmpty(mRunningPackage)) - return; - ClipboardUtil.setClip(mContext, mRunningPackage); - Toast.makeText(mContext, R.string.text_already_copied_to_clip, Toast.LENGTH_SHORT).show(); + if (!TextUtils.isEmpty(mRunningPackage)) { + ClipboardUtil.setClip(mContext, mRunningPackage); + Toast.makeText(mContext, getTextAlreadyCopied(R.string.text_latest_package), Toast.LENGTH_SHORT).show(); + } } @Optional @OnClick(R.id.class_name) void copyActivityName() { dismissSettingsDialog(); - if (TextUtils.isEmpty(mRunningActivity)) - return; - ClipboardUtil.setClip(mContext, mRunningActivity); - Toast.makeText(mContext, R.string.text_already_copied_to_clip, Toast.LENGTH_SHORT).show(); + if (!TextUtils.isEmpty(mRunningActivity)) { + ClipboardUtil.setClip(mContext, mRunningActivity); + Toast.makeText(mContext, getTextAlreadyCopied(R.string.text_latest_activity), Toast.LENGTH_SHORT).show(); + } + } + + @NonNull + private String getTextAlreadyCopied(int actionResId) { + return MessageFormat.format("{0} ({1})", + mContext.getString(R.string.text_already_copied_to_clip), + mContext.getString(actionResId).toLowerCase()); } @Optional @@ -344,7 +368,6 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp AutoJs.getInstance().getLayoutInspector().removeCaptureAvailableListener(this); } - @Override public void onStart() { setState(STATE_RECORDING); @@ -363,4 +386,5 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp public void onResume() { } + } diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/FloatyWindowManger.java b/app/src/main/java/org/autojs/autojs/ui/floating/FloatyWindowManger.java index ee4c0af7..20828865 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/FloatyWindowManger.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/FloatyWindowManger.java @@ -10,20 +10,11 @@ import com.stardust.app.GlobalAppContext; import com.stardust.autojs.util.FloatingPermission; import com.stardust.enhancedfloaty.FloatyService; import com.stardust.enhancedfloaty.FloatyWindow; -import com.stardust.enhancedfloaty.util.FloatingWindowPermissionUtil; -import org.autojs.autojs.App; import org.autojs.autojs.R; -import org.autojs.autojs.ui.floating.CircularMenu; - -import com.stardust.util.IntentUtil; import java.lang.ref.WeakReference; -import ezy.assist.compat.SettingsCompat; - -import static com.stardust.autojs.util.FloatingPermission.manageDrawOverlays; - /** * Created by Stardust on 2017/9/30. */ @@ -41,9 +32,9 @@ public class FloatyWindowManger { // SecurityException: https://github.com/hyb1996-guest/AutoJsIssueReport/issues/4781 } catch (Exception e) { e.printStackTrace(); - if(hasPermission){ - manageDrawOverlays(context); - GlobalAppContext.toast(R.string.text_no_floating_window_permission); + if (hasPermission) { + FloatingPermission.manageDrawOverlays(context); + GlobalAppContext.toast(R.string.text_no_floating_window_permission, Toast.LENGTH_LONG); } } return false; @@ -54,25 +45,30 @@ public class FloatyWindowManger { } public static void showCircularMenuIfNeeded() { - if (isCircularMenuShowing()) { - return; + if (!isCircularMenuShowing() || !canDrawOverlays()) { + showCircularMenu(); } - showCircularMenu(); } public static boolean showCircularMenu() { - if (!FloatingPermission.canDrawOverlays(GlobalAppContext.get())) { - Toast.makeText(GlobalAppContext.get(), R.string.text_no_floating_window_permission, Toast.LENGTH_SHORT).show(); - manageDrawOverlays(GlobalAppContext.get()); - return false; - } else { - GlobalAppContext.get().startService(new Intent(GlobalAppContext.get(), FloatyService.class)); - CircularMenu menu = new CircularMenu(GlobalAppContext.get()); + Context context = GlobalAppContext.get(); + + if (canDrawOverlays()) { + context.startService(new Intent(context, FloatyService.class)); + CircularMenu menu = new CircularMenu(context); sCircularMenu = new WeakReference<>(menu); return true; + } else { + Toast.makeText(context, R.string.text_no_floating_window_permission, Toast.LENGTH_SHORT).show(); + FloatingPermission.manageDrawOverlays(context); + return false; } } + public static boolean canDrawOverlays() { + return FloatingPermission.canDrawOverlays(GlobalAppContext.get()); + } + public static void hideCircularMenu() { if (sCircularMenu == null) return; @@ -82,6 +78,7 @@ public class FloatyWindowManger { sCircularMenu = null; } + @SuppressWarnings("deprecation") public static int getWindowType() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { return WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/gesture/BounceDragGesture.java b/app/src/main/java/org/autojs/autojs/ui/floating/gesture/BounceDragGesture.java index e67c31d8..1ce08f09 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/gesture/BounceDragGesture.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/gesture/BounceDragGesture.java @@ -16,11 +16,12 @@ public class BounceDragGesture extends DragGesture { private long mBounceDuration = 300; private static final int MIN_DY_TO_SCREEN_BOTTOM = 100; private static final int MIN_DY_TO_SCREEN_TOP = 0; - private BounceInterpolator mBounceInterpolator; + private final BounceInterpolator mBounceInterpolator; public BounceDragGesture(WindowBridge windowBridge, View view) { super(windowBridge, view); setAutoKeepToEdge(true); + setAlphaUnpressed(); mBounceInterpolator = new BounceInterpolator(); } @@ -47,12 +48,7 @@ public class BounceDragGesture extends DragGesture { protected void bounce(final int fromX, final int toX, final int y) { ValueAnimator animator = ValueAnimator.ofFloat(fromX, toX); - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mWindowBridge.updatePosition((int) ((float) animation.getAnimatedValue()), y); - } - }); + animator.addUpdateListener(animation -> mWindowBridge.updatePosition((int) ((float) animation.getAnimatedValue()), y)); animator.setDuration(mBounceDuration); animator.setInterpolator(mBounceInterpolator); animator.start(); diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/gesture/DragGesture.java b/app/src/main/java/org/autojs/autojs/ui/floating/gesture/DragGesture.java index f128ff74..6e6ba0d2 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/gesture/DragGesture.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/gesture/DragGesture.java @@ -33,6 +33,18 @@ public class DragGesture extends GestureDetector.SimpleOnGestureListener { mView = view; setupView(); } + + public void setAlpha(float alpha) { + mView.setAlpha(alpha); + } + + public void setAlphaPressed() { + setAlpha(mPressedAlpha); + } + + public void setAlphaUnpressed() { + setAlpha(mUnpressedAlpha); + } private void setupView() { final GestureDetectorCompat gestureDetector = new GestureDetectorCompat(mView.getContext(), this); @@ -41,7 +53,7 @@ public class DragGesture extends GestureDetector.SimpleOnGestureListener { public boolean onTouch(View v, MotionEvent event) { gestureDetector.onTouchEvent(event); if (event.getAction() == MotionEvent.ACTION_UP) { - mView.setAlpha(mUnpressedAlpha); + setAlphaUnpressed(); if (!onTheEdge() && mAutoKeepToEdge) { keepToEdge(); } @@ -113,7 +125,7 @@ public class DragGesture extends GestureDetector.SimpleOnGestureListener { } mWindowBridge.updatePosition(mInitialX + (int) ((e2.getRawX() - mInitialTouchX)), mInitialY + (int) ((e2.getRawY() - mInitialTouchY))); - mView.setAlpha(mPressedAlpha); + setAlphaPressed(); Log.d("DragGesture", "onScroll"); return false; } diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutBoundsFloatyWindow.java b/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutBoundsFloatyWindow.java index ac767c35..c63dffa1 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutBoundsFloatyWindow.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutBoundsFloatyWindow.java @@ -10,15 +10,13 @@ import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.Theme; import com.stardust.app.DialogUtils; import com.stardust.enhancedfloaty.FloatyService; +import com.stardust.view.accessibility.LayoutInspector; +import com.stardust.view.accessibility.NodeInfo; import org.autojs.autojs.R; import org.autojs.autojs.ui.codegeneration.CodeGenerateDialog; import org.autojs.autojs.ui.floating.FloatyWindowManger; import org.autojs.autojs.ui.floating.FullScreenFloatyWindow; - -import com.stardust.view.accessibility.LayoutInspector; -import com.stardust.view.accessibility.NodeInfo; - import org.autojs.autojs.ui.widget.BubblePopupMenu; import java.util.Arrays; @@ -74,11 +72,17 @@ public class LayoutBoundsFloatyWindow extends FullScreenFloatyWindow { protected void onViewCreated(View v) { mLayoutBoundsView.setOnNodeInfoSelectListener(info -> { + mLayoutBoundsView.setFocusable(false); mSelectedNode = info; ensureOperationPopMenu(); - if (mBubblePopMenu.getContentView().getMeasuredWidth() <= 0) + if (mBubblePopMenu.getContentView().getMeasuredWidth() <= 0) { mBubblePopMenu.preMeasure(); - mBubblePopMenu.showAsDropDownAtLocation(mLayoutBoundsView, info.getBoundsInScreen().height(), info.getBoundsInScreen().centerX() - mBubblePopMenu.getContentView().getMeasuredWidth() / 2, info.getBoundsInScreen().bottom - mLayoutBoundsView.getStatusBarHeight()); + } + mBubblePopMenu.showAsDropDownAtLocation(mLayoutBoundsView, + info.getBoundsInScreen().height(), + info.getBoundsInScreen().centerX() - mBubblePopMenu.getContentView().getMeasuredWidth() / 2, + info.getBoundsInScreen().bottom - mLayoutBoundsView.getStatusBarHeight()); + mLayoutBoundsView.setFocusable(true); }); mLayoutBoundsView.getBoundsPaint().setStrokeWidth(2f); mLayoutBoundsView.setRootNode(mRootNode); @@ -88,9 +92,13 @@ public class LayoutBoundsFloatyWindow extends FullScreenFloatyWindow { private void showNodeInfo() { + getNodeInfoDialog().show(); + } + + public MaterialDialog getNodeInfoDialog() { ensureDialog(); mNodeInfoView.setNodeInfo(mSelectedNode); - mNodeInfoDialog.show(); + return mNodeInfoDialog; } private void ensureOperationPopMenu() { diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutBoundsView.java b/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutBoundsView.java index 3d3e247e..c6360595 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutBoundsView.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutBoundsView.java @@ -18,6 +18,7 @@ import com.stardust.util.ViewUtil; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; /** @@ -98,7 +99,7 @@ public class LayoutBoundsView extends View { } canvas.clipRect(mTouchedNodeBounds, Region.Op.DIFFERENCE); } - canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mFillingPaint); + canvas.drawRect(0, 0, getWidth(), getHeight(), mFillingPaint); if (mTouchedNode != null) { canvas.restore(); } @@ -166,9 +167,7 @@ public class LayoutBoundsView extends View { if (list.isEmpty()) { return null; } - return Collections.min(list, (o1, o2) -> - o1.getBoundsInScreen().width() * o1.getBoundsInScreen().height() - - o2.getBoundsInScreen().width() * o2.getBoundsInScreen().height()); + return Collections.min(list, Comparator.comparingInt(o -> o.getBoundsInScreen().width() * o.getBoundsInScreen().height())); } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/FloatingActionMenu.java b/app/src/main/java/org/autojs/autojs/ui/main/FloatingActionMenu.java index 81526eec..fd6824f9 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/FloatingActionMenu.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/FloatingActionMenu.java @@ -3,11 +3,15 @@ package org.autojs.autojs.ui.main; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Context; + import androidx.annotation.AttrRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; + import com.google.android.material.floatingactionbutton.FloatingActionButton; + import androidx.interpolator.view.animation.FastOutSlowInInterpolator; + import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -34,13 +38,16 @@ public class FloatingActionMenu extends FrameLayout implements View.OnClickListe R.drawable.ic_floating_action_menu_file, R.drawable.ic_floating_action_menu_open, R.drawable.ic_project}; - private static final int[] LABELS = {R.string.text_directory, R.string.text_file, R.string.text_import, R.string.text_project}; - private TextView[] mLabels; + private static final int[] LABELS = { + R.string.text_directory, + R.string.text_file, + R.string.text_import, + R.string.text_project}; private FloatingActionButton[] mFabs; private View[] mFabContainers; private boolean mExpanded = false; - private int mInterval = 30; - private int mDuration = 250; + private final int mInterval = 30; + private final int mDuration = 250; private final Interpolator mInterpolator = new FastOutSlowInInterpolator(); private final PublishSubject mState = PublishSubject.create(); private OnFloatingActionButtonClickListener mOnFloatingActionButtonClickListener; @@ -113,11 +120,13 @@ public class FloatingActionMenu extends FrameLayout implements View.OnClickListe mState.onNext(false); } + @SuppressWarnings("SameParameterValue") private void buildFabs(int[] icons, int[] labels) { - if (icons.length != labels.length) + if (icons.length != labels.length) { throw new IllegalArgumentException("icons.length = " + icons.length + " is not equal to labels.length = " + labels.length); + } mFabs = new FloatingActionButton[icons.length]; - mLabels = new TextView[icons.length]; + TextView[] mLabels = new TextView[icons.length]; mFabContainers = new View[icons.length]; LayoutInflater inflater = LayoutInflater.from(getContext()); for (int i = 0; i < icons.length; i++) { diff --git a/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.java b/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.java index 008b3294..d096d748 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.java @@ -49,6 +49,7 @@ import org.autojs.autojs.ui.BaseActivity; import org.autojs.autojs.ui.doc.DocsFragment_; import org.autojs.autojs.ui.floating.FloatyWindowManger; import org.autojs.autojs.ui.log.LogActivity_; +import org.autojs.autojs.ui.main.drawer.DrawerFragment; import org.autojs.autojs.ui.main.scripts.MyScriptListFragment_; import org.autojs.autojs.ui.main.task.TaskManagerFragment_; import org.autojs.autojs.ui.settings.SettingsActivity_; @@ -131,8 +132,13 @@ public class MainActivity extends BaseActivity implements OnActivityResultDelega Toolbar toolbar = $(R.id.toolbar); setSupportActionBar(toolbar); toolbar.setTitle(R.string.app_name); - ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar, R.string.text_drawer_open, - R.string.text_drawer_close); + ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar, R.string.text_drawer_open, R.string.text_drawer_close) { + @Override + public void onDrawerOpened(View drawerView) { + super.onDrawerOpened(drawerView); + EventBus.getDefault().post(DrawerFragment.class); + } + }; drawerToggle.syncState(); mDrawerLayout.addDrawerListener(drawerToggle); } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/community/CommunityWebView.java b/app/src/main/java/org/autojs/autojs/ui/main/community/CommunityWebView.java deleted file mode 100644 index 70d9a30b..00000000 --- a/app/src/main/java/org/autojs/autojs/ui/main/community/CommunityWebView.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.autojs.autojs.ui.main.community; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.net.Uri; - -import com.google.android.material.bottomsheet.BottomSheetDialog; -import com.google.android.material.snackbar.BaseTransientBottomBar; -import com.google.android.material.snackbar.Snackbar; -import android.util.AttributeSet; -import android.webkit.ValueCallback; -import android.webkit.WebView; -import android.widget.Toast; - -import org.autojs.autojs.Pref; -import org.autojs.autojs.R; -import org.autojs.autojs.network.NodeBB; -import org.autojs.autojs.model.script.Scripts; -import org.autojs.autojs.network.download.DownloadManager; -import org.autojs.autojs.ui.common.OptionListView; -import org.autojs.autojs.ui.common.ScriptOperations; -import org.autojs.autojs.ui.filechooser.FileChooserDialogBuilder; -import org.autojs.autojs.ui.widget.EWebView; - -import java.util.regex.Pattern; - -import butterknife.OnClick; -import butterknife.Optional; -import io.reactivex.android.schedulers.AndroidSchedulers; - -/** - * Created by Stardust on 2017/10/19. - */ - -public class CommunityWebView extends EWebView { - - private String mUrl; - private BottomSheetDialog mBottomSheetDialog; - - public CommunityWebView(Context context) { - super(context); - init(); - } - - public CommunityWebView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - private void init() { - getWebView().setWebViewClient(new MyWebViewClient()); - getWebView().setWebChromeClient(new MyWebChromeClient()); - } - - private void shouldScriptOptionsDialog(String url) { - mUrl = url; - String fileName = DownloadManager.parseFileNameLocally(url); - mBottomSheetDialog = new BottomSheetDialog(getContext()); - mBottomSheetDialog.setContentView(new OptionListView.Builder(getContext()) - .title(fileName) - .item(R.id.save, R.drawable.ic_file_download_black_48dp, R.string.text_download) - .item(R.id.run, R.drawable.ic_play_arrow_white_48dp, R.string.text_run) - .bindItemClick(this) - .build()); - mBottomSheetDialog.show(); - } - - @SuppressLint("CheckResult") - @Optional - @OnClick(R.id.save) - void save() { - dismissBottomSheetDialog(); - new ScriptOperations(getContext(), CommunityWebView.this) - .download(mUrl) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(file -> - Snackbar.make(CommunityWebView.this, getResources().getString(R.string.format_file_downloaded, file.getPath()) - , Snackbar.LENGTH_LONG) - .setAction(R.string.text_open, v -> Scripts.INSTANCE.edit(getContext(), file)) - .show(), - error -> { - error.printStackTrace(); - Snackbar.make(CommunityWebView.this, R.string.text_download_failed, Snackbar.LENGTH_SHORT).show(); - }); - } - - @SuppressLint("CheckResult") - @Optional - @OnClick(R.id.run) - void run() { - dismissBottomSheetDialog(); - new ScriptOperations(getContext(), CommunityWebView.this) - .temporarilyDownload(mUrl) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(file -> { - Snackbar.make(CommunityWebView.this, R.string.text_start_running, Snackbar.LENGTH_SHORT).show(); - Scripts.INSTANCE.run(file); - }, error -> { - error.printStackTrace(); - Snackbar.make(CommunityWebView.this, R.string.text_download_failed, BaseTransientBottomBar.LENGTH_SHORT).show(); - }); - } - - private void dismissBottomSheetDialog() { - mBottomSheetDialog.dismiss(); - mBottomSheetDialog = null; - } - - - private class MyWebViewClient extends EWebView.MyWebViewClient { - - private final Pattern UPLOAD_FILE_PATTERN = Pattern.compile(NodeBB.url("assets/uploads/files/.+(\\.js|\\.auto)")); - - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - if (UPLOAD_FILE_PATTERN.matcher(url).matches()) { - shouldScriptOptionsDialog(url); - return true; - } - return super.shouldOverrideUrlLoading(view, url); - } - - @Override - public void onPageFinished(WebView view, String url) { - evalJavaScript("$('#header').hide();$('#content').css({ top: '0', position: 'absolute' });"); - } - } - - private class MyWebChromeClient extends EWebView.MyWebChromeClient { - - @Override - public boolean openFileChooser(ValueCallback callback, String[] acceptType) { - if (super.openFileChooser(callback, acceptType)) { - return true; - } - new FileChooserDialogBuilder(getContext()) - .title(R.string.text_select_file_to_upload) - .dir(Pref.getScriptDirPath()) - .singleChoice(file -> callback.onReceiveValue(Uri.fromFile(file))) - .cancelListener(dialog -> callback.onReceiveValue(null)) - .show(); - return true; - } - } -} diff --git a/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java b/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java index 11fd157c..d912e269 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java @@ -1,12 +1,9 @@ package org.autojs.autojs.ui.main.drawer; -import static android.content.Context.POWER_SERVICE; - import android.annotation.SuppressLint; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; -import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.os.PowerManager; @@ -22,13 +19,13 @@ import com.afollestad.materialdialogs.MaterialDialog; import com.google.android.material.snackbar.Snackbar; import com.stardust.app.AppOpsKt; import com.stardust.app.GlobalAppContext; +import com.stardust.autojs.core.accessibility.AccessibilityServiceTool; import com.stardust.autojs.core.util.ProcessShell; import com.stardust.autojs.util.FloatingPermission; import com.stardust.notification.NotificationListenerService; import com.stardust.theme.ThemeColorManager; import com.stardust.util.ClipboardUtil; import com.stardust.util.IntentUtil; -import com.stardust.view.accessibility.AccessibilityService; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EFragment; @@ -39,9 +36,9 @@ import org.autojs.autojs.external.foreground.ForegroundService; import org.autojs.autojs.pluginclient.DevPluginService; import org.autojs.autojs.pluginclient.JsonSocketClient; import org.autojs.autojs.pluginclient.JsonSocketServer; -import org.autojs.autojs.tool.AccessibilityServiceTool; import org.autojs.autojs.tool.Observers; import org.autojs.autojs.tool.RootTool; +import org.autojs.autojs.tool.SettingsTool; import org.autojs.autojs.tool.WifiTool; import org.autojs.autojs.ui.BaseActivity; import org.autojs.autojs.ui.common.NotAskAgainDialog; @@ -79,7 +76,7 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { @ViewById(R.id.drawer_menu) RecyclerView mDrawerMenu; - private final DrawerMenuItem mAccessibilityServiceItem = new DrawerMenuItem(R.drawable.ic_accessibility_black_48dp, R.string.text_accessibility_service, 0, this::enableOrDisableAccessibilityService); + private final DrawerMenuItem mAccessibilityServiceItem = new DrawerMenuItem(R.drawable.ic_accessibility_black_48dp, R.string.text_a11y_service, 0, this::enableOrDisableAccessibilityService); private final DrawerMenuItem mForegroundServiceItem = new DrawerMenuItem(R.drawable.ic_service_green, R.string.text_foreground_service, R.string.key_foreground_service, this::toggleForegroundService); private final DrawerMenuItem mFloatingWindowItem = new DrawerMenuItem(R.drawable.ic_robot_64, R.string.text_floating_window, 0, this::showOrDismissFloatingWindow); @@ -106,11 +103,11 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { mClientConnectionStateDisposable = JsonSocketClient.cxnState .observeOn(AndroidSchedulers.mainThread()) - .subscribe(state -> setItemState(mClientModeItem, state)); + .subscribe(state -> setCxnItemState(mClientModeItem, state)); mServerConnectionStateDisposable = JsonSocketServer.cxnState .observeOn(AndroidSchedulers.mainThread()) - .subscribe(state -> setItemState(mServerModeItem, state)); + .subscribe(state -> setCxnItemState(mServerModeItem, state)); EventBus.getDefault().register(this); } @@ -132,7 +129,11 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { @AfterViews public void setUpViews() { ThemeColorManager.addViewBackground(mHeaderView); + initMenuItems(); + + getAccessibilityServiceTool().enableAccessibilityServiceAutomaticallyIfNeeded(); + if (Pref.isFloatingMenuShown()) { FloatyWindowManger.showCircularMenuIfNeeded(); setChecked(mFloatingWindowItem, true); @@ -140,12 +141,12 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { JsonSocketClient jsonSocketClient = devPlugin.getJsonSocketClient(); if (jsonSocketClient != null) { - setChecked(mClientModeItem, jsonSocketClient.isConnected()); + syncClientModeState(); } if (Pref.isForegroundServiceEnabled()) { ForegroundService.start(GlobalAppContext.get()); - setChecked(mForegroundServiceItem, true); + syncForegroundServiceState(); } } @@ -179,7 +180,8 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { } public void enableOrDisableAccessibilityService(DrawerMenuItemViewHolder holder) { - boolean isAccessibilityServiceEnabled = isAccessibilityServiceEnabled(); + AccessibilityServiceTool ast = getAccessibilityServiceTool(); + boolean isAccessibilityServiceEnabled = ast.isAccessibilityServiceEnabled(); boolean checked = holder.getSwitchCompat().isChecked(); if (checked && !isAccessibilityServiceEnabled) { enableAccessibilityService(); @@ -188,6 +190,72 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { } } + @SuppressLint("CheckResult") + private void enableAccessibilityService() { + setProgress(mAccessibilityServiceItem, true); + + AccessibilityServiceTool ast = getAccessibilityServiceTool(); + Observable.fromCallable(ast::enableAccessibilityService) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((succeed) -> { + if (!succeed) { + ast.goToAccessibilitySetting(); + } + setProgress(mAccessibilityServiceItem, false); + syncSwitchState(); + }); + } + + @SuppressLint("CheckResult") + private void disableAccessibilityService() { + setProgress(mAccessibilityServiceItem, true); + + AccessibilityServiceTool ast = getAccessibilityServiceTool(); + Observable.fromCallable(ast::disableAccessibilityService) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((succeed) -> { + if (!succeed) { + toast(R.string.text_disable_a11y_service_failed); + ast.goToAccessibilitySetting(); + } + setProgress(mAccessibilityServiceItem, false); + syncSwitchState(); + }); + } + + private void enableAccessibilityServiceIfNeeded() { + AccessibilityServiceTool ast = getAccessibilityServiceTool(); + if (!ast.isAccessibilityServiceEnabled()) { + enableAccessibilityService(); + } + } + + private void toggleForegroundService(DrawerMenuItemViewHolder holder) { + Context context = requireContext(); + Context globalAppContext = GlobalAppContext.get(); + boolean checked = holder.getSwitchCompat().isChecked(); + if (checked) { + if (getForegroundServiceDialog(context) == null) { + ForegroundService.start(globalAppContext); + } + } else { + ForegroundService.stop(globalAppContext); + } + } + + private MaterialDialog getForegroundServiceDialog(Context context) { + return new NotAskAgainDialog.Builder(context, "DrawerFragment.foreground_service") + .title(R.string.text_foreground_service) + .content(R.string.description_foreground_service) + .positiveText(R.string.text_ok) + .onPositive((dialog, which) -> ForegroundService.start(GlobalAppContext.get())) + .canceledOnTouchOutside(false) + .cancelable(false) + .show(); + } + public void goToNotificationServiceSettings(DrawerMenuItemViewHolder holder) { boolean enabled = NotificationListenerService.Companion.getInstance() != null; boolean checked = holder.getSwitchCompat().isChecked(); @@ -197,31 +265,35 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { } public void goToUsageStatsSettings(DrawerMenuItemViewHolder holder) { - Context context = getContext(); - boolean enabled = false; - if (context != null) { - enabled = AppOpsKt.isUsageStatsPermissionGranted(context); - } + Context context = requireContext(); + boolean enabled = AppOpsKt.isUsageStatsPermissionGranted(context); boolean checked = holder.getSwitchCompat().isChecked(); if (checked && !enabled) { if (getUsageStatsDialog(context) == null) { - syncSwitchState(); + requestAppUsagePermission(context); } } else if (!checked && enabled) { - IntentUtil.requestAppUsagePermission(context); + requestAppUsagePermission(context); } } + private void requestAppUsagePermission(Context context) { + IntentUtil.requestAppUsagePermission(context); + } + private MaterialDialog getUsageStatsDialog(Context context) { return new NotAskAgainDialog.Builder(context, "DrawerFragment.usage_stats") .title(R.string.text_usage_stats_permission) .content(R.string.description_usage_stats_permission) - .positiveText(R.string.ok) - .dismissListener(dialog -> { - if (context != null) { - IntentUtil.requestAppUsagePermission(context); - } + .negativeText(R.string.text_quit) + .positiveText(R.string.text_ok) + .onNegative((dialog, which) -> { + dialog.dismiss(); + syncUsageStatsPermissionState(context); }) + .onPositive((dialog, which) -> requestAppUsagePermission(context)) + .canceledOnTouchOutside(false) + .cancelable(false) .show(); } @@ -232,8 +304,10 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { Pref.setFloatingMenuShown(checked); } if (checked && !isFloatingWindowShowing) { - setChecked(mFloatingWindowItem, FloatyWindowManger.showCircularMenu()); - enableAccessibilityServiceByRootIfNeeded(); + if (FloatyWindowManger.showCircularMenu()) { + setChecked(mFloatingWindowItem, true); + enableAccessibilityServiceIfNeeded(); + } } else if (!checked && isFloatingWindowShowing) { FloatyWindowManger.hideCircularMenu(); } @@ -241,29 +315,27 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { @SuppressLint("BatteryLife") public void toggleIgnoreBatteryOptimizations(DrawerMenuItemViewHolder holder) { - Context context = getContext(); + Context context = requireContext(); try { Intent intent = new Intent(); - boolean isIgnoring = false; - if (context != null) { - isIgnoring = ((PowerManager) context.getSystemService(POWER_SERVICE)) - .isIgnoringBatteryOptimizations(context.getPackageName()); - } + boolean isIgnoring = isIgnoringBatteryOptimizations(context); if (isIgnoring) { intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS); } else { - if (context != null) { - intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) - .setData(Uri.parse("package:" + context.getPackageName())); - } + intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) + .setData(Uri.parse("package:" + context.getPackageName())); } startActivity(intent); } catch (ActivityNotFoundException e) { e.printStackTrace(); - Toast.makeText(context, R.string.text_failed, Toast.LENGTH_LONG).show(); + toast(R.string.text_failed); } } + private boolean isIgnoringBatteryOptimizations(Context context) { + return ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).isIgnoringBatteryOptimizations(context.getPackageName()); + } + public void openThemeColorSettings(DrawerMenuItemViewHolder holder) { SettingsActivity.selectThemeColor(getActivity()); } @@ -299,13 +371,7 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { } private boolean hasWriteSecureSettingsAccess() { - Context context = getContext(); - if (context != null) { - @SuppressLint("WrongConstant") - int checkVal = context.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS_PERMISSION); - return checkVal == PackageManager.PERMISSION_GRANTED; - } - return false; + return SettingsTool.SecureSettings.isGranted(getContext()); } @SuppressLint("CheckResult") @@ -344,15 +410,15 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { try { ProcessShell.execCommand(cmd, true); if (state == hasWriteSecureSettingsAccess()) { - int successRes = state ? R.string.text_permission_granted_by_root : R.string.text_permission_revoked_by_root; - Toast.makeText(context, successRes, Toast.LENGTH_SHORT).show(); + int successRes = state ? R.string.text_permission_granted_with_root : R.string.text_permission_revoked_with_root; + toast(successRes); return; } } catch (Exception ignore) { // nothing to do here } - int successRes = state ? R.string.text_permission_granted_failed_by_root : R.string.text_permission_revoked_failed_by_root; - Toast.makeText(context, successRes, Toast.LENGTH_LONG).show(); + int successRes = state ? R.string.text_permission_granted_failed_with_root : R.string.text_permission_revoked_failed_with_root; + toast(successRes); } private void setWriteSecureSettingsAccessByAdb(boolean state) { @@ -374,7 +440,7 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { if (view != null) { Snackbar.make(view, resultRes, SNACK_BAR_DURATION).show(); } else { - Toast.makeText(context, resultRes, Toast.LENGTH_SHORT).show(); + toast(context, resultRes); } }) .negativeText(R.string.text_back) @@ -387,28 +453,16 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { if (view != null) { Snackbar.make(view, textRes, SNACK_BAR_DURATION).show(); } else { - Toast.makeText(context, textRes, Toast.LENGTH_SHORT).show(); + toast(context, textRes); } }) .cancelable(false) .autoDismiss(false) - .dismissListener(dialog -> setChecked(mWriteSecuritySettingsItem, hasWriteSecureSettingsAccess())) + .dismissListener(dialog -> setCheckedIfNeeded(mWriteSecuritySettingsItem, hasWriteSecureSettingsAccess())) .show(); } - @SuppressLint("CheckResult") - private void enableAccessibilityServiceByRootIfNeeded() { - Observable.fromCallable(() -> Pref.shouldEnableAccessibilityServiceByRoot() && !isAccessibilityServiceEnabled()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(needed -> { - if (needed && RootTool.isRootAvailable()) { - enableAccessibilityServiceByRoot(); - } - }); - - } - private void toggleRemoteServerCxn(DrawerMenuItemViewHolder holder) { boolean isChecked = holder.getSwitchCompat().isChecked(); boolean isDisconnected = !isJsonSocketClientConnected(); @@ -465,15 +519,6 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { } } - private void toggleForegroundService(DrawerMenuItemViewHolder holder) { - boolean checked = holder.getSwitchCompat().isChecked(); - if (checked) { - ForegroundService.start(GlobalAppContext.get()); - } else { - ForegroundService.stop(GlobalAppContext.get()); - } - } - @SuppressLint("CheckResult") private void inputRemoteHost() { Context activity = getActivity(); @@ -495,95 +540,111 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { } private String getInputHint() { - Context context = getContext(); - if (context != null) { - return context.getString(R.string.text_pc_server_address); - } - return "Input a server address"; + Context context = requireContext(); + return context.getString(R.string.text_pc_server_address); } private void onPCServerConnectException(Throwable e) { setChecked(mClientModeItem, false); - Toast.makeText(getContext(), - getString(R.string.error_connect_to_remote, e.getMessage()), - Toast.LENGTH_LONG).show(); + toast(getString(R.string.error_connect_to_remote, e.getMessage())); } private void onAJServerConnectException(Throwable e) { setChecked(mServerModeItem, false); - Toast.makeText(getContext(), - getString(R.string.error_enable_server, e.getMessage()), - Toast.LENGTH_LONG).show(); + toast(getString(R.string.error_enable_server, e.getMessage())); } - private void syncSwitchState() { - Context context = getContext(); + public void syncSwitchState() { + Context context = requireContext(); - if (context != null) { - setChecked(mUsageStatsPermissionItem, AppOpsKt.isUsageStatsPermissionGranted(context)); - } + syncAccessibilityServiceState(); + syncForegroundServiceState(); - if (mFloatingWindowItem.isChecked() && !FloatingPermission.canDrawOverlays(context)) { - setChecked(mFloatingWindowItem, false); - } + syncFloatingWindowState(context); - if (context != null) { - setChecked(mIgnoreBatteryOptimizationsItem, ((PowerManager) context.getSystemService(POWER_SERVICE)) - .isIgnoringBatteryOptimizations(context.getPackageName())); - } + syncClientModeState(); + syncServerModeState(); - setChecked(mAccessibilityServiceItem, AccessibilityServiceTool.isAccessibilityServiceEnabled(getActivity())); - setChecked(mNotificationPermissionItem, NotificationListenerService.Companion.getInstance() != null); - setChecked(mDisplayOverOtherAppsItem, FloatingPermission.canDrawOverlays(context)); - setChecked(mWriteSystemSettingsItem, Settings.System.canWrite(getContext())); - setChecked(mWriteSecuritySettingsItem, hasWriteSecureSettingsAccess()); - setChecked(mClientModeItem, isJsonSocketClientConnected()); - setChecked(mServerModeItem, isServerSocketConnected()); + syncNotificationPermissionState(); + syncUsageStatsPermissionState(context); + syncIgnoreBatteryOptimizationsState(context); + syncDisplayOverOtherAppsState(context); + syncWriteSystemSettingsState(); + syncWriteSecuritySettingsState(); } - private boolean isAccessibilityServiceEnabled() { - return AccessibilityServiceTool.isAccessibilityServiceEnabled(getActivity()); + private void syncForegroundServiceState() { + setCheckedIfNeeded(mForegroundServiceItem, ForegroundService.isRunning(GlobalAppContext.get())); } - private void enableAccessibilityService() { - if (Pref.shouldEnableAccessibilityServiceByRoot() && RootTool.isRootAvailable()) { - enableAccessibilityServiceByRoot(); - } else { - AccessibilityServiceTool.goToAccessibilitySetting(); - } + private void syncWriteSecuritySettingsState() { + setCheckedIfNeeded(mWriteSecuritySettingsItem, hasWriteSecureSettingsAccess()); } - private void disableAccessibilityService() { - if (!AccessibilityService.Companion.disable()) { - AccessibilityServiceTool.goToAccessibilitySetting(); - } + private void syncWriteSystemSettingsState() { + setCheckedIfNeeded(mWriteSystemSettingsItem, Settings.System.canWrite(getContext())); } - @SuppressLint("CheckResult") - private void enableAccessibilityServiceByRoot() { - setProgress(mAccessibilityServiceItem, true); - Observable.fromCallable(() -> AccessibilityServiceTool.enableAccessibilityServiceByRootAndWaitFor(4000)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(succeed -> { - if (!succeed) { - Toast.makeText(getContext(), R.string.text_enable_accessibility_service_by_root_failed, Toast.LENGTH_SHORT).show(); - AccessibilityServiceTool.goToAccessibilitySetting(); - } - setProgress(mAccessibilityServiceItem, false); - }); + private void syncDisplayOverOtherAppsState(Context context) { + setCheckedIfNeeded(mDisplayOverOtherAppsItem, FloatingPermission.canDrawOverlays(context)); + } + + private void syncIgnoreBatteryOptimizationsState(Context context) { + setCheckedIfNeeded(mIgnoreBatteryOptimizationsItem, isIgnoringBatteryOptimizations(context)); + } + + private void syncUsageStatsPermissionState(Context context) { + setCheckedIfNeeded(mUsageStatsPermissionItem, AppOpsKt.isUsageStatsPermissionGranted(context)); + } + + private void syncNotificationPermissionState() { + setCheckedIfNeeded(mNotificationPermissionItem, NotificationListenerService.Companion.getInstance() != null); + } + + private void syncServerModeState() { + setCheckedIfNeeded(mServerModeItem, isServerSocketConnected()); + } + + private void syncClientModeState() { + setCheckedIfNeeded(mClientModeItem, isJsonSocketClientConnected()); + } + + private void syncFloatingWindowState(Context context) { + setCheckedIfNeeded(mFloatingWindowItem, FloatyWindowManger.isCircularMenuShowing() && FloatingPermission.canDrawOverlays(context)); + } + + private void syncAccessibilityServiceState() { + setCheckedIfNeeded(mAccessibilityServiceItem, getAccessibilityServiceTool().isAccessibilityServiceEnabled()); } - @SuppressWarnings("unused") @Subscribe public void onCircularMenuStateChange(CircularMenu.StateChangeEvent event) { - setChecked(mFloatingWindowItem, event.getCurrentState() != CircularMenu.STATE_CLOSED); + setCheckedIfNeeded(mFloatingWindowItem, event.getCurrentState() != CircularMenu.STATE_CLOSED); + } + + @Subscribe + public void onDrawerOpened(Class drawerFragmentClass) { + syncSwitchState(); } private void showMessage(CharSequence text) { - if (getContext() == null) - return; - Toast.makeText(getContext(), text, Toast.LENGTH_SHORT).show(); + toast(text); + } + + private void toast(CharSequence text) { + toast(getContext(), text); + } + + private void toast(int resId) { + toast(getContext(), resId); + } + + private void toast(Context context, CharSequence text) { + Toast.makeText(context, text, Toast.LENGTH_SHORT).show(); + } + + private void toast(Context context, int resId) { + Toast.makeText(context, resId, Toast.LENGTH_SHORT).show(); } private void setProgress(DrawerMenuItem item, boolean progress) { @@ -591,16 +652,27 @@ public class DrawerFragment extends androidx.fragment.app.Fragment { mDrawerMenuAdapter.notifyItemChanged(item); } + private void setCheckedIfNeeded(DrawerMenuItem item, boolean b) { + if (item.isChecked() != b) { + setChecked(item, b); + } + } + private void setChecked(DrawerMenuItem item, boolean checked) { item.setChecked(checked); mDrawerMenuAdapter.notifyItemChanged(item); } - private void setItemState(DrawerMenuItem item, DevPluginService.State state) { - setChecked(item, state.getState() == DevPluginService.State.CONNECTED); + private void setCxnItemState(DrawerMenuItem item, DevPluginService.State state) { + setCheckedIfNeeded(item, state.getState() == DevPluginService.State.CONNECTED); setProgress(item, state.getState() == DevPluginService.State.CONNECTING); if (state.getException() != null) { showMessage(state.getException().getMessage()); } } + + private AccessibilityServiceTool getAccessibilityServiceTool() { + return new AccessibilityServiceTool(requireContext()); + } + } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerMenuItem.java b/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerMenuItem.java index da378e48..5e75bf67 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerMenuItem.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerMenuItem.java @@ -7,7 +7,6 @@ import java.io.IOException; */ public class DrawerMenuItem { - public interface Action { void onClick(DrawerMenuItemViewHolder holder) throws IOException; } @@ -102,4 +101,5 @@ public class DrawerMenuItem { public int hashCode() { return mTitle; } + } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskManagerFragment.java b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskManagerFragment.java index 425a8d1a..e73d0eae 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskManagerFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskManagerFragment.java @@ -2,18 +2,20 @@ package org.autojs.autojs.ui.main.task; import android.app.Activity; import android.os.Bundle; -import com.google.android.material.floatingactionbutton.FloatingActionButton; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import android.view.View; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.google.android.material.floatingactionbutton.FloatingActionButton; + +import org.androidannotations.annotations.AfterViews; +import org.androidannotations.annotations.EFragment; +import org.androidannotations.annotations.ViewById; import org.autojs.autojs.R; import org.autojs.autojs.autojs.AutoJs; import org.autojs.autojs.ui.main.ViewPagerFragment; import org.autojs.autojs.ui.widget.SimpleAdapterDataObserver; -import org.androidannotations.annotations.AfterViews; -import org.androidannotations.annotations.EFragment; -import org.androidannotations.annotations.ViewById; +import java.util.Objects; /** * Created by Stardust on 2017/3/24. @@ -24,13 +26,9 @@ public class TaskManagerFragment extends ViewPagerFragment { @ViewById(R.id.task_list) TaskListRecyclerView mTaskListRecyclerView; - @ViewById(R.id.notice_no_running_script) - View mNoRunningScriptNotice; - @ViewById(R.id.swipe_refresh_layout) SwipeRefreshLayout mSwipeRefreshLayout; - public TaskManagerFragment() { super(45); setArguments(new Bundle()); @@ -39,23 +37,14 @@ public class TaskManagerFragment extends ViewPagerFragment { @AfterViews void setUpViews() { init(); - final boolean noRunningScript = mTaskListRecyclerView.getAdapter().getItemCount() == 0; - mNoRunningScriptNotice.setVisibility(noRunningScript ? View.VISIBLE : View.GONE); } private void init() { - mTaskListRecyclerView.getAdapter().registerAdapterDataObserver(new SimpleAdapterDataObserver() { - + Objects.requireNonNull(mTaskListRecyclerView.getAdapter()).registerAdapterDataObserver(new SimpleAdapterDataObserver() { @Override public void onSomethingChanged() { - final boolean noRunningScript = mTaskListRecyclerView.getAdapter().getItemCount() == 0; - mTaskListRecyclerView.postDelayed(() -> { - if (mNoRunningScriptNotice == null) - return; - mNoRunningScriptNotice.setVisibility(noRunningScript ? View.VISIBLE : View.GONE); - }, 150); + // To do something here maybe some day. } - }); mSwipeRefreshLayout.setOnRefreshListener(() -> { mTaskListRecyclerView.refresh(); diff --git a/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java b/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java index 002a6ebe..4f846198 100644 --- a/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java @@ -5,8 +5,6 @@ import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Environment; -import androidx.annotation.Nullable; -import androidx.cardview.widget.CardView; import android.text.Editable; import android.text.TextUtils; import android.util.Log; @@ -15,6 +13,9 @@ import android.widget.EditText; import android.widget.ImageView; import android.widget.Toast; +import androidx.annotation.Nullable; +import androidx.cardview.widget.CardView; + import com.afollestad.materialdialogs.MaterialDialog; import com.google.android.material.textfield.TextInputLayout; import com.stardust.autojs.project.ProjectConfig; @@ -39,7 +40,7 @@ import org.autojs.autojs.ui.shortcut.ShortcutIconSelectActivity_; import java.io.File; import java.io.InputStream; -import java.util.Locale; +import java.util.Objects; import java.util.concurrent.Callable; import java.util.regex.Pattern; @@ -116,8 +117,8 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa private void showPluginDownloadDialog(int msgRes) { new ThemeColorMaterialDialogBuilder(this) .content(msgRes) - .positiveText(R.string.ok) - .negativeText(R.string.cancel) + .positiveText(R.string.text_download) + .negativeText(R.string.text_cancel) .onPositive((dialog, which) -> downloadPlugin()) .onNegative((dialog, which) -> finish()) .show(); @@ -125,8 +126,7 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa } private void downloadPlugin() { - IntentUtil.browse(this, "https://github.com/" + - "SuperMonster002/Hello-Sockpuppet/raw/master/" + + IntentUtil.browse(this, "https://cdn.jsdelivr.net/gh/SuperMonster002/Hello-Sockpuppet@master/" + "%5B" + "auto.js" + "%5D" + "%5B" + "apk_builder_plugin_4.1.1_alpha2" + "%5D" + "%5B" + "arm-v7a" + "%5D" + @@ -206,20 +206,18 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa } private boolean checkInputs() { - boolean inputValid = true; - inputValid &= checkNotEmpty(mSourcePath); - inputValid &= checkNotEmpty(mOutputPath); - inputValid &= checkNotEmpty(mAppName); - inputValid &= checkNotEmpty(mSourcePath); - inputValid &= checkNotEmpty(mVersionCode); - inputValid &= checkNotEmpty(mVersionName); - inputValid &= checkPackageNameValid(mPackageName); - return inputValid; + return checkNotEmpty(mSourcePath) + & checkNotEmpty(mOutputPath) + & checkNotEmpty(mAppName) + & checkNotEmpty(mSourcePath) + & checkNotEmpty(mVersionCode) + & checkNotEmpty(mVersionName) + & checkPackageNameValid(mPackageName); } private boolean checkPackageNameValid(EditText editText) { Editable text = editText.getText(); - String hint = ((TextInputLayout) editText.getParent().getParent()).getHint().toString(); + String hint = Objects.requireNonNull(((TextInputLayout) editText.getParent().getParent()).getHint()).toString(); if (TextUtils.isEmpty(text)) { editText.setError(hint + getString(R.string.text_should_not_be_empty)); return false; @@ -236,7 +234,7 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa if (!TextUtils.isEmpty(editText.getText()) || !editText.isShown()) return true; // TODO: 2017/12/8 more beautiful ways? - String hint = ((TextInputLayout) editText.getParent().getParent()).getHint().toString(); + String hint = Objects.requireNonNull(((TextInputLayout) editText.getParent().getParent()).getHint()).toString(); editText.setError(hint + getString(R.string.text_should_not_be_empty)); return false; } @@ -289,7 +287,7 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa private void showProgressDialog() { mProgressDialog = new MaterialDialog.Builder(this) .progress(true, 100) - .content(R.string.text_on_progress) + .content(R.string.text_in_progress) .cancelable(false) .show(); } @@ -299,7 +297,7 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa mProgressDialog.dismiss(); mProgressDialog = null; } - Toast.makeText(this, getString(R.string.text_build_failed) + error.getMessage(), Toast.LENGTH_SHORT).show(); + Toast.makeText(this, getString(R.string.text_build_failed) + "\n" + error.getMessage(), Toast.LENGTH_SHORT).show(); Log.e(LOG_TAG, "Build failed", error); } @@ -310,7 +308,7 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa .title(R.string.text_build_successfully) .content(getString(R.string.format_build_successfully, outApk.getPath())) .positiveText(R.string.text_install) - .negativeText(R.string.cancel) + .negativeText(R.string.text_cancel) .onPositive((dialog, which) -> IntentUtil.installApkOrToast(BuildActivity.this, outApk.getPath(), AppFileProvider.AUTHORITY) ) diff --git a/app/src/main/java/org/autojs/autojs/ui/project/ProjectConfigActivity.java b/app/src/main/java/org/autojs/autojs/ui/project/ProjectConfigActivity.java index 704113ae..c3188708 100644 --- a/app/src/main/java/org/autojs/autojs/ui/project/ProjectConfigActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/project/ProjectConfigActivity.java @@ -103,7 +103,7 @@ public class ProjectConfigActivity extends BaseActivity { if (mProjectConfig == null) { new ThemeColorMaterialDialogBuilder(this) .title(R.string.text_invalid_project) - .positiveText(R.string.ok) + .positiveText(R.string.text_ok) .dismissListener(dialogInterface -> finish()) .show(); } diff --git a/app/src/main/java/org/autojs/autojs/ui/settings/ScriptDirPathPreference.java b/app/src/main/java/org/autojs/autojs/ui/settings/ScriptDirPathPreference.java index eb56979c..c07cf09a 100644 --- a/app/src/main/java/org/autojs/autojs/ui/settings/ScriptDirPathPreference.java +++ b/app/src/main/java/org/autojs/autojs/ui/settings/ScriptDirPathPreference.java @@ -1,7 +1,6 @@ package org.autojs.autojs.ui.settings; import android.content.Context; -import androidx.annotation.NonNull; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; @@ -10,6 +9,8 @@ import android.widget.EditText; import android.widget.RadioGroup; import android.widget.Toast; +import androidx.annotation.NonNull; + import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.prefs.MaterialEditTextPreference; @@ -83,7 +84,7 @@ public class ScriptDirPathPreference extends MaterialEditTextPreference { MaterialDialog dialog = new ThemeColorMaterialDialogBuilder(getContext()) .progress(true, 0) .progressIndeterminateStyle(true) - .title(R.string.text_on_progress) + .title(R.string.text_in_progress) .cancelable(false) .content("") .show(); diff --git a/app/src/main/java/org/autojs/autojs/ui/settings/SettingsActivity.java b/app/src/main/java/org/autojs/autojs/ui/settings/SettingsActivity.java index fab7d230..fd0bb6b2 100644 --- a/app/src/main/java/org/autojs/autojs/ui/settings/SettingsActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/settings/SettingsActivity.java @@ -7,10 +7,14 @@ import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceScreen; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; import androidx.core.util.Pair; +import com.afollestad.materialdialogs.MaterialDialog; +import com.stardust.app.GlobalAppContext; import com.stardust.theme.app.ColorSelectActivity; import com.stardust.theme.preference.ThemeColorPreferenceFragment; import com.stardust.theme.util.ListBuilder; @@ -18,14 +22,20 @@ import com.stardust.util.MapBuilder; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EActivity; +import org.autojs.autojs.Pref; import org.autojs.autojs.R; import org.autojs.autojs.ui.BaseActivity; +import org.autojs.autojs.ui.common.NotAskAgainDialog; import org.autojs.autojs.ui.error.IssueReporterActivity; +import org.autojs.autojs.ui.update.UpdateCheckDialog; import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; -import java.util.Objects; +import java.util.Set; import de.psdev.licensesdialog.LicenseResolver; import de.psdev.licensesdialog.LicensesDialog; @@ -69,6 +79,62 @@ public class SettingsActivity extends BaseActivity { ColorSelectActivity.startColorSelect(context, context.getString(R.string.mt_color_picker_title), colorItems); } + @NonNull + private static LinkedHashMap getAvailableLanguages(@NonNull Context context) { + LinkedHashMap map = new LinkedHashMap<>(); + map.put(context.getString(R.string.text_app_language_follow_system), + ((BaseActivity) context)::setLocaleFollowSystem); + map.put(context.getString(R.string.text_app_language_simplified_chinese), + () -> ((BaseActivity) context).updateLocale(Locale.SIMPLIFIED_CHINESE)); + map.put(context.getString(R.string.text_app_language_english), + () -> ((BaseActivity) context).updateLocale(Locale.ENGLISH)); + return map; + } + + public static void selectAppLanguage(Context context) { + LinkedHashMap languagesMap = getAvailableLanguages(context); + Set languagesKey = languagesMap.keySet(); + Collection languagesRunnable = languagesMap.values(); + + new MaterialDialog.Builder(context) + .title(R.string.text_app_language) + .items(languagesKey) + .itemsCallbackSingleChoice(Pref.getAppLanguageIndex(), (dialog, itemView, position, text) -> true) + .positiveText(R.string.text_ok) + .onPositive((dialog, which) -> { + int index = dialog.getSelectedIndex(); + Runnable run = (Runnable) languagesRunnable.toArray()[index]; + if (run != null) { + Pref.setAppLanguageIndex(index); + GlobalAppContext.post(run); + } + dialog.dismiss(); + }) + .negativeText(R.string.text_cancel) + .onNegative((dialog, which) -> dialog.dismiss()) + .neutralText(R.string.text_dialog_button_go_to_settings) + .onNeutral((dialog, which) -> { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClassName("com.android.settings", "com.android.settings.LanguageSettings"); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + }) + .autoDismiss(false) + .show(); + + showImperfectHint(context); + } + + private static void showImperfectHint(Context context) { + new NotAskAgainDialog.Builder(context, "SettingsActivity.select_app_language_imperfect_hint") + .title(R.string.text_notice) + .content(R.string.text_imperfect_hint_for_app_language) + .positiveText(R.string.text_ok) + .onPositive((dialog, which) -> dialog.dismiss()) + .autoDismiss(false) + .show(); + } + @AfterViews void setUpUI() { setUpToolbar(); @@ -79,10 +145,16 @@ public class SettingsActivity extends BaseActivity { Toolbar toolbar = $(R.id.toolbar); toolbar.setTitle(R.string.text_setting); setSupportActionBar(toolbar); - Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); + setDisplayHomeAsUpEnabledIfNeeded(); toolbar.setNavigationOnClickListener(v -> finish()); } + private void setDisplayHomeAsUpEnabledIfNeeded() { + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } + } public static class PreferenceFragment extends ThemeColorPreferenceFragment { private Map ACTION_MAP; @@ -98,9 +170,11 @@ public class SettingsActivity extends BaseActivity { super.onStart(); ACTION_MAP = new MapBuilder() .put(getString(R.string.text_theme_color), () -> selectThemeColor(getActivity())) + .put(getString(R.string.text_check_for_updates), () -> new UpdateCheckDialog(getActivity()).show()) .put(getString(R.string.text_issue_report), () -> startActivity(new Intent(getActivity(), IssueReporterActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))) - .put(getString(R.string.text_about_me_and_repo), () -> startActivity(new Intent(getActivity(), AboutActivity_.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))) + .put(getString(R.string.text_about_app_and_developer), () -> startActivity(new Intent(getActivity(), AboutActivity_.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))) .put(getString(R.string.text_licenses), this::showLicenseDialog) + .put(getString(R.string.text_app_language), () -> selectAppLanguage(getActivity())) .build(); } @@ -109,9 +183,8 @@ public class SettingsActivity extends BaseActivity { if (action != null) { action.run(); return true; - } else { - return super.onPreferenceTreeClick(preferenceScreen, preference); } + return super.onPreferenceTreeClick(preferenceScreen, preference); } private void showLicenseDialog() { @@ -154,4 +227,5 @@ public class SettingsActivity extends BaseActivity { } } + } diff --git a/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutCreateActivity.java b/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutCreateActivity.java index f979bdb3..47b69070 100644 --- a/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutCreateActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutCreateActivity.java @@ -73,7 +73,7 @@ public class ShortcutCreateActivity extends AppCompatActivity { new ThemeColorMaterialDialogBuilder(this) .customView(view, false) .title(R.string.text_send_shortcut) - .positiveText(R.string.ok) + .positiveText(R.string.text_ok) .onPositive((dialog, which) -> { createShortcut(); finish(); diff --git a/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java b/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java index 2e5e01e6..3f57a90d 100644 --- a/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/timing/TimedTaskSettingActivity.java @@ -14,7 +14,6 @@ import android.provider.Settings; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; -import androidx.core.content.FileProvider; import android.text.TextUtils; import android.util.Log; @@ -394,7 +393,7 @@ public class TimedTaskSettingActivity extends BaseActivity { if (mIntentTask != null) { TimedTaskManager.getInstance().removeTask(mIntentTask); } - Toast.makeText(this, R.string.text_already_create, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.text_already_created, Toast.LENGTH_SHORT).show(); } else { task.setId(mTimedTask.getId()); TimedTaskManager.getInstance().updateTask(task); @@ -426,7 +425,7 @@ public class TimedTaskSettingActivity extends BaseActivity { if (mIntentTask != null) { task.setId(mIntentTask.getId()); TimedTaskManager.getInstance().updateTask(task); - Toast.makeText(this, R.string.text_already_create, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.text_already_created, Toast.LENGTH_SHORT).show(); } else { TimedTaskManager.getInstance().addTask(task); if (mTimedTask != null) { diff --git a/app/src/main/java/org/autojs/autojs/ui/update/UpdateCheckDialog.java b/app/src/main/java/org/autojs/autojs/ui/update/UpdateCheckDialog.java new file mode 100644 index 00000000..36222910 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/ui/update/UpdateCheckDialog.java @@ -0,0 +1,61 @@ +package org.autojs.autojs.ui.update; + +import android.content.Context; + +import com.afollestad.materialdialogs.MaterialDialog; +import com.stardust.app.GlobalAppContext; + +import org.autojs.autojs.R; +import org.autojs.autojs.network.VersionService; +import org.autojs.autojs.network.entity.VersionInfo; +import org.autojs.autojs.tool.SimpleObserver; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.annotations.NonNull; + +/** + * Created by Stardust on 2017/9/20. + */ + +public class UpdateCheckDialog { + + private final MaterialDialog mProgress; + private final Context mContext; + + public UpdateCheckDialog(Context context) { + mContext = context; + mProgress = new MaterialDialog.Builder(context) + .title(R.string.text_under_development_title) + .content(R.string.text_under_development_content) + .positiveText(R.string.text_ok) + .build(); +// mProgress = new MaterialDialog.Builder(context) +// .progress(true, 0) +// .content(R.string.text_checking_update) +// .build(); + } + + public void show() { + mProgress.show(); +// VersionService.checkForUpdates() +// .observeOn(AndroidSchedulers.mainThread()) +// .subscribe(new SimpleObserver<>() { +// @Override +// public void onNext(@NonNull VersionInfo versionInfo) { +// mProgress.dismiss(); +// if (versionInfo.isNewer()) { +// new UpdateInfoDialogBuilder(mContext, versionInfo).show(); +// } else { +// GlobalAppContext.toast(R.string.text_is_latest_version); +// } +// } +// +// @Override +// public void onError(@NonNull Throwable e) { +// e.printStackTrace(); +// mProgress.dismiss(); +// GlobalAppContext.toast(R.string.text_check_update_error); +// } +// }); + } +} diff --git a/app/src/main/java/org/autojs/autojs/ui/update/UpdateInfoDialogBuilder.java b/app/src/main/java/org/autojs/autojs/ui/update/UpdateInfoDialogBuilder.java new file mode 100644 index 00000000..ec2dfb9b --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/ui/update/UpdateInfoDialogBuilder.java @@ -0,0 +1,68 @@ +package org.autojs.autojs.ui.update; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import androidx.annotation.NonNull; + +import com.afollestad.materialdialogs.MaterialDialog; +import com.stardust.app.GlobalAppContext; +import com.stardust.util.IntentUtil; + +import org.autojs.autojs.Pref; +import org.autojs.autojs.R; +import org.autojs.autojs.external.fileprovider.AppFileProvider; +import org.autojs.autojs.network.download.DownloadManager; +import org.autojs.autojs.network.entity.VersionInfo; + +import java.io.File; + +import io.reactivex.android.schedulers.AndroidSchedulers; + +/** + * Created by Stardust on 2017/4/9. + */ + +public class UpdateInfoDialogBuilder extends MaterialDialog.Builder { + + private static final String KEY_IGNORED_VERSION_PREFIX = "Ignored version: "; + private final SharedPreferences mSharedPreferences; + private VersionInfo mVersionInfo; + + public UpdateInfoDialogBuilder(@NonNull Context context, VersionInfo info) { + super(context); + mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + updateInfo(info); + } + + public void updateInfo(VersionInfo info) { + mVersionInfo = info; + title(GlobalAppContext.getString(R.string.text_new_version_found)); + content(info.appVersionName + "\n" + info.appVersionCode); + } + + @Override + public MaterialDialog show() { + if (mSharedPreferences.getBoolean(KEY_IGNORED_VERSION_PREFIX + mVersionInfo.appVersionCode, false)) { + return null; + } + return super.show(); + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + @SuppressLint("CheckResult") + private void directlyDownload(String downloadUrl) { + final String path = new File(Pref.getScriptDirPath(), "autojs6-latest.apk").getPath(); + DownloadManager.getInstance().downloadWithProgress(getContext(), downloadUrl, path) + .subscribeOn(AndroidSchedulers.mainThread()) + .subscribe(file -> IntentUtil.installApkOrToast(getContext(), file.getPath(), AppFileProvider.AUTHORITY), + error -> { + error.printStackTrace(); + GlobalAppContext.toast(R.string.text_download_failed); + }); + + } + +} diff --git a/app/src/main/java/org/autojs/autojs/ui/user/LoginActivity.java b/app/src/main/java/org/autojs/autojs/ui/user/LoginActivity.java deleted file mode 100644 index 9ae4d447..00000000 --- a/app/src/main/java/org/autojs/autojs/ui/user/LoginActivity.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.autojs.autojs.ui.user; - -import android.content.Intent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.TextView; -import android.widget.Toast; - -import com.afollestad.materialdialogs.MaterialDialog; -import org.autojs.autojs.R; -import org.autojs.autojs.network.NodeBB; -import org.autojs.autojs.network.UserService; -import org.autojs.autojs.ui.BaseActivity; -import com.stardust.theme.ThemeColorManager; - -import org.androidannotations.annotations.AfterViews; -import org.androidannotations.annotations.Click; -import org.androidannotations.annotations.EActivity; -import org.androidannotations.annotations.ViewById; - -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; - -/** - * Created by Stardust on 2017/9/20. - */ -@EActivity(R.layout.activity_login) -public class LoginActivity extends BaseActivity { - - @ViewById(R.id.username) - TextView mUserName; - - @ViewById(R.id.password) - TextView mPassword; - - @ViewById(R.id.login) - View mLogin; - - @AfterViews - void setUpViews() { - setToolbarAsBack(getString(R.string.text_login)); - ThemeColorManager.addViewBackground(mLogin); - } - - @Click(R.id.login) - void login() { - String userName = mUserName.getText().toString(); - String password = mPassword.getText().toString(); - if (!checkNotEmpty(userName, password)) { - return; - } - MaterialDialog dialog = new MaterialDialog.Builder(this) - .progress(true, 0) - .content(R.string.text_logging_in) - .cancelable(false) - .show(); - UserService.getInstance().login(userName, password) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(response -> { - dialog.dismiss(); - Toast.makeText(getApplicationContext(), R.string.text_login_succeed, Toast.LENGTH_SHORT).show(); - finish(); - } - , error -> { - dialog.dismiss(); - mPassword.setError(NodeBB.getErrorMessage(error, LoginActivity.this, R.string.text_login_fail)); - }); - - } - - @Click(R.id.forgot_password) - void forgotPassword() { - WebActivity_.intent(this) - .extra(WebActivity.EXTRA_URL, NodeBB.BASE_URL + "reset") - .extra(Intent.EXTRA_TITLE, getString(R.string.text_reset_password)) - .start(); - } - - private boolean checkNotEmpty(String userName, String password) { - if (userName.isEmpty()) { - mUserName.setError(getString(R.string.text_username_cannot_be_empty)); - return false; - } - if (password.isEmpty()) { - mUserName.setError(getString(R.string.text_password_cannot_be_empty)); - return false; - } - return true; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_login, menu); - return true; - } - - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.action_register) { - RegisterActivity_.intent(this).start(); - finish(); - } - return super.onOptionsItemSelected(item); - } -} diff --git a/app/src/main/java/org/autojs/autojs/ui/user/RegisterActivity.java b/app/src/main/java/org/autojs/autojs/ui/user/RegisterActivity.java deleted file mode 100644 index 2f09aa56..00000000 --- a/app/src/main/java/org/autojs/autojs/ui/user/RegisterActivity.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.autojs.autojs.ui.user; - -import android.util.Log; -import android.util.Patterns; -import android.view.View; -import android.widget.TextView; -import android.widget.Toast; - -import com.afollestad.materialdialogs.MaterialDialog; -import org.autojs.autojs.R; -import org.autojs.autojs.network.NodeBB; -import org.autojs.autojs.network.UserService; -import org.autojs.autojs.ui.BaseActivity; -import com.stardust.theme.ThemeColorManager; - -import org.androidannotations.annotations.AfterViews; -import org.androidannotations.annotations.Click; -import org.androidannotations.annotations.EActivity; -import org.androidannotations.annotations.ViewById; - -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; - -/** - * Created by Stardust on 2017/10/26. - */ -@EActivity(R.layout.activity_register) -public class RegisterActivity extends BaseActivity { - - @ViewById(R.id.email) - TextView mEmail; - - @ViewById(R.id.username) - TextView mUserName; - - @ViewById(R.id.password) - TextView mPassword; - - @ViewById(R.id.register) - View mRegister; - - - @AfterViews - void setUpViews() { - setToolbarAsBack(getString(R.string.text_register)); - ThemeColorManager.addViewBackground(mRegister); - } - - @Click(R.id.register) - void login() { - String email = mEmail.getText().toString(); - String userName = mUserName.getText().toString(); - String password = mPassword.getText().toString(); - if (!validateInput(email, userName, password)) { - return; - } - MaterialDialog dialog = new MaterialDialog.Builder(this) - .progress(true, 0) - .content(R.string.text_registering) - .cancelable(false) - .show(); - UserService.getInstance().register(email, userName, password) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(response -> { - dialog.dismiss(); - onRegisterResponse(response.string()); - } - , error -> { - dialog.dismiss(); - mPassword.setError(NodeBB.getErrorMessage(error, RegisterActivity.this, R.string.text_register_fail)); - }); - - } - - private void onRegisterResponse(String res) { - Toast.makeText(this, R.string.text_register_succeed, Toast.LENGTH_SHORT).show(); - finish(); - } - - private boolean validateInput(String email, String userName, String password) { - if (email.isEmpty()) { - mEmail.setError(getString(R.string.text_email_cannot_be_empty)); - return false; - } - if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) { - mEmail.setError(getString(R.string.text_email_format_error)); - return false; - } - if (userName.isEmpty()) { - mUserName.setError(getString(R.string.text_username_cannot_be_empty)); - return false; - } - if (password.isEmpty()) { - mUserName.setError(getString(R.string.text_password_cannot_be_empty)); - return false; - } - if (password.length() < 6) { - mPassword.setError(getString(R.string.nodebb_error_change_password_error_length)); - return false; - } - return true; - } -} diff --git a/app/src/main/java/org/autojs/autojs/ui/user/UserDetailActivity.java b/app/src/main/java/org/autojs/autojs/ui/user/UserDetailActivity.java deleted file mode 100644 index 3dbba999..00000000 --- a/app/src/main/java/org/autojs/autojs/ui/user/UserDetailActivity.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.autojs.autojs.ui.user; - -import org.autojs.autojs.ui.BaseActivity; - -/** - * Created by Stardust on 2017/10/26. - */ - -public class UserDetailActivity extends WebActivity { - -} diff --git a/app/src/main/java/org/autojs/autojs/ui/user/WebActivity.java b/app/src/main/java/org/autojs/autojs/ui/user/WebActivity.java deleted file mode 100644 index 28bbb16a..00000000 --- a/app/src/main/java/org/autojs/autojs/ui/user/WebActivity.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.autojs.autojs.ui.user; - -import android.content.Intent; -import androidx.annotation.NonNull; - -import com.stardust.app.OnActivityResultDelegate; -import org.autojs.autojs.R; -import org.autojs.autojs.ui.BaseActivity; -import org.autojs.autojs.ui.widget.EWebView; - -import org.androidannotations.annotations.AfterViews; -import org.androidannotations.annotations.EActivity; -import org.androidannotations.annotations.ViewById; - -/** - * Created by Stardust on 2017/10/26. - */ -@EActivity(R.layout.activity_web) -public class WebActivity extends BaseActivity implements OnActivityResultDelegate.DelegateHost { - - public static final String EXTRA_URL = "url"; - - private OnActivityResultDelegate.Mediator mMediator = new OnActivityResultDelegate.Mediator(); - - @ViewById(R.id.eweb_view) - EWebView mEWebView; - - @AfterViews - void setupViews() { - setToolbarAsBack(getIntent().getStringExtra(Intent.EXTRA_TITLE)); - mEWebView.getWebView().loadUrl(getIntent().getStringExtra(EXTRA_URL)); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - mMediator.onActivityResult(requestCode, resultCode, data); - } - - @NonNull - @Override - public OnActivityResultDelegate.Mediator getOnActivityResultDelegateMediator() { - return mMediator; - } -} diff --git a/app/src/main/java/org/autojs/autojs/ui/widget/AppWithStatusBarLayout.java b/app/src/main/java/org/autojs/autojs/ui/widget/AppWithStatusBarLayout.java index 4addc273..84818a66 100644 --- a/app/src/main/java/org/autojs/autojs/ui/widget/AppWithStatusBarLayout.java +++ b/app/src/main/java/org/autojs/autojs/ui/widget/AppWithStatusBarLayout.java @@ -5,14 +5,15 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.res.Configuration; import android.graphics.Rect; -import androidx.annotation.IntDef; -import androidx.annotation.Nullable; -import com.google.android.material.appbar.AppBarLayout; import android.util.AttributeSet; import android.util.TypedValue; import android.view.ViewTreeObserver; import android.view.Window; +import androidx.annotation.Nullable; + +import com.google.android.material.appbar.AppBarLayout; + /** * Created by Stardust on 2017/8/22. */ diff --git a/app/src/main/java/org/autojs/autojs/ui/widget/AvatarView.java b/app/src/main/java/org/autojs/autojs/ui/widget/AvatarView.java deleted file mode 100644 index f5ed2b82..00000000 --- a/app/src/main/java/org/autojs/autojs/ui/widget/AvatarView.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.autojs.autojs.ui.widget; - -import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.GradientDrawable; -import androidx.annotation.AttrRes; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.TextView; - -import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.DiskCacheStrategy; -import com.bumptech.glide.request.RequestOptions; -import com.makeramen.roundedimageview.RoundedImageView; - -import org.autojs.autojs.R; -import org.autojs.autojs.network.NodeBB; -import org.autojs.autojs.network.entity.user.User; - -import butterknife.BindView; -import butterknife.ButterKnife; - -/** - * Created by 婷 on 2017/9/29. - */ - -public class AvatarView extends FrameLayout { - - @BindView(R.id.icon_text) - TextView mIconText; - - @BindView(R.id.icon) - RoundedImageView mIcon; - - private GradientDrawable mIconTextBackground; - - - public AvatarView(@NonNull Context context) { - super(context); - init(); - } - - public AvatarView(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - init(); - } - - public AvatarView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(); - } - - private void init() { - inflate(getContext(), R.layout.avatar_view, this); - ButterKnife.bind(this); - mIconTextBackground = (GradientDrawable) mIconText.getBackground(); - } - - public void setIcon(int resId) { - mIcon.setVisibility(View.VISIBLE); - mIconText.setVisibility(View.GONE); - mIcon.setImageResource(resId); - } - - public void setUser(final User user) { - if (TextUtils.isEmpty(user.getPicture())) { - mIcon.setVisibility(View.GONE); - mIconText.setVisibility(View.VISIBLE); - mIconTextBackground.setColor(Color.parseColor(user.getIconBgColor())); - mIconTextBackground.setCornerRadius(getWidth() / 2); - mIconText.setText(user.getIconText()); - } else { - mIcon.setVisibility(View.VISIBLE); - mIconText.setVisibility(View.GONE); - mIcon.setCornerRadius(getWidth() / 2); - Glide.with(getContext()) - .load(NodeBB.BASE_URL + user.getPicture()) - .apply(new RequestOptions() - .diskCacheStrategy(DiskCacheStrategy.NONE) - .skipMemoryCache(true) - ) - .into(mIcon); - } - } -} - diff --git a/app/src/main/java/org/autojs/autojs/ui/widget/BubblePopupMenu.java b/app/src/main/java/org/autojs/autojs/ui/widget/BubblePopupMenu.java index 3e007f09..764968f9 100644 --- a/app/src/main/java/org/autojs/autojs/ui/widget/BubblePopupMenu.java +++ b/app/src/main/java/org/autojs/autojs/ui/widget/BubblePopupMenu.java @@ -3,13 +3,14 @@ package org.autojs.autojs.ui.widget; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; -import androidx.recyclerview.widget.RecyclerView; import android.view.Gravity; import android.view.View; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; +import androidx.recyclerview.widget.RecyclerView; + import org.autojs.autojs.R; import java.util.List; @@ -20,20 +21,19 @@ import java.util.List; public class BubblePopupMenu extends PopupWindow { - public interface OnItemClickListener { void onClick(View view, int position); } - private RecyclerView mRecyclerView; + private final RecyclerView mRecyclerView; private OnItemClickListener mOnItemClickListener; - private View mLittleTriangle; + private final View mLittleTriangle; public BubblePopupMenu(Context context, List options) { super(context); View view = View.inflate(context, R.layout.bubble_popup_menu, null); mLittleTriangle = view.findViewById(R.id.little_triangle); - mRecyclerView = (RecyclerView) view.findViewById(R.id.list); + mRecyclerView = view.findViewById(R.id.list); mRecyclerView.setAdapter(new SimpleRecyclerViewAdapter<>(R.layout.bubble_popup_menu_item, options, MenuItemViewHolder::new)); setContentView(view); setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); @@ -51,13 +51,7 @@ public class BubblePopupMenu extends PopupWindow { int width = getContentView().getMeasuredWidth(); int height = getContentView().getMeasuredHeight(); LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mLittleTriangle.getLayoutParams(); - if (x + width > screenWidth) { - params.leftMargin = x + width - screenWidth; - } else if (x < 0) { - params.leftMargin = x; - } else { - params.leftMargin = 0; - } + params.leftMargin = x + width > screenWidth ? x + width - screenWidth : Math.min(x, 0); if (y > screenHeight / 2) { getContentView().setRotation(180); mRecyclerView.setRotation(180); @@ -71,26 +65,21 @@ public class BubblePopupMenu extends PopupWindow { super.showAtLocation(parent, Gravity.NO_GRAVITY, x, y); } - public void preMeasure() { getContentView().measure(getWidth(), getHeight()); } - private class MenuItemViewHolder extends BindableViewHolder { - private TextView mOption; + private final TextView mOption; public MenuItemViewHolder(View itemView) { super(itemView); - mOption = (TextView) itemView.findViewById(R.id.option); - itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mOnItemClickListener != null) { - int i = mRecyclerView.getChildAdapterPosition(v); - mOnItemClickListener.onClick(v, i); - } + mOption = itemView.findViewById(R.id.option); + itemView.setOnClickListener(v -> { + if (mOnItemClickListener != null) { + int i = mRecyclerView.getChildAdapterPosition(v); + mOnItemClickListener.onClick(v, i); } }); } diff --git a/app/src/main/jniLibs/arm64-v8a/libc++_shared.so b/app/src/main/jniLibs/arm64-v8a/libc++_shared.so new file mode 100644 index 00000000..8ea640ca Binary files /dev/null and b/app/src/main/jniLibs/arm64-v8a/libc++_shared.so differ diff --git a/app/src/main/jniLibs/armeabi-v7a/libc++_shared.so b/app/src/main/jniLibs/armeabi-v7a/libc++_shared.so new file mode 100644 index 00000000..3b084d23 Binary files /dev/null and b/app/src/main/jniLibs/armeabi-v7a/libc++_shared.so differ diff --git a/app/src/main/jniLibs/armeabi-v7a/libjackpal-androidterm5.so b/app/src/main/jniLibs/armeabi-v7a/libjackpal-androidterm5.so deleted file mode 100644 index 8abd6b57..00000000 Binary files a/app/src/main/jniLibs/armeabi-v7a/libjackpal-androidterm5.so and /dev/null differ diff --git a/app/src/main/jniLibs/armeabi-v7a/libjackpal-termexec2.so b/app/src/main/jniLibs/armeabi-v7a/libjackpal-termexec2.so deleted file mode 100644 index a413d87f..00000000 Binary files a/app/src/main/jniLibs/armeabi-v7a/libjackpal-termexec2.so and /dev/null differ diff --git a/app/src/main/jniLibs/armeabi-v7a/libopencv_java3.so b/app/src/main/jniLibs/armeabi-v7a/libopencv_java3.so deleted file mode 100644 index 38f1ba4f..00000000 Binary files a/app/src/main/jniLibs/armeabi-v7a/libopencv_java3.so and /dev/null differ diff --git a/app/src/main/jniLibs/armeabi/libjackpal-androidterm5.so b/app/src/main/jniLibs/armeabi/libjackpal-androidterm5.so deleted file mode 100644 index 8abd6b57..00000000 Binary files a/app/src/main/jniLibs/armeabi/libjackpal-androidterm5.so and /dev/null differ diff --git a/app/src/main/jniLibs/armeabi/libjackpal-termexec2.so b/app/src/main/jniLibs/armeabi/libjackpal-termexec2.so deleted file mode 100644 index a413d87f..00000000 Binary files a/app/src/main/jniLibs/armeabi/libjackpal-termexec2.so and /dev/null differ diff --git a/app/src/main/jniLibs/x86/libc++_shared.so b/app/src/main/jniLibs/x86/libc++_shared.so new file mode 100644 index 00000000..d938772f Binary files /dev/null and b/app/src/main/jniLibs/x86/libc++_shared.so differ diff --git a/app/src/main/jniLibs/x86_64/libc++_shared.so b/app/src/main/jniLibs/x86_64/libc++_shared.so new file mode 100644 index 00000000..18bec40b Binary files /dev/null and b/app/src/main/jniLibs/x86_64/libc++_shared.so differ diff --git a/app/src/main/res/layout/activity_about_items.xml b/app/src/main/res/layout/activity_about_items.xml index a4acf8b2..e338aabc 100644 --- a/app/src/main/res/layout/activity_about_items.xml +++ b/app/src/main/res/layout/activity_about_items.xml @@ -56,7 +56,7 @@ diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml deleted file mode 100644 index 29c7be77..00000000 --- a/app/src/main/res/layout/activity_login.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_timed_task_setting.xml b/app/src/main/res/layout/activity_timed_task_setting.xml index 97ae4d39..e2a3157e 100644 --- a/app/src/main/res/layout/activity_timed_task_setting.xml +++ b/app/src/main/res/layout/activity_timed_task_setting.xml @@ -263,7 +263,7 @@ android:layout_height="wrap_content" android:layout_marginTop="16dp" android:paddingStart="16dp" - android:text="@string/text_run_on_broadcast" + android:text="@string/text_broadcast_task" tools:ignore="RtlSymmetry" /> - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/air_card_login_compat.xml b/app/src/main/res/layout/air_card_login_compat.xml index ea52b5b5..c7f1317c 100644 --- a/app/src/main/res/layout/air_card_login_compat.xml +++ b/app/src/main/res/layout/air_card_login_compat.xml @@ -23,82 +23,67 @@ --> - - + app:cardBackgroundColor="?cardBackgroundColor"> + + + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/air_title_login" + android:textAppearance="@style/TextAppearance.AppCompat.Body2" + android:textColor="?android:textColorSecondary" /> - + - - - - + android:layout_marginTop="@dimen/air_baseline" + android:paddingStart="@dimen/air_radio_button_padding_start" + android:paddingLeft="@dimen/air_radio_button_padding_start" + android:paddingEnd="0dp" + android:paddingRight="0dp" + android:checked="true" + android:text="@string/air_label_use_guest" /> - + + - - - - + android:orientation="vertical"> - - + android:layout_marginTop="@dimen/air_baseline_half" + android:hint="@string/air_label_email_optional"> + + @@ -107,48 +92,65 @@ - - - - + android:layout_marginTop="@dimen/air_baseline" + android:checked="false" + android:paddingStart="@dimen/air_radio_button_padding_start" + android:paddingLeft="@dimen/air_radio_button_padding_start" + android:paddingEnd="0dp" + android:paddingRight="0dp" + android:text="@string/air_label_use_account" /> - + + + android:orientation="vertical"> - + android:layout_marginTop="@dimen/air_baseline_half" + android:hint="@string/air_label_username"> + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_find_or_replace.xml b/app/src/main/res/layout/dialog_find_or_replace.xml index 5b45215b..c6b2f245 100644 --- a/app/src/main/res/layout/dialog_find_or_replace.xml +++ b/app/src/main/res/layout/dialog_find_or_replace.xml @@ -61,7 +61,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="4dp" - android:text="@string/hint_regex" + android:text="@string/hint_find_with_regex" android:textColor="#929397" android:textSize="12sp"/> diff --git a/app/src/main/res/layout/dialog_script_loop.xml b/app/src/main/res/layout/dialog_script_loop.xml index 8a979a7e..daa5854c 100644 --- a/app/src/main/res/layout/dialog_script_loop.xml +++ b/app/src/main/res/layout/dialog_script_loop.xml @@ -1,73 +1,82 @@ - + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingLeft="16dp" + android:paddingRight="16dp"> - - - - - - - - + android:layout_marginVertical="12dp" + android:textColorHint="#91000000" + android:hint="@string/text_loop_times"> + android:id="@+id/loop_times" + android:layout_width="match_parent" + android:layout_height="48dp" + android:inputType="number" + android:text="0" + android:textColor="#ff000000" + tools:ignore="HardcodedText" + android:height="48dp" /> + + - - + android:layout_marginVertical="12dp" + android:textColorHint="#91000000" + android:hint="@string/text_loop_interval"> + + + + + + + + + + - \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_update_info.xml b/app/src/main/res/layout/dialog_update_info.xml deleted file mode 100644 index 714972b5..00000000 --- a/app/src/main/res/layout/dialog_update_info.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/dialog_update_info_btn.xml b/app/src/main/res/layout/dialog_update_info_btn.xml deleted file mode 100644 index dbe47a12..00000000 --- a/app/src/main/res/layout/dialog_update_info_btn.xml +++ /dev/null @@ -1,9 +0,0 @@ - -