├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── values-night │ │ │ │ └── themes.xml │ │ │ ├── layout │ │ │ │ └── activity_main.xml │ │ │ └── drawable │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── ic_launcher-playstore.png │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── cc │ │ │ └── aoeiuv020 │ │ │ └── iamnotdisabled │ │ │ └── MainActivity.kt │ ├── test │ │ └── java │ │ │ └── cc │ │ │ └── aoeiuv020 │ │ │ └── iamnotdisabled │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── cc │ │ └── aoeiuv020 │ │ └── iamnotdisabled │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── hook ├── .gitignore ├── src │ ├── main │ │ ├── assets │ │ │ └── xposed_init │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ ├── strings-notran.xml │ │ │ │ └── colors.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ └── drawable │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── ic_launcher-playstore.png │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── cc │ │ │ └── aoeiuv020 │ │ │ └── iamnotdisabled │ │ │ └── hook │ │ │ └── MainHook.java │ ├── test │ │ └── java │ │ │ └── cc │ │ │ └── aoeiuv020 │ │ │ └── iamnotdisabled │ │ │ └── hook │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── cc │ │ └── aoeiuv020 │ │ └── iamnotdisabled │ │ └── hook │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── readme └── chrome+litiaotiao.jpg ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── signing.gradle ├── latest-version.sh ├── latest-changelog.sh ├── template-update.md ├── settings.gradle ├── ChangeLog.txt ├── LICENSE ├── gradle.properties ├── README.md ├── .gitignore ├── gradlew.bat ├── signing.txt ├── gradlew └── .github └── workflows └── main.yml /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /hook/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /hook/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | cc.aoeiuv020.iamnotdisabled.hook.MainHook -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 我残? 3 | -------------------------------------------------------------------------------- /hook/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 非残! 3 | -------------------------------------------------------------------------------- /readme/chrome+litiaotiao.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/readme/chrome+litiaotiao.jpg -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /latest-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cur="$(dirname $0)" 3 | cd $cur 4 | cat ChangeLog.txt |head -2 |tail -1 |sed 's/\(.*\):/\1/' 5 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /hook/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/hook/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AoEiuV020/IAmNotDisabled/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3DDC84 4 | -------------------------------------------------------------------------------- /hook/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #DC3D3D 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Jan 06 01:57:28 CST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /latest-changelog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 打印最新版本的更新日志, 3 | # 关键是以markdown的格式加粗第一行, 4 | # 可选参数一个,指定版本打印更新日志, 5 | set -e 6 | cd $(dirname $0) 7 | versionName=$1 8 | versionName=${versionName:=$(./latest-version.sh)} 9 | cat ./ChangeLog.txt |sed -n "/$versionName:/,\$p" |sed '/^$/,$d;1d' |sed '1s/[,,]$//;1s/^\(.*\)$/### \1\n/' 10 | -------------------------------------------------------------------------------- /hook/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /hook/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /template-update.md: -------------------------------------------------------------------------------- 1 | *[${BUILD_NAME}]更新,${VERSION_PREFIX}${BUILD_VERSION}* 2 | [CI](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}) [反馈](https://github.com/${GITHUB_REPOSITORY}/issues) 3 | 4 | *下载地址:* 5 | [GITHUB](https://github.com/${GITHUB_REPOSITORY}/releases/tag/${BUILD_VERSION}) 6 | 7 | *更新日志:* 8 | ${TG_CHANGELOG} 9 | -------------------------------------------------------------------------------- /hook/src/main/res/values/strings-notran.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | cc.aoeiuv020.iamnotdisabled 5 | com.android.chrome 6 | com.google.android.inputmethod.latin 7 | 8 | 9 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | dependencyResolutionManagement { 2 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 3 | repositories { 4 | google() 5 | mavenCentral() 6 | //noinspection JcenterRepositoryObsolete,GrDeprecatedAPIUsage 7 | jcenter() // Warning: this repository is going to shut down soon 8 | } 9 | } 10 | rootProject.name = "IAmNotDisabled" 11 | include ':app' 12 | include ':hook' 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /hook/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/test/java/cc/aoeiuv020/iamnotdisabled/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package cc.aoeiuv020.iamnotdisabled 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } -------------------------------------------------------------------------------- /hook/src/test/java/cc/aoeiuv020/iamnotdisabled/hook/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package cc.aoeiuv020.iamnotdisabled.hook 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } -------------------------------------------------------------------------------- /ChangeLog.txt: -------------------------------------------------------------------------------- 1 | 更新日志: 2 | 6.6: 3 | 兼容性优化,适配新版LSPosed的堆栈变化, 4 | 5 | 6.5: 6 | 性能优化,减少一个无用循环, 7 | 8 | 6.4: 9 | 优化卡顿问题, 10 | 11 | 6.3: 12 | 修复chrome隐瞒无障碍同时使用读屏软件, 13 | 14 | 6.2: 15 | 隐瞒无障碍的应用正常使用读屏软件, 16 | 17 | 6.1: 18 | 扩大针对处理的范围, 19 | 20 | 6.0: 21 | 发布到xposed仓库, 22 | 23 | 5.0: 24 | 改显示的版本号, 25 | 26 | 4.0: 27 | 优化hook安装包体积, 28 | 直接删除兼容低版本用的图标, 29 | 相应的最低版本提升到26, 30 | 31 | 3.0: 32 | 改低最低版本要求到安卓5, 33 | 没测试,只是想留一个支持低版本的包, 34 | 35 | 2.0: 36 | 优化hook安装包体积, 37 | 放弃kotlin,改用java, 38 | 39 | 1.0: 40 | 配置签名, -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/cc/aoeiuv020/iamnotdisabled/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package cc.aoeiuv020.iamnotdisabled 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("cc.aoeiuv020.iamnotdisabled", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /hook/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /hook/src/androidTest/java/cc/aoeiuv020/iamnotdisabled/hook/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package cc.aoeiuv020.iamnotdisabled.hook 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("cc.aoeiuv020.iamnotdisabled.hook", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 25 | 26 | -------------------------------------------------------------------------------- /hook/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 15 | 18 | 21 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 啊o额iu鱼 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /hook/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | } 4 | 5 | android { 6 | compileSdk 32 7 | 8 | defaultConfig { 9 | applicationId "cc.aoeiuv020.iamnotdisabled.hook" 10 | minSdk 26 11 | targetSdk 32 12 | versionCode rootProject.ext.versionCode 13 | versionName rootProject.ext.versionName 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | compileOptions { 25 | sourceCompatibility JavaVersion.VERSION_1_8 26 | targetCompatibility JavaVersion.VERSION_1_8 27 | } 28 | } 29 | 30 | dependencies { 31 | compileOnly 'de.robv.android.xposed:api:82' 32 | 33 | //noinspection GradleDynamicVersion 34 | testImplementation 'junit:junit:4.+' 35 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' 36 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 37 | } 38 | 39 | apply from: rootProject.file('gradle/signing.gradle') 40 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IAmNotDisabled 2 | 使用xposed hook假装自己没有使用无障碍服务, 3 | [![img](https://img.shields.io/badge/%E6%9B%B4%E6%96%B0%E6%97%A5%E5%BF%97-ChangeLog-brightgreen)](./ChangeLog.txt) 4 | [![CI](https://github.com/AoEiuV020/IAmNotDisabled/actions/workflows/main.yml/badge.svg)](https://github.com/AoEiuV020/IAmNotDisabled/actions/workflows/main.yml) 5 | [![img](https://img.shields.io/github/v/release/AoEiuV020/IAmNotDisabled.svg)](https://github.com/AoEiuV020/IAmNotDisabled/releases) 6 | 7 | ## !!!本项目并非反反作弊用途,只针对善意的无障碍检测,不保证对反作弊检测有效!!! 8 | 9 | 起因:[https://www.v2ex.com/t/826317](https://www.v2ex.com/t/826317) 10 | 使用无障碍服务会被部分app特殊对待, 11 | 然而有可能使用了无障碍只是为了便利,并不希望被优待, 12 | 于是有了本项目, 13 | 针对chrome,假装自己没有使用无障碍服务,才可以使用新版的各种标签相关功能和动画, 14 | 15 | ### 项目包含两个应用模块 16 | * app 我残? 用于测试hook效果,打开时检测到无障碍服务就会提示, 17 | * hook 非残! xposed模块通过hook负责查询无障碍的系统服务伪装成没有启用无障碍服务, 18 | 19 | ### 模块使用需求 20 | * 安卓8以上,不为啥,只是觉得没必要支持旧版, 21 | * [Riru-LSPosed](https://github.com/LSPosed/LSPosed) 1.6.5以上,不为啥,只是因为我开发时在用的就是这个, 22 | * 理论上对任何目标应用都有效, 23 | 24 | ### 模块使用方法 25 | 1. 手机解锁, 26 | 1. 刷入Magisk, 27 | 1. 刷入Magisk模块Riru和Riri-LSPosed, 28 | 1. 安装“[非残!](https://github.com/AoEiuV020/IAmNotDisabled/releases)”,IAmNotDisabled-hook.apk, 29 | 1. 在LSPosed中激活非残并勾选需要隐瞒无障碍服务应用,比如chrome, 30 | 1. 重启目标应用生效, 31 | 32 | 下图,开启“李跳跳”的同时使用chrome的新版标签, 33 | ![img](readme/chrome+litiaotiao.jpg) 34 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | } 5 | 6 | android { 7 | compileSdk 32 8 | 9 | defaultConfig { 10 | applicationId "cc.aoeiuv020.iamnotdisabled" 11 | minSdk 26 12 | targetSdk 32 13 | versionCode rootProject.ext.versionCode 14 | versionName rootProject.ext.versionName 15 | 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | kotlinOptions { 30 | jvmTarget = '1.8' 31 | } 32 | } 33 | 34 | dependencies { 35 | 36 | implementation 'androidx.core:core-ktx:1.7.0' 37 | implementation 'androidx.appcompat:appcompat:1.4.0' 38 | implementation 'com.google.android.material:material:1.4.0' 39 | implementation 'androidx.constraintlayout:constraintlayout:2.1.2' 40 | //noinspection GradleDynamicVersion 41 | testImplementation 'junit:junit:4.+' 42 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' 43 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 44 | } 45 | 46 | apply from: rootProject.file('gradle/signing.gradle') 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.aar 4 | *.ap_ 5 | *.aab 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | # Uncomment the following line in case you need and you don't have the release build type files in your app 18 | # release/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea/ 42 | 43 | # Keystore files 44 | # Uncomment the following lines if you do not want to check your keystore files in. 45 | *.jks 46 | *.jks.txt 47 | #*.keystore 48 | 49 | # External native build folder generated in Android Studio 2.2 and later 50 | .externalNativeBuild 51 | .cxx/ 52 | 53 | # Google Services (e.g. APIs or Firebase) 54 | google-services.json 55 | 56 | # Freeline 57 | freeline.py 58 | freeline/ 59 | freeline_project_description.json 60 | 61 | # fastlane 62 | fastlane/report.xml 63 | fastlane/Preview.html 64 | fastlane/screenshots 65 | fastlane/test_output 66 | fastlane/readme.md 67 | 68 | # Version control 69 | vcs.xml 70 | 71 | # lint 72 | lint/intermediates/ 73 | lint/generated/ 74 | lint/outputs/ 75 | lint/tmp/ 76 | # lint/reports/ 77 | 78 | ### 79 | /release 80 | /signing.properties 81 | /publish.properties 82 | class_files.txt 83 | .attach_pid* 84 | *-mapping.txt 85 | *.apk.idsig 86 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 12 | 13 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /hook/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 12 | 13 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /gradle/signing.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | android { 3 | 4 | // 签名信息从signing.properties中获取, 5 | // debug和release使用相同签名,以便用debug包覆盖release包从而调试, 6 | // 如果没有,就会使用默认debug签名, 7 | def signingFile = rootProject.file('signing.properties') 8 | String sha1 = null 9 | if (signingFile.exists()) { 10 | def input = signingFile.newInputStream() 11 | def p = new Properties() 12 | p.load(input) 13 | input.close() 14 | // 签名文件存在才配置签名, 15 | def jks = rootProject.file(p['storeFile']) 16 | if (jks.exists()) { 17 | signingConfigs { 18 | config { 19 | keyAlias p['keyAlias'] 20 | keyPassword p['keyPassword'] 21 | storeFile jks 22 | storePassword p['storePassword'] 23 | v1SigningEnabled true 24 | v2SigningEnabled true 25 | } 26 | } 27 | buildTypes { 28 | debug.signingConfig signingConfigs.config 29 | release.signingConfig signingConfigs.config 30 | } 31 | def signingConfig = signingConfigs.config 32 | if (signingConfig != null) { 33 | //noinspection UnnecessaryQualifiedReference 34 | def keyStore = java.security.KeyStore.getInstance( 35 | signingConfig.getStoreType() != null ? 36 | signingConfig.getStoreType() : KeyStore.getDefaultType()) 37 | FileInputStream fis = new FileInputStream(signingConfig.getStoreFile()) 38 | keyStore.load(fis, signingConfig.getStorePassword().toCharArray()) 39 | fis.close() 40 | char[] keyPassword = signingConfig.getKeyPassword().toCharArray() 41 | //noinspection UnnecessaryQualifiedReference 42 | def entry = keyStore.getEntry( 43 | signingConfig.getKeyAlias(), 44 | new java.security.KeyStore.PasswordProtection(keyPassword)) 45 | if (entry != null) { 46 | //noinspection UnnecessaryQualifiedReference 47 | def digest = java.security.MessageDigest.getInstance("SHA-1") 48 | sha1 = digest.digest(entry.getCertificate().encoded).encodeHex().toString() 49 | } 50 | } 51 | } 52 | } 53 | if (sha1 == null) { 54 | defaultConfig.buildConfigField('String', "SIGNATURE", 'null') 55 | } else { 56 | defaultConfig.buildConfigField('String', "SIGNATURE", '"' + sha1 + '"') 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /signing.txt: -------------------------------------------------------------------------------- 1 | Alias name: IAmNotDisabled 2 | Creation date: 2022年1月6日 3 | Entry type: PrivateKeyEntry 4 | Certificate chain length: 1 5 | Certificate[1]: 6 | Owner: CN=AoEiuV020, OU=IAmNotDisabled, O=AoEiuV020, L=China, ST=China, C=CN 7 | Issuer: CN=AoEiuV020, OU=IAmNotDisabled, O=AoEiuV020, L=China, ST=China, C=CN 8 | Serial number: 7b6f250d 9 | Valid from: Thu Jan 06 02:58:02 CST 2022 until: Mon May 24 02:58:02 CST 2049 10 | Certificate fingerprints: 11 | SHA1: 66:ED:5E:E1:AC:D5:4E:F4:50:1C:3C:78:A3:7D:71:59:51:DA:21:7E 12 | SHA256: 20:10:77:72:62:57:A8:81:00:50:0A:3D:B5:25:BC:EC:10:69:10:5B:F9:02:C3:F1:F6:F6:9E:C6:26:10:FB:61 13 | Signature algorithm name: SHA256withRSA 14 | Subject Public Key Algorithm: 2048-bit RSA key 15 | Version: 3 16 | 17 | Extensions: 18 | 19 | #1: ObjectId: 2.5.29.14 Criticality=false 20 | SubjectKeyIdentifier [ 21 | KeyIdentifier [ 22 | 0000: 05 CD E3 EB DD 35 D2 58 E7 E4 FE 2A 37 3A AC F3 .....5.X...*7:.. 23 | 0010: 5F 7D E8 1A _... 24 | ] 25 | ] 26 | 27 | 28 | > Task :hook:signingReport 29 | Variant: debug 30 | Config: config 31 | Store: /mnt/wext/code/git/IAmNotDisabled/IAmNotDisabled.jks 32 | Alias: IAmNotDisabled 33 | MD5: 44:43:D3:3D:34:46:4C:1B:16:60:91:87:4A:7F:1E:54 34 | SHA1: 66:ED:5E:E1:AC:D5:4E:F4:50:1C:3C:78:A3:7D:71:59:51:DA:21:7E 35 | SHA-256: 20:10:77:72:62:57:A8:81:00:50:0A:3D:B5:25:BC:EC:10:69:10:5B:F9:02:C3:F1:F6:F6:9E:C6:26:10:FB:61 36 | Valid until: Monday, May 24, 2049 37 | ---------- 38 | Variant: release 39 | Config: config 40 | Store: /mnt/wext/code/git/IAmNotDisabled/IAmNotDisabled.jks 41 | Alias: IAmNotDisabled 42 | MD5: 44:43:D3:3D:34:46:4C:1B:16:60:91:87:4A:7F:1E:54 43 | SHA1: 66:ED:5E:E1:AC:D5:4E:F4:50:1C:3C:78:A3:7D:71:59:51:DA:21:7E 44 | SHA-256: 20:10:77:72:62:57:A8:81:00:50:0A:3D:B5:25:BC:EC:10:69:10:5B:F9:02:C3:F1:F6:F6:9E:C6:26:10:FB:61 45 | Valid until: Monday, May 24, 2049 46 | ---------- 47 | Variant: debugAndroidTest 48 | Config: config 49 | Store: /mnt/wext/code/git/IAmNotDisabled/IAmNotDisabled.jks 50 | Alias: IAmNotDisabled 51 | MD5: 44:43:D3:3D:34:46:4C:1B:16:60:91:87:4A:7F:1E:54 52 | SHA1: 66:ED:5E:E1:AC:D5:4E:F4:50:1C:3C:78:A3:7D:71:59:51:DA:21:7E 53 | SHA-256: 20:10:77:72:62:57:A8:81:00:50:0A:3D:B5:25:BC:EC:10:69:10:5B:F9:02:C3:F1:F6:F6:9E:C6:26:10:FB:61 54 | Valid until: Monday, May 24, 2049 55 | ---------- 56 | 57 | > Task :app:signingReport 58 | Variant: debug 59 | Config: config 60 | Store: /mnt/wext/code/git/IAmNotDisabled/IAmNotDisabled.jks 61 | Alias: IAmNotDisabled 62 | MD5: 44:43:D3:3D:34:46:4C:1B:16:60:91:87:4A:7F:1E:54 63 | SHA1: 66:ED:5E:E1:AC:D5:4E:F4:50:1C:3C:78:A3:7D:71:59:51:DA:21:7E 64 | SHA-256: 20:10:77:72:62:57:A8:81:00:50:0A:3D:B5:25:BC:EC:10:69:10:5B:F9:02:C3:F1:F6:F6:9E:C6:26:10:FB:61 65 | Valid until: Monday, May 24, 2049 66 | ---------- 67 | Variant: release 68 | Config: config 69 | Store: /mnt/wext/code/git/IAmNotDisabled/IAmNotDisabled.jks 70 | Alias: IAmNotDisabled 71 | MD5: 44:43:D3:3D:34:46:4C:1B:16:60:91:87:4A:7F:1E:54 72 | SHA1: 66:ED:5E:E1:AC:D5:4E:F4:50:1C:3C:78:A3:7D:71:59:51:DA:21:7E 73 | SHA-256: 20:10:77:72:62:57:A8:81:00:50:0A:3D:B5:25:BC:EC:10:69:10:5B:F9:02:C3:F1:F6:F6:9E:C6:26:10:FB:61 74 | Valid until: Monday, May 24, 2049 75 | ---------- 76 | Variant: debugAndroidTest 77 | Config: config 78 | Store: /mnt/wext/code/git/IAmNotDisabled/IAmNotDisabled.jks 79 | Alias: IAmNotDisabled 80 | MD5: 44:43:D3:3D:34:46:4C:1B:16:60:91:87:4A:7F:1E:54 81 | SHA1: 66:ED:5E:E1:AC:D5:4E:F4:50:1C:3C:78:A3:7D:71:59:51:DA:21:7E 82 | SHA-256: 20:10:77:72:62:57:A8:81:00:50:0A:3D:B5:25:BC:EC:10:69:10:5B:F9:02:C3:F1:F6:F6:9E:C6:26:10:FB:61 83 | Valid until: Monday, May 24, 2049 84 | ---------- 85 | 86 | Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0. 87 | Use '--warning-mode all' to show the individual deprecation warnings. 88 | See https://docs.gradle.org/7.0.2/userguide/command_line_interface.html#sec:command_line_warnings 89 | 90 | BUILD SUCCESSFUL in 973ms 91 | 2 actionable tasks: 2 executed 92 | -------------------------------------------------------------------------------- /app/src/main/java/cc/aoeiuv020/iamnotdisabled/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package cc.aoeiuv020.iamnotdisabled 2 | 3 | import android.accessibilityservice.AccessibilityServiceInfo 4 | import android.annotation.SuppressLint 5 | import android.os.Bundle 6 | import android.os.Handler 7 | import android.os.Looper 8 | import android.provider.Settings 9 | import android.view.View 10 | import android.view.accessibility.AccessibilityManager 11 | import android.widget.TextView 12 | import androidx.appcompat.app.AppCompatActivity 13 | import androidx.core.content.ContextCompat 14 | import androidx.lifecycle.DefaultLifecycleObserver 15 | import androidx.lifecycle.LifecycleOwner 16 | 17 | class MainActivity : AppCompatActivity() { 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(R.layout.activity_main) 21 | 22 | findViewById(R.id.tvResult).setOnClickListener { 23 | checkDisabled() 24 | } 25 | checkDisabled() 26 | addListener() 27 | } 28 | 29 | private fun addListener() { 30 | val accessibilityManager = 31 | ContextCompat.getSystemService(this, AccessibilityManager::class.java) 32 | ?: error("unreachable") 33 | lifecycle.addObserver(object : DefaultLifecycleObserver { 34 | private val handler = Handler(Looper.getMainLooper()) 35 | private val listener = AccessibilityManager.AccessibilityStateChangeListener { 36 | updateDisabled(listOf("监听到无障碍服务 " + getEnabledString(it))) 37 | } 38 | private val touchExplorationListener = 39 | AccessibilityManager.TouchExplorationStateChangeListener { 40 | updateDisabled(listOf("监听到读屏服务 " + getEnabledString(it))) 41 | } 42 | 43 | override fun onCreate(owner: LifecycleOwner) { 44 | accessibilityManager.addAccessibilityStateChangeListener(listener) 45 | accessibilityManager.addAccessibilityStateChangeListener(listener, handler) 46 | accessibilityManager.addTouchExplorationStateChangeListener(touchExplorationListener) 47 | accessibilityManager.addTouchExplorationStateChangeListener( 48 | touchExplorationListener, 49 | handler 50 | ) 51 | } 52 | 53 | override fun onDestroy(owner: LifecycleOwner) { 54 | accessibilityManager.removeAccessibilityStateChangeListener(listener) 55 | accessibilityManager.removeTouchExplorationStateChangeListener(touchExplorationListener) 56 | } 57 | }) 58 | } 59 | 60 | private fun getEnabledString(enabled: Boolean) = if (enabled) "启用" else "禁用" 61 | 62 | private fun checkDisabled() { 63 | val serviceList = getFromAccessibilityManager() + getFromSettingsSecure() 64 | updateDisabled(serviceList) 65 | } 66 | 67 | @SuppressLint("SetTextI18n") 68 | private fun updateDisabled( 69 | serviceList: List 70 | ) { 71 | val tvResult: TextView = findViewById(R.id.tvResult) 72 | val tvReason: TextView = findViewById(R.id.tvReason) 73 | if (serviceList.isNotEmpty()) { 74 | tvResult.text = "你是残疾人!" 75 | tvReason.text = "因为:\n" + serviceList.joinToString("\n") 76 | } else { 77 | tvResult.text = "你很健康" 78 | tvReason.text = "" 79 | } 80 | } 81 | 82 | private fun getFromAccessibilityManager(): List { 83 | val accessibilityManager = 84 | ContextCompat.getSystemService(this, AccessibilityManager::class.java) 85 | ?: error("unreachable") 86 | val serviceList: List = 87 | accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK) 88 | ?: emptyList() 89 | val nameList = serviceList.map { 90 | packageManager.getApplicationLabel(it.resolveInfo.serviceInfo.applicationInfo) 91 | .toString() 92 | }.toMutableList() 93 | if (accessibilityManager.isEnabled) { 94 | nameList.add("AccessibilityManager.isEnabled") 95 | } 96 | if (accessibilityManager.isTouchExplorationEnabled) { 97 | nameList.add("AccessibilityManager.isTouchExplorationEnabled") 98 | } 99 | return nameList 100 | } 101 | 102 | private fun getFromSettingsSecure(): List { 103 | val settingValue = Settings.Secure.getString( 104 | contentResolver, 105 | Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES 106 | ) 107 | val nameList = if (settingValue.isEmpty()) { 108 | emptyList() 109 | } else { 110 | settingValue.split(':') 111 | }.toMutableList() 112 | val enabled = Settings.Secure.getInt(contentResolver, Settings.Secure.ACCESSIBILITY_ENABLED) 113 | if (enabled != 0) { 114 | nameList.add("ACCESSIBILITY_ENABLED == $enabled") 115 | } 116 | return nameList 117 | } 118 | } -------------------------------------------------------------------------------- /hook/src/main/java/cc/aoeiuv020/iamnotdisabled/hook/MainHook.java: -------------------------------------------------------------------------------- 1 | package cc.aoeiuv020.iamnotdisabled.hook; 2 | 3 | import android.content.ContentResolver; 4 | import android.os.Handler; 5 | import android.provider.Settings; 6 | import android.view.accessibility.AccessibilityManager; 7 | 8 | import java.util.Collections; 9 | 10 | import de.robv.android.xposed.IXposedHookLoadPackage; 11 | import de.robv.android.xposed.IXposedHookZygoteInit; 12 | import de.robv.android.xposed.XC_MethodHook; 13 | import de.robv.android.xposed.XC_MethodReplacement; 14 | import de.robv.android.xposed.XposedBridge; 15 | import de.robv.android.xposed.XposedHelpers; 16 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 17 | 18 | /** 19 | * Created by AoEiuV020 on 2022.01.06-03:25:32. 20 | */ 21 | @SuppressWarnings("RedundantThrows") 22 | public class MainHook implements IXposedHookLoadPackage, IXposedHookZygoteInit { 23 | @Override 24 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { 25 | XposedBridge.log("handleLoadPackage: " + lpparam.processName); 26 | XposedHelpers.findAndHookMethod("android.provider.Settings$Secure", lpparam.classLoader, "getString", ContentResolver.class, String.class, new XC_MethodHook() { 27 | protected void beforeHookedMethod(MethodHookParam methodHookParam2) throws Throwable { 28 | if (Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(methodHookParam2.args[1])) { 29 | methodHookParam2.setResult(""); 30 | } 31 | } 32 | }); 33 | XposedHelpers.findAndHookMethod("android.provider.Settings$Secure", lpparam.classLoader, "getInt", ContentResolver.class, String.class, new XC_MethodHook() { 34 | protected void beforeHookedMethod(MethodHookParam methodHookParam2) throws Throwable { 35 | if (Settings.Secure.ACCESSIBILITY_ENABLED.equals(methodHookParam2.args[1])) { 36 | methodHookParam2.setResult(0); 37 | } 38 | } 39 | }); 40 | } 41 | 42 | private boolean doNotHack(Throwable throwable) { 43 | if (throwable.getStackTrace().length >= 3) { 44 | StackTraceElement stackTraceElement = throwable.getStackTrace()[3]; 45 | if (stackTraceElement.getClassName().startsWith("LSPHooker_")) { 46 | stackTraceElement = throwable.getStackTrace()[4]; 47 | } 48 | return stackTraceElement.getClassName().startsWith("android.") 49 | || stackTraceElement.getClassName().startsWith("androidx.") 50 | || stackTraceElement.getClassName().startsWith("com.android.") 51 | || stackTraceElement.getClassName().startsWith("org.chromium.content.browser."); 52 | } 53 | return false; 54 | } 55 | 56 | @Override 57 | public void initZygote(StartupParam startupParam) throws Throwable { 58 | XposedBridge.log("initZygote: " + startupParam.modulePath); 59 | XposedHelpers.findAndHookMethod( 60 | "android.view.accessibility.AccessibilityManager", 61 | null, 62 | "getEnabledAccessibilityServiceList", 63 | int.class, 64 | XC_MethodReplacement.returnConstant(Collections.emptyList()) 65 | ); 66 | XposedHelpers.findAndHookMethod( 67 | "android.view.accessibility.AccessibilityManager", 68 | null, 69 | "isEnabled", 70 | new XC_MethodHook() { 71 | @Override 72 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 73 | Throwable throwable = new Throwable(); 74 | if (doNotHack(throwable)) return; 75 | param.setResult(false); 76 | } 77 | } 78 | ); 79 | XposedHelpers.findAndHookMethod( 80 | "android.view.accessibility.AccessibilityManager", 81 | null, 82 | "isTouchExplorationEnabled", 83 | new XC_MethodHook() { 84 | @Override 85 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 86 | Throwable throwable = new Throwable(); 87 | if (doNotHack(throwable)) return; 88 | param.setResult(false); 89 | } 90 | } 91 | ); 92 | XposedHelpers.findAndHookMethod( 93 | "android.view.accessibility.AccessibilityManager", 94 | null, 95 | "addAccessibilityStateChangeListener", 96 | AccessibilityManager.AccessibilityStateChangeListener.class, 97 | XC_MethodReplacement.returnConstant(true) 98 | ); 99 | XposedHelpers.findAndHookMethod( 100 | "android.view.accessibility.AccessibilityManager", 101 | null, 102 | "addAccessibilityStateChangeListener", 103 | AccessibilityManager.AccessibilityStateChangeListener.class, 104 | Handler.class, 105 | XC_MethodReplacement.returnConstant(null) 106 | ); 107 | XposedHelpers.findAndHookMethod( 108 | "android.view.accessibility.AccessibilityManager", 109 | null, 110 | "addTouchExplorationStateChangeListener", 111 | AccessibilityManager.TouchExplorationStateChangeListener.class, 112 | XC_MethodReplacement.returnConstant(true) 113 | ); 114 | XposedHelpers.findAndHookMethod( 115 | "android.view.accessibility.AccessibilityManager", 116 | null, 117 | "addTouchExplorationStateChangeListener", 118 | AccessibilityManager.TouchExplorationStateChangeListener.class, 119 | Handler.class, 120 | XC_MethodReplacement.returnConstant(null) 121 | ); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | env: 3 | TZ: Asia/Shanghai 4 | 5 | on: 6 | push: 7 | paths-ignore: 8 | - '/readme/*' 9 | - '**/README.md' 10 | - '.github/workflows/*' 11 | - '!.github/workflows/main.yml' 12 | 13 | jobs: 14 | build: 15 | 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: init custom env 21 | run: | 22 | set -a 23 | BUILD_NAME="${GITHUB_REPOSITORY#*/}" 24 | if [[ ${GITHUB_REF} == refs/tags* ]] 25 | then 26 | CREATE_RELEASE="true" 27 | BUILD_VERSION=${GITHUB_REF#refs/tags/} 28 | RELEASE_BODY=$(./latest-changelog.sh $BUILD_VERSION) 29 | if [[ -z "$RELEASE_BODY" ]] 30 | then 31 | RELEASE_BODY='### ${{ github.event.head_commit.message }}' 32 | fi 33 | TG_CHANGELOG="$RELEASE_BODY" 34 | elif [[ ${GITHUB_REF} == refs/pull* ]] 35 | then 36 | CREATE_RELEASE="false" 37 | num=${GITHUB_REF#refs/pull/} 38 | num=${num%/merge} 39 | BUILD_VERSION=pr-${num}-"$(date +'%Y%m%d%H%M%S')" 40 | else 41 | CREATE_RELEASE="true" 42 | echo PRE_RELEASE="true" >> .custom_env 43 | BUILD_VERSION="$(date +'%Y%m%d%H%M%S')" 44 | RELEASE_BODY=$(echo '${{ toJson(github.event.commits) }}' |jq -r 'map("### "+.message)|join("\n\n------\n")') 45 | TG_CHANGELOG=$(echo "$RELEASE_BODY"|sed -n "s/### \(.*\)/\1/p" |sed -n '{;=;p}' | sed "N;s/\n/. /g") 46 | VERSION_PREFIX='内测版-' 47 | fi 48 | BUILD_NAME_WITH_VERSION="$BUILD_NAME-$BUILD_VERSION" 49 | echo BUILD_NAME="$BUILD_NAME" >> .custom_env 50 | echo BUILD_VERSION="$BUILD_VERSION" >> .custom_env 51 | echo BUILD_NAME_WITH_VERSION="$BUILD_NAME_WITH_VERSION" >> .custom_env 52 | echo CREATE_RELEASE="$CREATE_RELEASE" >> .custom_env 53 | if test -n "$RELEASE_BODY" 54 | then 55 | echo 'RELEASE_BODY<> .custom_env 56 | echo "$RELEASE_BODY" >> .custom_env 57 | echo 'EOF' >> .custom_env 58 | echo 'UPDATE_BODY<> .custom_env 59 | envsubst < template-update.md >> .custom_env 60 | echo >> .custom_env 61 | echo 'EOF' >> .custom_env 62 | fi 63 | if [[ "$CREATE_RELEASE" == "true" && -n "${{ secrets.XPOSED_UPLOAD_TOKEN }}" ]] 64 | then 65 | echo CREATE_XPOSED_RELEASE="true" >> .custom_env 66 | fi 67 | if [[ "$CREATE_RELEASE" == "true" && -n "${{ secrets.TELEGRAM_TO }}" && -n "${{ secrets.TELEGRAM_TOKEN }}" ]] 68 | then 69 | echo SEND_TELEGRAM="true" >> .custom_env 70 | fi 71 | cat .custom_env 72 | cat .custom_env >> $GITHUB_ENV 73 | - name: set up JDK 1.11 74 | uses: actions/setup-java@v1 75 | with: 76 | java-version: 1.11 77 | - name: Build with Gradle 78 | run: | 79 | ./gradlew :app:assembleRelease 80 | ./gradlew :hook:assembleRelease 81 | - uses: AoEiuV020/sign-android-release@v2 82 | name: Sign app APK 83 | env: 84 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }} 85 | if: ${{ env.SIGNING_KEY != '' }} 86 | with: 87 | releaseDirectory: ./app/build/outputs/apk/release 88 | signingKeyBase64: ${{ secrets.SIGNING_KEY }} 89 | alias: ${{ secrets.ALIAS }} 90 | keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} 91 | keyPassword: ${{ secrets.KEY_PASSWORD }} 92 | - uses: AoEiuV020/sign-android-release@v2 93 | name: Sign hook APK 94 | env: 95 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }} 96 | if: ${{ env.SIGNING_KEY != '' }} 97 | with: 98 | releaseDirectory: ./hook/build/outputs/apk/release 99 | signingKeyBase64: ${{ secrets.SIGNING_KEY }} 100 | alias: ${{ secrets.ALIAS }} 101 | keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} 102 | keyPassword: ${{ secrets.KEY_PASSWORD }} 103 | - name: Build with Gradle 104 | run: | 105 | find ./app/build/outputs -name '*.apk' -exec mv {} $BUILD_NAME_WITH_VERSION-app.apk \; 106 | find ./hook/build/outputs -name '*.apk' -exec mv {} $BUILD_NAME_WITH_VERSION-hook.apk \; 107 | - name: Upload APK 108 | uses: actions/upload-artifact@master 109 | with: 110 | name: build 111 | path: ${{ env.BUILD_NAME_WITH_VERSION }}*.apk 112 | - name: create release 113 | if: ${{ env.CREATE_RELEASE == 'true' }} 114 | id: create_release 115 | uses: actions/create-release@v1 116 | env: 117 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 118 | with: 119 | tag_name: ${{ env.BUILD_VERSION }} 120 | release_name: ${{ env.BUILD_VERSION }} 121 | body: ${{ env.RELEASE_BODY }} 122 | draft: true 123 | prerelease: ${{ env.PRE_RELEASE == 'true' }} 124 | - name: Upload app 125 | if: ${{ env.CREATE_RELEASE == 'true' }} 126 | uses: actions/upload-release-asset@v1 127 | env: 128 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 129 | with: 130 | upload_url: ${{ steps.create_release.outputs.upload_url }} 131 | asset_path: ${{ env.BUILD_NAME_WITH_VERSION }}-app.apk 132 | asset_name: ${{ env.BUILD_NAME_WITH_VERSION }}-app.apk 133 | asset_content_type: application/zip 134 | - name: Upload hook 135 | if: ${{ env.CREATE_RELEASE == 'true' }} 136 | uses: actions/upload-release-asset@v1 137 | env: 138 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 139 | with: 140 | upload_url: ${{ steps.create_release.outputs.upload_url }} 141 | asset_path: ${{ env.BUILD_NAME_WITH_VERSION }}-hook.apk 142 | asset_name: ${{ env.BUILD_NAME_WITH_VERSION }}-hook.apk 143 | asset_content_type: application/zip 144 | - name: public release 145 | if: ${{ env.CREATE_RELEASE == 'true' }} 146 | uses: AoEiuV020/publish-release@master 147 | env: 148 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 149 | with: 150 | release_id: ${{ steps.create_release.outputs.id }} 151 | 152 | - name: create release 153 | if: ${{ env.CREATE_XPOSED_RELEASE == 'true' }} 154 | id: xposed_create_release 155 | uses: actions/create-release@v1 156 | env: 157 | GITHUB_TOKEN: ${{ secrets.XPOSED_UPLOAD_TOKEN }} 158 | with: 159 | owner: Xposed-Modules-Repo 160 | repo: cc.aoeiuv020.iamnotdisabled.hook 161 | commitish: main 162 | tag_name: ${{ env.BUILD_VERSION }} 163 | release_name: ${{ env.BUILD_VERSION }} 164 | body: ${{ env.RELEASE_BODY }} 165 | draft: true 166 | prerelease: ${{ env.PRE_RELEASE == 'true' }} 167 | - name: Upload app 168 | if: ${{ env.CREATE_XPOSED_RELEASE == 'true' }} 169 | uses: actions/upload-release-asset@v1 170 | env: 171 | GITHUB_TOKEN: ${{ secrets.XPOSED_UPLOAD_TOKEN }} 172 | with: 173 | upload_url: ${{ steps.xposed_create_release.outputs.upload_url }} 174 | asset_path: ${{ env.BUILD_NAME_WITH_VERSION }}-app.apk 175 | asset_name: ${{ env.BUILD_NAME_WITH_VERSION }}-app.apk 176 | asset_content_type: application/zip 177 | - name: Upload hook 178 | if: ${{ env.CREATE_XPOSED_RELEASE == 'true' }} 179 | uses: actions/upload-release-asset@v1 180 | env: 181 | GITHUB_TOKEN: ${{ secrets.XPOSED_UPLOAD_TOKEN }} 182 | with: 183 | upload_url: ${{ steps.xposed_create_release.outputs.upload_url }} 184 | asset_path: ${{ env.BUILD_NAME_WITH_VERSION }}-hook.apk 185 | asset_name: ${{ env.BUILD_NAME_WITH_VERSION }}-hook.apk 186 | asset_content_type: application/zip 187 | - name: public release 188 | if: ${{ env.CREATE_XPOSED_RELEASE == 'true' }} 189 | uses: AoEiuV020/publish-release@master 190 | env: 191 | GITHUB_TOKEN: ${{ secrets.XPOSED_UPLOAD_TOKEN }} 192 | with: 193 | owner: Xposed-Modules-Repo 194 | repo: cc.aoeiuv020.iamnotdisabled.hook 195 | release_id: ${{ steps.xposed_create_release.outputs.id }} 196 | 197 | - name: Send commit to telegram 198 | if: ${{ env.SEND_TELEGRAM == 'true' }} 199 | uses: appleboy/telegram-action@master 200 | with: 201 | to: ${{ secrets.TELEGRAM_TO }} 202 | token: ${{ secrets.TELEGRAM_TOKEN }} 203 | format: markdown 204 | disable_web_page_preview: true 205 | message: ${{ env.UPDATE_BODY }} 206 | document: ${{ env.BUILD_NAME_WITH_VERSION }}-hook.apk 207 | --------------------------------------------------------------------------------