Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0374a835e | ||
|
|
c033dbef72 | ||
|
|
a8ce1b9acb | ||
|
|
ec61eb5000 |
136
README.md
136
README.md
@@ -26,6 +26,7 @@
|
||||
### 简介
|
||||
|
||||
* Android 平台支持无障碍服务的 JavaScript 自动化工具
|
||||
* 需要 [Android 7.0](https://zh.wikipedia.org/wiki/Android_Nougat) (`API 24`) 及以上
|
||||
* 复刻 (Fork) 自 [hyb1996/Auto.js](https://github.com/hyb1996/Auto.js)
|
||||
|
||||
******
|
||||
@@ -53,7 +54,7 @@
|
||||
* 支持将脚本文件或项目打包为 APK 文件
|
||||
* 支持利用 Root 权限扩展功能 (屏幕点击/滑动/录制/Shell)
|
||||
* 支持作为 Tasker 插件使用
|
||||
* 支持与 VSCode 连接并进行桌面开发 (需要 [AutoJs6-VSCode-Ext](https://github.com/SuperMonster003/AutoJs6-VSCode-Ext) 插件)
|
||||
* 支持与 VSCode 连接并进行桌面开发 (需要 [AutoJs6-VSCode-Extension](https://github.com/SuperMonster003/AutoJs6-VSCode-Extension) 插件)
|
||||
|
||||
******
|
||||
|
||||
@@ -61,7 +62,10 @@
|
||||
|
||||
******
|
||||
|
||||
* Rhino 引擎由 [v1.7.7.2](https://github.com/mozilla/rhino/releases/tag/Rhino1_7_7_2_Release) 升级至 [v1.7.14 (SNAPSHOT)](https://github.com/mozilla/rhino/)
|
||||
* VSCode 插件支持客户端 (LAN) 及服务端 (LAN/ADB) 连接方式
|
||||
|
||||
|
||||
* Rhino 引擎由 [v1.7.7.2](https://github.com/mozilla/rhino/releases/tag/Rhino1_7_7_2_Release) 升级至 [v1.7.14](https://github.com/mozilla/rhino/)
|
||||
|
||||
* 支持 [Object.values()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/values)
|
||||
|
||||
@@ -99,6 +103,58 @@
|
||||
|
||||
[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
|
||||
|
||||
* `新增` images.bilateralFilter() 双边滤波图像处理方法
|
||||
* `修复` 多次调用 toast 只生效最后一次调用的问题
|
||||
* `修复` toast.dismiss() 可能无效的问题
|
||||
* `修复` 客户端模式及服务端模式开关可能无法正常工作的问题
|
||||
* `修复` 客户端模式及服务端模式开关状态不能正常刷新的问题
|
||||
* `修复` 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
|
||||
* `优化` 升级 Androidx Preference 版本 1.1.1 -> 1.2.0
|
||||
* `优化` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.3 -> 5.0.0-alpha.4
|
||||
* `优化` 升级 Android Material 版本 1.6.0-alpha01 -> 1.6.0-alpha02
|
||||
* `优化` 升级 Android Gradle 插件版本 7.2.0-alpha06 -> 7.2.0-beta01
|
||||
* `优化` 升级 Gradle 发行版本 7.3.3 -> 7.4-rc-2
|
||||
|
||||
# v6.0.1
|
||||
|
||||
###### 2022/01/01
|
||||
@@ -117,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)
|
||||
@@ -190,11 +183,14 @@
|
||||
|
||||
******
|
||||
|
||||
* [AutoJs6-VSCode-Ext](https://github.com/SuperMonster003/AutoJs6-VSCode-Ext) { 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 自动化工具 (二次开发项目)`
|
||||
|
||||
[//]: # (* [Auto.js-TypeScript-Declarations](https://github.com/SuperMonster003/Auto.js-TypeScript-Declarations) { author: [SuperMonster003](https://github.com/SuperMonster003) })
|
||||
[//]: # ( - `Auto.js 声明文件 (.d.ts)`)
|
||||
* [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)`)
|
||||
|
||||
162
app/build.gradle
162
app/build.gradle
@@ -1,16 +1,12 @@
|
||||
plugins {
|
||||
id "com.android.application"
|
||||
id "com.jakewharton.butterknife"
|
||||
id "kotlin-android"
|
||||
id "kotlin-kapt"
|
||||
id 'com.android.application'
|
||||
id 'com.jakewharton.butterknife'
|
||||
id 'kotlin-android'
|
||||
id 'kotlin-kapt'
|
||||
}
|
||||
|
||||
def annotationsVer = "4.8.0"
|
||||
def butterKnifeVer = "10.2.3"
|
||||
def leakcanaryVer = "2.7"
|
||||
|
||||
def properties = new Properties()
|
||||
def propFile = new File("sign.properties")
|
||||
def propFile = new File('sign.properties')
|
||||
def isPropFileExists = propFile.exists()
|
||||
|
||||
isPropFileExists && properties.load(new FileInputStream(propFile))
|
||||
@@ -22,32 +18,32 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
||||
}
|
||||
|
||||
// tasks.withType(JavaCompile) {
|
||||
// options.compilerArgs << "-Xlint:deprecation" << "-Xlint:unchecked"
|
||||
// options.compilerArgs << '-Xlint:deprecation' << '-Xlint:unchecked'
|
||||
// }
|
||||
|
||||
android {
|
||||
signingConfigs {
|
||||
isPropFileExists && release {
|
||||
storeFile file(properties["storeFile"])
|
||||
keyPassword properties["keyPassword"]
|
||||
keyAlias properties["keyAlias"]
|
||||
storePassword properties["storePassword"]
|
||||
storeFile file(properties['storeFile'])
|
||||
keyPassword properties['keyPassword']
|
||||
keyAlias properties['keyAlias']
|
||||
storePassword properties['storePassword']
|
||||
}
|
||||
}
|
||||
compileSdkVersion versions.compile
|
||||
compileSdkVersion versions.project.compile
|
||||
defaultConfig {
|
||||
applicationId "org.autojs.autojs"
|
||||
minSdkVersion versions.mini
|
||||
targetSdkVersion versions.target
|
||||
versionCode versions.appVersionCode
|
||||
versionName versions.appVersionName
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
applicationId 'org.autojs.autojs'
|
||||
minSdkVersion versions.project.mini
|
||||
targetSdkVersion versions.project.target
|
||||
versionCode versions.project.appVersionCode
|
||||
versionName versions.project.appVersionName
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
multiDexEnabled true
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments = [
|
||||
"resourcePackageName": applicationId,
|
||||
"androidManifestFile": "$projectDir/src/main/AndroidManifest.xml".toString()
|
||||
'resourcePackageName': applicationId,
|
||||
'androidManifestFile': "$projectDir/src/main/AndroidManifest.xml".toString()
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -56,7 +52,7 @@ android {
|
||||
debug {
|
||||
shrinkResources false
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
if (isPropFileExists) {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
@@ -68,7 +64,7 @@ android {
|
||||
release {
|
||||
shrinkResources false
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
if (isPropFileExists) {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
@@ -77,17 +73,17 @@ android {
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_16
|
||||
targetCompatibility JavaVersion.VERSION_16
|
||||
encoding = "utf-8"
|
||||
encoding = 'utf-8'
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
disable "MissingTranslation"
|
||||
disable "ExtraTranslation"
|
||||
disable 'MissingTranslation'
|
||||
disable 'ExtraTranslation'
|
||||
}
|
||||
configurations.all {
|
||||
resolutionStrategy.force "com.google.code.findbugs:jsr305:3.0.1"
|
||||
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.1'
|
||||
}
|
||||
flavorDimensions "channel"
|
||||
flavorDimensions 'channel'
|
||||
splits {
|
||||
// Configures multiple APKs based on ABI.
|
||||
abi {
|
||||
@@ -101,22 +97,33 @@ android {
|
||||
reset()
|
||||
|
||||
// Specifies a list of ABIs that Gradle should create APKs for.
|
||||
include "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 {
|
||||
common {
|
||||
buildConfigField "String", "CHANNEL", "\"common\""
|
||||
buildConfigField "String", "APP_SINCE_DATE", "\"${versions.appSinceDate}\""
|
||||
buildConfigField 'String', 'CHANNEL', '"common"'
|
||||
buildConfigField 'String', 'APP_SINCE_DATE', "\"${versions.project.appSinceDate}\""
|
||||
}
|
||||
}
|
||||
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/**"]))
|
||||
delete(fileTree(dir: outputDir, includes: ['declarations/**']))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,103 +135,90 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
// JUnit
|
||||
testImplementation "junit:junit:${junitVer}"
|
||||
testImplementation "junit:junit:${versions.junit}"
|
||||
|
||||
// LeakCanary
|
||||
debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakcanaryVer}"
|
||||
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:${annotationsVer}"
|
||||
implementation "org.androidannotations:androidannotations-api:${annotationsVer}"
|
||||
kapt "org.androidannotations:androidannotations:${versions.annotations}"
|
||||
implementation "org.androidannotations:androidannotations-api:${versions.annotations}"
|
||||
|
||||
// ButterKnife
|
||||
kapt "com.jakewharton:butterknife-compiler:${butterKnifeVer}"
|
||||
implementation "com.jakewharton:butterknife:${butterKnifeVer}"
|
||||
kapt "com.jakewharton:butterknife-compiler:${versions.butterKnife}"
|
||||
implementation "com.jakewharton:butterknife:${versions.butterKnife}"
|
||||
|
||||
// Android supports
|
||||
implementation "androidx.appcompat:appcompat:1.4.0"
|
||||
implementation "androidx.cardview:cardview:1.0.0"
|
||||
implementation "com.google.android.material:material:1.6.0-alpha01"
|
||||
implementation "androidx.multidex:multidex:2.0.1"
|
||||
|
||||
// Material Dialogs
|
||||
implementation "com.afollestad.material-dialogs:core:0.9.6.0"
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
|
||||
// SwipeRefreshLayout
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
|
||||
// Common Markdown
|
||||
implementation "com.github.atlassian:commonmark-java:commonmark-parent-0.9.0"
|
||||
implementation 'com.github.atlassian:commonmark-java:commonmark-parent-0.9.0'
|
||||
|
||||
// Android issue reporter (a github issue reporter)
|
||||
implementation "com.heinrichreimersoftware:android-issue-reporter:1.3.1"
|
||||
implementation 'com.heinrichreimersoftware:android-issue-reporter:1.3.1'
|
||||
|
||||
// MultiLevelListView
|
||||
implementation "com.github.hyb1996:android-multi-level-listview:1.1"
|
||||
implementation 'com.github.hyb1996:android-multi-level-listview:1.1'
|
||||
|
||||
// Licenses Dialog
|
||||
implementation "de.psdev.licensesdialog:licensesdialog:2.2.0"
|
||||
implementation 'de.psdev.licensesdialog:licensesdialog:2.2.0'
|
||||
|
||||
// Expandable RecyclerView
|
||||
implementation "com.bignerdranch.android:expandablerecyclerview:3.0.0-RC1"
|
||||
implementation 'com.bignerdranch.android:expandablerecyclerview:3.0.0-RC1'
|
||||
|
||||
// FlexibleDivider
|
||||
implementation "com.yqritc:recyclerview-flexibledivider:1.4.0"
|
||||
implementation 'com.yqritc:recyclerview-flexibledivider:1.4.0'
|
||||
|
||||
// AVLoadingView
|
||||
implementation "com.wang.avi:library:2.1.3"
|
||||
implementation 'com.wang.avi:library:2.1.3'
|
||||
|
||||
// Commons Lang
|
||||
implementation "org.apache.commons:commons-lang3:3.12.0"
|
||||
implementation 'org.apache.commons:commons-lang3:3.12.0'
|
||||
|
||||
// Expandable RecyclerView
|
||||
implementation "com.thoughtbot:expandablerecyclerview:1.3"
|
||||
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"
|
||||
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
|
||||
implementation "com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0"
|
||||
implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2"
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||
implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
|
||||
implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
|
||||
|
||||
// Glide
|
||||
kapt "com.github.bumptech.glide:compiler:4.12.0"
|
||||
implementation "com.github.bumptech.glide:glide:4.12.0"
|
||||
kapt "com.github.bumptech.glide:compiler:${versions.glide}"
|
||||
|
||||
// Joda Time
|
||||
implementation "joda-time:joda-time:2.10.13"
|
||||
implementation 'joda-time:joda-time:2.10.13'
|
||||
|
||||
// Tasker Plugin
|
||||
implementation "com.twofortyfouram:android-plugin-client-sdk-for-locale:4.0.3"
|
||||
implementation 'com.twofortyfouram:android-plugin-client-sdk-for-locale:4.0.3'
|
||||
|
||||
// Flurry
|
||||
implementation "com.flurry.android:analytics:13.1.0"
|
||||
|
||||
// Material Dialogs
|
||||
implementation "com.afollestad.material-dialogs:commons:0.9.6.0"
|
||||
implementation 'com.flurry.android:analytics:13.1.0'
|
||||
|
||||
// Android Job
|
||||
implementation "com.evernote:android-job:1.4.2"
|
||||
implementation 'com.evernote:android-job:1.4.2'
|
||||
|
||||
// Extracted from com.github.hyb1996:MutableTheme:1.0.0
|
||||
implementation "com.jrummyapps:colorpicker:2.1.7"
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
||||
implementation "com.github.ozodrukh:CircularReveal:2.0.1"
|
||||
implementation 'com.jrummyapps:colorpicker:2.1.7'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||
implementation 'com.github.ozodrukh:CircularReveal:2.0.1'
|
||||
|
||||
// Bugly
|
||||
implementation project(":libs:com.tencent.bugly.crashreport-2.6.6")
|
||||
implementation project(':libs:com.tencent.bugly.crashreport-2.6.6')
|
||||
|
||||
implementation project(":automator")
|
||||
implementation project(":common")
|
||||
implementation project(":autojs")
|
||||
implementation project(':automator')
|
||||
implementation project(':common')
|
||||
implementation project(':autojs')
|
||||
}
|
||||
|
||||
java {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package="org.autojs.autojs">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||
@@ -29,7 +30,7 @@
|
||||
|
||||
|
||||
<application
|
||||
android:name=".App"
|
||||
android:name="org.autojs.autojs.App"
|
||||
android:allowBackup="false"
|
||||
android:icon="@drawable/autojs_material"
|
||||
android:label="@string/app_name"
|
||||
@@ -44,9 +45,8 @@
|
||||
android:value="2.1" />
|
||||
|
||||
<activity
|
||||
android:name=".ui.splash.SplashActivity"
|
||||
android:name="org.autojs.autojs.ui.splash.SplashActivity"
|
||||
android:hardwareAccelerated="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme.Splash"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
@@ -56,13 +56,12 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.main.MainActivity_"
|
||||
android:name="org.autojs.autojs.ui.main.MainActivity_"
|
||||
android:hardwareAccelerated="true"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/AppTheme.FullScreen" />
|
||||
<activity
|
||||
android:name=".external.shortcut.ShortcutActivity"
|
||||
android:name="org.autojs.autojs.external.shortcut.ShortcutActivity"
|
||||
android:taskAffinity="org.autojs.autojs.external.shortcut.ShortcutActivity"
|
||||
android:theme="@android:style/Theme.NoDisplay"
|
||||
android:exported="true">
|
||||
@@ -84,41 +83,34 @@
|
||||
</provider>
|
||||
|
||||
<activity
|
||||
android:name=".ui.edit.EditActivity_"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:name="org.autojs.autojs.ui.edit.EditActivity_"
|
||||
android:configChanges="orientation|screenSize|locale"
|
||||
android:launchMode="standard"
|
||||
android:multiprocess="true"
|
||||
android:taskAffinity="org.autojs.autojs.edit"
|
||||
android:theme="@style/EditorTheme" />
|
||||
<activity android:name=".ui.settings.AboutActivity_" />
|
||||
<activity android:name="org.autojs.autojs.ui.settings.AboutActivity_" />
|
||||
<activity
|
||||
android:name=".ui.settings.SettingsActivity_"
|
||||
android:name="org.autojs.autojs.ui.settings.SettingsActivity_"
|
||||
android:theme="@style/AppTheme.Settings" />
|
||||
<activity android:name=".ui.error.ErrorReportActivity" />
|
||||
<activity android:name="org.autojs.autojs.ui.error.ErrorReportActivity" />
|
||||
<activity
|
||||
android:name=".external.tasker.TaskerScriptEditActivity_"
|
||||
android:configChanges="orientation|screenSize" />
|
||||
<activity android:name=".ui.edit.ViewSampleActivity" />
|
||||
android:name="org.autojs.autojs.external.tasker.TaskerScriptEditActivity_"
|
||||
android:configChanges="orientation|screenSize|locale" />
|
||||
<activity android:name="org.autojs.autojs.ui.edit.ViewSampleActivity" />
|
||||
<activity
|
||||
android:name=".ui.user.LoginActivity_"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
android:name="org.autojs.autojs.ui.project.BuildActivity_"
|
||||
android:configChanges="orientation|screenSize|locale" />
|
||||
<activity android:name="org.autojs.autojs.ui.project.ProjectConfigActivity_" />
|
||||
<activity android:name="org.autojs.autojs.ui.log.LogActivity_" />
|
||||
<activity android:name="org.autojs.autojs.ui.doc.DocumentationActivity_" />
|
||||
<activity android:name="org.autojs.autojs.ui.shortcut.ShortcutIconSelectActivity_" />
|
||||
<activity android:name="org.autojs.autojs.ui.timing.TimedTaskSettingActivity_" />
|
||||
<activity
|
||||
android:name=".ui.user.RegisterActivity_"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity android:name=".ui.user.WebActivity_" />
|
||||
<activity
|
||||
android:name=".ui.project.BuildActivity_"
|
||||
android:configChanges="orientation|screenSize" />
|
||||
<activity android:name=".ui.project.ProjectConfigActivity_" />
|
||||
<activity android:name=".ui.log.LogActivity_" />
|
||||
<activity android:name=".ui.doc.DocumentationActivity_" />
|
||||
<activity android:name=".ui.shortcut.ShortcutIconSelectActivity_" />
|
||||
<activity android:name=".ui.timing.TimedTaskSettingActivity_" />
|
||||
<activity
|
||||
android:name=".ui.shortcut.ShortcutCreateActivity"
|
||||
android:name="org.autojs.autojs.ui.shortcut.ShortcutCreateActivity"
|
||||
android:theme="@style/AppTheme.Transparent" />
|
||||
<activity
|
||||
android:name=".external.widget.ScriptWidgetSettingsActivity_"
|
||||
android:name="org.autojs.autojs.external.widget.ScriptWidgetSettingsActivity_"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||
@@ -130,46 +122,46 @@
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ui.error.IssueReporterActivity"
|
||||
android:name="org.autojs.autojs.ui.error.IssueReporterActivity"
|
||||
android:theme="@style/IssueReporterTheme" />
|
||||
|
||||
|
||||
<service android:name=".external.foreground.ForegroundService" />
|
||||
<service android:name=".external.ScriptExecutionIntentService" />
|
||||
<service android:name="org.autojs.autojs.external.foreground.ForegroundService" />
|
||||
<service android:name="org.autojs.autojs.external.ScriptExecutionIntentService" />
|
||||
|
||||
<activity android:name=".external.tasker.TaskPrefEditActivity_" />
|
||||
<activity android:name="org.autojs.autojs.external.tasker.TaskPrefEditActivity_" />
|
||||
|
||||
<service
|
||||
android:name=".external.tile.LayoutBoundsTile"
|
||||
android:name="org.autojs.autojs.external.tile.LayoutBoundsTile"
|
||||
android:icon="@drawable/ic_circular_menu_bounds"
|
||||
android:label="@string/text_inspect_layout_bounds"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
|
||||
android:exported="false">
|
||||
android:exported="true">
|
||||
<meta-data
|
||||
android:name="android.service.quicksettings.ACTIVE_TILE"
|
||||
android:value="false" />
|
||||
android:value="true" />
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".external.tile.LayoutHierarchyTile"
|
||||
android:name="org.autojs.autojs.external.tile.LayoutHierarchyTile"
|
||||
android:icon="@drawable/ic_circular_menu_hierarchy"
|
||||
android:label="@string/text_inspect_layout_hierarchy"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
|
||||
android:exported="false">
|
||||
android:exported="true">
|
||||
|
||||
<meta-data
|
||||
android:name="android.service.quicksettings.ACTIVE_TILE"
|
||||
android:value="false" />
|
||||
android:value="true" />
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<activity-alias
|
||||
android:name=".external.tasker.PluginActivity"
|
||||
android:name="org.autojs.autojs.external.tasker.PluginActivity"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/ic_android_eat_js"
|
||||
android:label="@string/app_name"
|
||||
@@ -222,7 +214,7 @@
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".external.tasker.FireSettingReceiver"
|
||||
android:name="org.autojs.autojs.external.tasker.FireSettingReceiver"
|
||||
android:exported="true"
|
||||
android:process=":background"
|
||||
tools:ignore="ExportedReceiver">
|
||||
@@ -234,7 +226,7 @@
|
||||
</receiver>
|
||||
|
||||
<activity
|
||||
android:name=".external.open.EditIntentActivity"
|
||||
android:name="org.autojs.autojs.external.open.EditIntentActivity"
|
||||
android:icon="@drawable/autojs_material"
|
||||
android:label="@string/text_edit_script"
|
||||
android:exported="true">
|
||||
@@ -252,7 +244,7 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".external.open.RunIntentActivity"
|
||||
android:name="org.autojs.autojs.external.open.RunIntentActivity"
|
||||
android:icon="@drawable/autojs_material"
|
||||
android:label="@string/text_run_script"
|
||||
android:taskAffinity="org.autojs.autojs.external.open.RunIntentActivity"
|
||||
@@ -272,7 +264,7 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".external.open.ImportIntentActivity"
|
||||
android:name="org.autojs.autojs.external.open.ImportIntentActivity"
|
||||
android:icon="@drawable/autojs_material"
|
||||
android:label="@string/text_import_script"
|
||||
android:theme="@style/AppTheme.Transparent"
|
||||
@@ -302,7 +294,7 @@
|
||||
</service>
|
||||
|
||||
<receiver
|
||||
android:name=".external.widget.ScriptWidget"
|
||||
android:name="org.autojs.autojs.external.widget.ScriptWidget"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
@@ -314,7 +306,7 @@
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".timing.TaskReceiver"
|
||||
android:name="org.autojs.autojs.timing.TaskReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.stardust.autojs.action.task" />
|
||||
|
||||
@@ -4,6 +4,58 @@
|
||||
|
||||
******
|
||||
|
||||
# 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
|
||||
|
||||
* `新增` images.bilateralFilter() 双边滤波图像处理方法
|
||||
* `修复` 多次调用 toast 只生效最后一次调用的问题
|
||||
* `修复` toast.dismiss() 可能无效的问题
|
||||
* `修复` 客户端模式及服务端模式开关可能无法正常工作的问题
|
||||
* `修复` 客户端模式及服务端模式开关状态不能正常刷新的问题
|
||||
* `修复` 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
|
||||
* `优化` 升级 Androidx Preference 版本 1.1.1 -> 1.2.0
|
||||
* `优化` 升级 Okhttp3 版本 3.10.0 -> 5.0.0-alpha.3 -> 5.0.0-alpha.4
|
||||
* `优化` 升级 Android Material 版本 1.6.0-alpha01 -> 1.6.0-alpha02
|
||||
* `优化` 升级 Android Gradle 插件版本 7.2.0-alpha06 -> 7.2.0-beta01
|
||||
* `优化` 升级 Gradle 发行版本 7.3.3 -> 7.4-rc-2
|
||||
|
||||
# v6.0.1
|
||||
|
||||
###### 2022/01/01
|
||||
|
||||
@@ -961,7 +961,7 @@
|
||||
<li>如果想要在电脑而不是手机上开发Auto.js,可以使用VS Code以及相应的Auto.js插件使得在电脑上编辑的脚本能推送到手机运行,参见<a href="https://github.com/hyb1996/Auto.js-VSCode-Extension">Auto.js-VSCode-Extension</a>。</li>
|
||||
</ul>
|
||||
<p>本文档的章节大致上是以模块来分的,总体上可以分成"自动操作"类模块(控件操作、触摸模拟、按键模拟等)和其他类模块(设备、应用、界面等)。</p>
|
||||
<p>"自动操作"的部分又可以大致分为基于控件和基于坐标的操作。基于坐标的操作是传统按键精灵、触摸精灵等脚本软件采用的方式,通过屏幕坐标来点击、长按指定位置模拟操作,从而到达目的。例如<code>click(100, 200)</code>, <code>press(100, 200, 500)</code>等。这种方式在游戏类脚本中比较有可行性,结合找图找色、坐标放缩功能也能达到较好的兼容性。但是,这种方式对一般软件脚本却难以达到想要的效果,而且这种方式需要安卓7.0版本以上或者root权限才能执行。所以对于一般软件脚本(例如批量添加联系人、自动提取短信验证码等等),我们采用基于控件的模拟操作方式,结合通知事情、按键事情等达成更好的工作流。这些部分的文档参见<a href="widgets-based-automation.html">基于控件的操作</a>和<a href="coordinates-based-automation.html">基于坐标的操作</a>。</p>
|
||||
<p>"自动操作"的部分又可以大致分为基于控件和基于坐标的操作。基于坐标的操作是传统按键精灵、触摸精灵等脚本软件采用的方式,通过屏幕坐标来点击、长按指定位置模拟操作,从而到达目的。例如<code>click(100, 200)</code>, <code>press(100, 200, 500)</code>等。这种方式在游戏类脚本中比较有可行性,结合找图找色、坐标放缩功能也能达到较好的兼容性。但是,这种方式对一般软件脚本却难以达到想要的效果,而且这种方式需要root权限才能执行。所以对于一般软件脚本(例如批量添加联系人、自动提取短信验证码等等),我们采用基于控件的模拟操作方式,结合通知事情、按键事情等达成更好的工作流。这些部分的文档参见<a href="widgets-based-automation.html">基于控件的操作</a>和<a href="coordinates-based-automation.html">基于坐标的操作</a>。</p>
|
||||
<p>其他部分主要包括:</p>
|
||||
<ul>
|
||||
<li>app: 应用。启动应用,卸载应用,使用应用查看、编辑文件、访问网页,发送应用间广播等。</li>
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<li>如果想要在电脑而不是手机上开发Auto.js,可以使用VS Code以及相应的Auto.js插件使得在电脑上编辑的脚本能推送到手机运行,参见<a href="https://github.com/hyb1996/Auto.js-VSCode-Extension">Auto.js-VSCode-Extension</a>。</li>
|
||||
</ul>
|
||||
<p>本文档的章节大致上是以模块来分的,总体上可以分成"自动操作"类模块(控件操作、触摸模拟、按键模拟等)和其他类模块(设备、应用、界面等)。</p>
|
||||
<p>"自动操作"的部分又可以大致分为基于控件和基于坐标的操作。基于坐标的操作是传统按键精灵、触摸精灵等脚本软件采用的方式,通过屏幕坐标来点击、长按指定位置模拟操作,从而到达目的。例如<code>click(100, 200)</code>, <code>press(100, 200, 500)</code>等。这种方式在游戏类脚本中比较有可行性,结合找图找色、坐标放缩功能也能达到较好的兼容性。但是,这种方式对一般软件脚本却难以达到想要的效果,而且这种方式需要安卓7.0版本以上或者root权限才能执行。所以对于一般软件脚本(例如批量添加联系人、自动提取短信验证码等等),我们采用基于控件的模拟操作方式,结合通知事情、按键事情等达成更好的工作流。这些部分的文档参见<a href="widgets-based-automation.html">基于控件的操作</a>和<a href="coordinates-based-automation.html">基于坐标的操作</a>。</p>
|
||||
<p>"自动操作"的部分又可以大致分为基于控件和基于坐标的操作。基于坐标的操作是传统按键精灵、触摸精灵等脚本软件采用的方式,通过屏幕坐标来点击、长按指定位置模拟操作,从而到达目的。例如<code>click(100, 200)</code>, <code>press(100, 200, 500)</code>等。这种方式在游戏类脚本中比较有可行性,结合找图找色、坐标放缩功能也能达到较好的兼容性。但是,这种方式对一般软件脚本却难以达到想要的效果,而且这种方式需要root权限才能执行。所以对于一般软件脚本(例如批量添加联系人、自动提取短信验证码等等),我们采用基于控件的模拟操作方式,结合通知事情、按键事情等达成更好的工作流。这些部分的文档参见<a href="widgets-based-automation.html">基于控件的操作</a>和<a href="coordinates-based-automation.html">基于坐标的操作</a>。</p>
|
||||
<p>其他部分主要包括:</p>
|
||||
<ul>
|
||||
<li>app: 应用。启动应用,卸载应用,使用应用查看、编辑文件、访问网页,发送应用间广播等。</li>
|
||||
|
||||
7
app/src/main/assets/sample/计时器/基本读写.js
Normal file
7
app/src/main/assets/sample/计时器/基本读写.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const KEY = "key_test";
|
||||
|
||||
recorder.save(KEY);
|
||||
|
||||
sleep(1e3, '±700');
|
||||
|
||||
toastLog(`Slept for ${recorder.load(KEY)} ms`, 'l');
|
||||
10
app/src/main/assets/sample/计时器/循环监测.js
Normal file
10
app/src/main/assets/sample/计时器/循环监测.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const KEY = "wait_for_test";
|
||||
const timeout = 3; // seconds
|
||||
|
||||
toast(`${timeout} seconds counting down...`, 'l');
|
||||
|
||||
recorder.save(KEY);
|
||||
|
||||
while (recorder.isLessThan(KEY, timeout * 1e3)) ; // @EmptyLoopBody
|
||||
|
||||
toast(`Finished.\nSpent ${recorder.load(KEY) / 1e3} s.`, 'l', 'f');
|
||||
15
app/src/main/assets/sample/计时器/条件检测.js
Normal file
15
app/src/main/assets/sample/计时器/条件检测.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const KEY = "key_test";
|
||||
|
||||
recorder.save(KEY);
|
||||
|
||||
!function action() {
|
||||
sleep(1e3, '±700');
|
||||
}();
|
||||
|
||||
let et = recorder.load(KEY);
|
||||
|
||||
if (et < 1e3) {
|
||||
toastLog('Abnormal elapsed time');
|
||||
} else {
|
||||
toastLog('Normal elapsed time');
|
||||
}
|
||||
27
app/src/main/assets/sample/计时器/计算函数运行时间.js
Normal file
27
app/src/main/assets/sample/计时器/计算函数运行时间.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// Sample A - Simple time-consumed function
|
||||
|
||||
const f = function test() {
|
||||
sleep(500, '±200');
|
||||
};
|
||||
|
||||
console.log(`Function "${f.name}" spent ${recorder(f)} ms`);
|
||||
|
||||
// Sample B - Fibonacci without memoization
|
||||
|
||||
const fibonacci = (x) => x <= 2 ? 1 : fibonacci(x - 2) + fibonacci(x - 1);
|
||||
|
||||
recorder.save('fibonacci');
|
||||
|
||||
let num = 1;
|
||||
let limit = 3e3; // 3 seconds
|
||||
|
||||
while (1) {
|
||||
let et = recorder(fibonacci.bind(null, num));
|
||||
toastLog(`Fibonacci ${num} spent ${et} ms`, false, 'f');
|
||||
if (et > limit) {
|
||||
break;
|
||||
}
|
||||
num += 1;
|
||||
}
|
||||
|
||||
toastLog('Finished');
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Integer> EVENT_ACTION_RES_ID_MAP = new SparseArrayEntries<Integer>()
|
||||
.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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -32,6 +32,9 @@ import org.autojs.autojs.ui.floating.layoutinspector.LayoutHierarchyFloatyWindow
|
||||
import org.autojs.autojs.ui.log.LogActivity_;
|
||||
import org.autojs.autojs.ui.settings.SettingsActivity_;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
@@ -41,11 +44,15 @@ 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();
|
||||
|
||||
public static AutoJs getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
public synchronized static void initInstance(Application application) {
|
||||
if (instance != null) {
|
||||
return;
|
||||
@@ -59,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());
|
||||
@@ -108,11 +116,18 @@ public class AutoJs extends com.stardust.autojs.AutoJs {
|
||||
|
||||
@Override
|
||||
protected GlobalConsole createGlobalConsole() {
|
||||
DevPluginService devPluginService = DevPluginService.getInstance();
|
||||
return new GlobalConsole(getUiHandler()) {
|
||||
@Override
|
||||
public String println(int level, CharSequence charSequence) {
|
||||
String log = super.println(level, charSequence);
|
||||
new Thread(() -> DevPluginService.getInstance().print(log)).start();
|
||||
|
||||
// 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.
|
||||
printExecutor.submit(() -> devPluginService.print(log));
|
||||
|
||||
return log;
|
||||
}
|
||||
};
|
||||
@@ -122,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);
|
||||
}
|
||||
}
|
||||
@@ -145,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();
|
||||
@@ -180,4 +184,8 @@ public class AutoJs extends com.stardust.autojs.AutoJs {
|
||||
return runtime;
|
||||
}
|
||||
|
||||
private AccessibilityServiceTool getAccessibilityTool() {
|
||||
return new AccessibilityServiceTool(appContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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<String, Attributes> entries = manifest.getEntries();
|
||||
Iterator<Entry<String, Attributes>> iterator = entries.entrySet().iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Entry<String, Attributes> entry = iterator.next();
|
||||
for (Entry<String, Attributes> entry : entries.entrySet()) {
|
||||
print.print("Name: " + entry.getKey() + "\r\n");
|
||||
Iterator<Entry<Object, Object>> iter = entry.getValue().entrySet().iterator();
|
||||
|
||||
while(iter.hasNext()) {
|
||||
Entry<Object, Object> att = iter.next();
|
||||
for (Entry<Object, Object> 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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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<ScriptFile> 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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<String, String> 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<Map<String, String>> 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));
|
||||
}
|
||||
}
|
||||
@@ -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<Topic> {
|
||||
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<Topic> {
|
||||
return getTopics(CID_SCRIPTS)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<ResponseBody> 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<ResponseBody> 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<Boolean> refreshOnlineStatus() {
|
||||
PublishSubject<Boolean> 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<ResponseBody> logout() {
|
||||
return NodeBB.getInstance()
|
||||
.getXCsrfToken()
|
||||
.flatMap(mUserApi::logout)
|
||||
.doOnError(Throwable::printStackTrace)
|
||||
.doOnComplete(this::refreshOnlineStatus);
|
||||
}
|
||||
|
||||
public Observable<User> me() {
|
||||
return NodeBB.getInstance().getRetrofit()
|
||||
.create(UserApi.class)
|
||||
.me()
|
||||
.doOnNext(this::setUser)
|
||||
.doOnError(error -> setUser(null));
|
||||
}
|
||||
|
||||
|
||||
public Observable<List<Notification>> getNotifications() {
|
||||
return NodeBB.getInstance().getRetrofit()
|
||||
.create(UserApi.class)
|
||||
.getNotifications()
|
||||
.map(NotificationResponse::getNotifications);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<VersionInfo> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Config> getConfig();
|
||||
|
||||
}
|
||||
@@ -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<Category>
|
||||
|
||||
@GET("/api/topic/{tid}")
|
||||
fun getTopic(@Path("tid") pid: Long): Deferred<Topic>
|
||||
|
||||
|
||||
}
|
||||
@@ -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<VersionInfo> checkForUpdates();
|
||||
|
||||
}
|
||||
@@ -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<User> me();
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/login")
|
||||
Observable<ResponseBody> login(@HeaderMap Map<String, String> csrfToken, @Field("username") String userName, @Field("password") String password);
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("/register")
|
||||
Observable<ResponseBody> register(@HeaderMap Map<String, String> csrfToken, @Field("email") String email,
|
||||
@Field("username") String userName, @Field("password") String password, @Field("password-confirm") String repeatPassword);
|
||||
|
||||
|
||||
@POST("/logout")
|
||||
Observable<ResponseBody> logout(@HeaderMap Map<String, String> csrfToken);
|
||||
|
||||
@GET("/api/notifications")
|
||||
Observable<NotificationResponse> getNotifications();
|
||||
}
|
||||
@@ -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<String, VolatileBox<Boolean>> mDownloadStatuses = new ConcurrentHashMap<>();
|
||||
private final DownloadApi mDownloadApi;
|
||||
private final ConcurrentHashMap<String, VolatileBox<Boolean>> 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<Integer> 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<Integer>() {
|
||||
.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<Boolean> mStatus;
|
||||
private final String mUrl;
|
||||
private final String mPath;
|
||||
private final VolatileBox<Boolean> mStatus;
|
||||
private InputStream mInputStream;
|
||||
private FileOutputStream mFileOutputStream;
|
||||
private PublishSubject<Integer> mProgress;
|
||||
private final PublishSubject<Integer> 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?
|
||||
}
|
||||
|
||||
@@ -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<Download> downloads;
|
||||
public List<OldVersion> 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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class DevPluginService {
|
||||
|
||||
private volatile JsonSocketClient mJsonSocketClient;
|
||||
private volatile JsonSocketServer mJsonSocketServer;
|
||||
private volatile ServerSocket mAJServerSocket;
|
||||
private volatile ServerSocket mServerSocket;
|
||||
|
||||
public DevPluginService() {
|
||||
File cache = new File(GlobalAppContext.get().getCacheDir(), "remote_project");
|
||||
@@ -97,6 +97,11 @@ public class DevPluginService {
|
||||
return mJsonSocketServer;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ServerSocket getServerSocket() {
|
||||
return mServerSocket;
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
public Observable<JsonSocketClient> connectToRemoteServer(String host) {
|
||||
int port = Port.PC_SERVER;
|
||||
@@ -135,11 +140,11 @@ public class DevPluginService {
|
||||
.doOnNext(jsonSocketServer -> {
|
||||
try {
|
||||
mJsonSocketServer = jsonSocketServer;
|
||||
mAJServerSocket = jsonSocketServer.getServerSocket();
|
||||
if (mAJServerSocket != null) {
|
||||
mServerSocket = jsonSocketServer.getServerSocket();
|
||||
if (mServerSocket != null) {
|
||||
jsonSocketServer
|
||||
.setStateConnected()
|
||||
.setSocket(mAJServerSocket.accept())
|
||||
.setSocket(mServerSocket.accept())
|
||||
.subscribeMessage()
|
||||
.monitorMessage()
|
||||
.sayHello();
|
||||
@@ -161,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) {
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.stardust.autojs.runtime.api.Device;
|
||||
import com.stardust.util.MapBuilder;
|
||||
|
||||
import org.autojs.autojs.BuildConfig;
|
||||
import org.autojs.autojs.tool.IOTool;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
@@ -113,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);
|
||||
|
||||
@@ -129,24 +148,29 @@ abstract public class JsonSocket extends Socket {
|
||||
private void writeMap(String type, Map<String, ?> map) {
|
||||
JsonObject data = new JsonObject();
|
||||
for (Map.Entry<String, ?> 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<String, ?> 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<String, String> pair) {
|
||||
@@ -196,13 +220,12 @@ abstract public class JsonSocket extends Socket {
|
||||
|
||||
public void monitorMessage(Socket socket, JsonSocket jsonSocket) {
|
||||
new Thread(() -> {
|
||||
InputStream inputStream = null;
|
||||
InputStreamReader inputStreamReader = null;
|
||||
BufferedReader bufferedReader = null;
|
||||
try {
|
||||
inputStream = socket.getInputStream();
|
||||
inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
|
||||
bufferedReader = new BufferedReader(inputStreamReader);
|
||||
// try (AutoCloseable) { ... }
|
||||
// @Thank to Zen2H
|
||||
try (InputStream inputStream = socket.getInputStream();
|
||||
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
|
||||
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)
|
||||
) {
|
||||
final StringBuilder stringBuilder = new StringBuilder();
|
||||
String readLine;
|
||||
Log.d(TAG, "bufferedReader is reading lines...");
|
||||
@@ -216,9 +239,6 @@ abstract public class JsonSocket extends Socket {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
IOTool.close(bufferedReader);
|
||||
IOTool.close(inputStreamReader);
|
||||
IOTool.close(inputStream);
|
||||
try {
|
||||
jsonSocket.switchOff();
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -12,6 +12,8 @@ import com.google.gson.JsonObject;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.subjects.PublishSubject;
|
||||
@@ -20,6 +22,8 @@ public class JsonSocketClient extends JsonSocket {
|
||||
|
||||
private static final String TAG = JsonSocketClient.class.getSimpleName();
|
||||
|
||||
private final ExecutorService jsonSocketExecutor = Executors.newSingleThreadExecutor();
|
||||
|
||||
public static final PublishSubject<DevPluginService.State> cxnState = PublishSubject.create();
|
||||
|
||||
private final PublishSubject<JsonElement> mJsonElementPublishSubject = PublishSubject.create();
|
||||
@@ -32,14 +36,14 @@ public class JsonSocketClient extends JsonSocket {
|
||||
|
||||
// @Constructor
|
||||
public JsonSocketClient(String host, int port) {
|
||||
new Thread(() -> {
|
||||
jsonSocketExecutor.submit(() -> {
|
||||
try {
|
||||
setStateConnecting();
|
||||
mSocket = new Socket(host, port);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isSocketReady() {
|
||||
@@ -80,6 +84,7 @@ public class JsonSocketClient extends JsonSocket {
|
||||
mSocket.close();
|
||||
mSocket = null;
|
||||
}
|
||||
jsonSocketExecutor.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<AccessibilityService> 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<? extends android.accessibilityservice.AccessibilityService> 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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 <T> Observer<T> emptyObserver() {
|
||||
return new Observer<T>() {
|
||||
return new Observer<>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@ public class ThreadTool {
|
||||
try {
|
||||
//noinspection BusyWait
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InterruptedException ignore) {
|
||||
// Ignored.
|
||||
}
|
||||
}
|
||||
result.set(true);
|
||||
|
||||
@@ -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 extends View> 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<String> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -18,8 +18,8 @@ public class RxDialogs {
|
||||
public static Observable<Boolean> confirm(Context context, String text) {
|
||||
PublishSubject<Boolean> 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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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<String> 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())
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<ScriptFile> 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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<Boolean> 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++) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
import android.view.Gravity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
@@ -48,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_;
|
||||
@@ -130,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);
|
||||
}
|
||||
@@ -185,7 +192,7 @@ public class MainActivity extends BaseActivity implements OnActivityResultDelega
|
||||
stopService(new Intent(view.getContext(), FloatyService.class));
|
||||
AutoJs.getInstance().getScriptEngineService().stopAll();
|
||||
finish();
|
||||
Runtime.getRuntime().exit(0);
|
||||
Process.killProcess(Process.myPid());
|
||||
}
|
||||
|
||||
@Click(R.id.restart)
|
||||
@@ -199,7 +206,7 @@ public class MainActivity extends BaseActivity implements OnActivityResultDelega
|
||||
}
|
||||
Intent mainIntent = Intent.makeRestartActivityTask(componentName);
|
||||
context.startActivity(mainIntent);
|
||||
Runtime.getRuntime().exit(0);
|
||||
Process.killProcess(Process.myPid());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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<Uri> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -52,6 +49,7 @@ import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
@@ -78,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);
|
||||
@@ -105,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);
|
||||
}
|
||||
@@ -131,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);
|
||||
@@ -139,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,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();
|
||||
@@ -187,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();
|
||||
@@ -196,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();
|
||||
}
|
||||
|
||||
@@ -231,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();
|
||||
}
|
||||
@@ -240,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());
|
||||
}
|
||||
@@ -298,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")
|
||||
@@ -343,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) {
|
||||
@@ -373,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)
|
||||
@@ -386,65 +453,69 @@ 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();
|
||||
if (isChecked && isDisconnected) {
|
||||
inputRemoteHost();
|
||||
} else {
|
||||
disconnectJsonSocketClientIFN();
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleRemoteServerCxn(DrawerMenuItemViewHolder holder) throws IOException {
|
||||
JsonSocketClient jsonSocketClient = devPlugin.getJsonSocketClient();
|
||||
boolean disconnected = jsonSocketClient == null || !jsonSocketClient.isSocketReady();
|
||||
boolean checked = holder.getSwitchCompat().isChecked();
|
||||
|
||||
if (checked) {
|
||||
if (disconnected) {
|
||||
inputRemoteHost();
|
||||
}
|
||||
} else {
|
||||
if (jsonSocketClient != null) {
|
||||
jsonSocketClient.switchOff();
|
||||
private void disconnectJsonSocketClientIFN() {
|
||||
JsonSocketClient client = devPlugin.getJsonSocketClient();
|
||||
if (client != null) {
|
||||
try {
|
||||
client.switchOff();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private void toggleLocalServerCxn(DrawerMenuItemViewHolder holder) throws IOException {
|
||||
JsonSocketServer jsonSocketServer = devPlugin.getJsonSocketServer();
|
||||
boolean checked = holder.getSwitchCompat().isChecked();
|
||||
private boolean isJsonSocketClientConnected() {
|
||||
JsonSocketClient client = devPlugin.getJsonSocketClient();
|
||||
return client != null && client.isSocketReady();
|
||||
}
|
||||
|
||||
if (checked) {
|
||||
devPlugin.enableLocalServer()
|
||||
@SuppressLint("CheckResult")
|
||||
private void toggleLocalServerCxn(DrawerMenuItemViewHolder holder) {
|
||||
boolean isChecked = holder.getSwitchCompat().isChecked();
|
||||
boolean isDisconnected = !isServerSocketConnected();
|
||||
|
||||
if (isChecked && isDisconnected) {
|
||||
devPlugin
|
||||
.enableLocalServer()
|
||||
.subscribe(Observers.emptyConsumer(), this::onAJServerConnectException);
|
||||
} else {
|
||||
if (jsonSocketServer != null) {
|
||||
jsonSocketServer.switchOff();
|
||||
}
|
||||
disconnectServerSocketIFN();
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleForegroundService(DrawerMenuItemViewHolder holder) {
|
||||
boolean checked = holder.getSwitchCompat().isChecked();
|
||||
if (checked) {
|
||||
ForegroundService.start(GlobalAppContext.get());
|
||||
} else {
|
||||
ForegroundService.stop(GlobalAppContext.get());
|
||||
private boolean isServerSocketConnected() {
|
||||
ServerSocket serverSocket = devPlugin.getServerSocket();
|
||||
return serverSocket != null && !serverSocket.isClosed();
|
||||
}
|
||||
|
||||
private void disconnectServerSocketIFN() {
|
||||
ServerSocket serverSocket = devPlugin.getServerSocket();
|
||||
if (serverSocket != null) {
|
||||
try {
|
||||
serverSocket.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,93 +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());
|
||||
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<DrawerFragment> 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) {
|
||||
@@ -563,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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<String, Runnable> getAvailableLanguages(@NonNull Context context) {
|
||||
LinkedHashMap<String, Runnable> 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<String, Runnable> languagesMap = getAvailableLanguages(context);
|
||||
Set<String> languagesKey = languagesMap.keySet();
|
||||
Collection<Runnable> 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<String, Runnable> ACTION_MAP;
|
||||
@@ -98,9 +170,11 @@ public class SettingsActivity extends BaseActivity {
|
||||
super.onStart();
|
||||
ACTION_MAP = new MapBuilder<String, Runnable>()
|
||||
.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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,9 +10,11 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.PersistableBundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
@@ -65,13 +67,13 @@ public class ShortcutCreateActivity extends AppCompatActivity {
|
||||
private void showDialog() {
|
||||
View view = View.inflate(this, R.layout.shortcut_create_dialog, null);
|
||||
ButterKnife.bind(this, view);
|
||||
mUseAndroidNShortcut.setVisibility(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ?
|
||||
View.VISIBLE : View.GONE);
|
||||
mUseAndroidNShortcut.setVisibility(Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1
|
||||
? View.VISIBLE : View.GONE);
|
||||
mName.setText(mScriptFile.getSimplifiedName());
|
||||
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();
|
||||
@@ -90,7 +92,7 @@ public class ShortcutCreateActivity extends AppCompatActivity {
|
||||
|
||||
@SuppressLint("NewApi") //for fool android studio
|
||||
private void createShortcut() {
|
||||
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 && mUseAndroidNShortcut.isChecked())
|
||||
if ((Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1 && mUseAndroidNShortcut.isChecked())
|
||||
|| Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
createShortcutByShortcutManager();
|
||||
return;
|
||||
@@ -132,7 +134,7 @@ public class ShortcutCreateActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@SuppressLint({"CheckResult", "MissingSuperCall"})
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode != RESULT_OK) {
|
||||
@@ -149,7 +151,7 @@ public class ShortcutCreateActivity extends AppCompatActivity {
|
||||
return;
|
||||
}
|
||||
Uri uri = data.getData();
|
||||
if(uri == null){
|
||||
if (uri == null) {
|
||||
return;
|
||||
}
|
||||
Observable.fromCallable(() -> BitmapFactory.decodeStream(getContentResolver().openInputStream(uri)))
|
||||
@@ -158,9 +160,7 @@ public class ShortcutCreateActivity extends AppCompatActivity {
|
||||
.subscribe((bitmap -> {
|
||||
mIcon.setImageBitmap(bitmap);
|
||||
mIsDefaultIcon = false;
|
||||
}), error -> {
|
||||
Log.e(LOG_TAG, "decode stream", error);
|
||||
});
|
||||
}), error -> Log.e(LOG_TAG, "decode stream", error));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> 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<String> {
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
BIN
app/src/main/jniLibs/arm64-v8a/libc++_shared.so
Normal file
BIN
app/src/main/jniLibs/arm64-v8a/libc++_shared.so
Normal file
Binary file not shown.
BIN
app/src/main/jniLibs/armeabi-v7a/libc++_shared.so
Normal file
BIN
app/src/main/jniLibs/armeabi-v7a/libc++_shared.so
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
app/src/main/jniLibs/x86/libc++_shared.so
Normal file
BIN
app/src/main/jniLibs/x86/libc++_shared.so
Normal file
Binary file not shown.
BIN
app/src/main/jniLibs/x86_64/libc++_shared.so
Normal file
BIN
app/src/main/jniLibs/x86_64/libc++_shared.so
Normal file
Binary file not shown.
@@ -56,7 +56,7 @@
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/github"
|
||||
android:text="@string/text_app_source_code"
|
||||
android:textColor="@android:color/secondary_text_light"
|
||||
android:textSize="16sp" />
|
||||
</LinearLayout>
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/app_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<com.stardust.theme.widget.ThemeColorToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:theme="@style/ToolBarStyle"
|
||||
android:title="@string/text_login"
|
||||
app:layout_scrollFlags="scroll|enterAlways"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay"/>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:hint="@string/text_username">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatEditText
|
||||
android:id="@+id/username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:textColor="?android:textColorPrimary"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:hint="@string/text_password">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatEditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPassword"
|
||||
android:textColor="?android:textColorPrimary"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/forgot_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:orientation="horizontal"
|
||||
android:padding="4dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/text_forgot_password"
|
||||
android:textColor="#929397"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/text_reset_password"
|
||||
android:textColor="@color/colorAccent"
|
||||
android:textSize="12sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@color/colorPrimary"
|
||||
android:foreground="?selectableItemBackground"
|
||||
android:gravity="center"
|
||||
android:padding="12dp"
|
||||
android:text="@string/text_login"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="15sp"/>
|
||||
|
||||
</FrameLayout>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user