├── .gitattributes
├── .github
└── workflows
│ └── android.yml
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── xposed_init
│ ├── cpp
│ └── classhelper
│ │ ├── CMakeLists.txt
│ │ └── native-lib.cpp
│ ├── java
│ └── com
│ │ └── yifeplayte
│ │ └── wommo
│ │ ├── activity
│ │ ├── MainActivity.kt
│ │ └── pages
│ │ │ └── MainPage.kt
│ │ ├── hook
│ │ ├── MainHook.kt
│ │ ├── hooks
│ │ │ ├── BaseHook.kt
│ │ │ ├── BaseMultiHook.kt
│ │ │ ├── BasePackage.kt
│ │ │ ├── BaseSubHook.kt
│ │ │ ├── BaseSubPackage.kt
│ │ │ ├── BaseUniversalHook.kt
│ │ │ ├── multipackage
│ │ │ │ ├── ExposureRefreshForNonMIUIWidget.kt
│ │ │ │ ├── ForceSupportBarrage.kt
│ │ │ │ ├── ForceSupportSendApp.kt
│ │ │ │ └── ShowNotificationImportance.kt
│ │ │ ├── singlepackage
│ │ │ │ ├── Android.kt
│ │ │ │ ├── Barrage.kt
│ │ │ │ ├── ContentExtension.kt
│ │ │ │ ├── DownloadProvider.kt
│ │ │ │ ├── Home.kt
│ │ │ │ ├── IntentResolver.kt
│ │ │ │ ├── PackageInstaller.kt
│ │ │ │ ├── PowerKeeper.kt
│ │ │ │ ├── ScreenRecorder.kt
│ │ │ │ ├── SecurityCenter.kt
│ │ │ │ ├── Settings.kt
│ │ │ │ ├── SystemUI.kt
│ │ │ │ ├── VoiceAssist.kt
│ │ │ │ ├── android
│ │ │ │ │ ├── DisableSafeMediaVolume.kt
│ │ │ │ │ ├── ForceDarkModeForAllApps.kt
│ │ │ │ │ ├── UseAOSPScreenshot.kt
│ │ │ │ │ └── UseAOSPShareSheet.kt
│ │ │ │ ├── barrage
│ │ │ │ │ ├── BarrageNotTouchable.kt
│ │ │ │ │ ├── GlobalBarrage.kt
│ │ │ │ │ └── ModifyBarrageLength.kt
│ │ │ │ ├── contentextension
│ │ │ │ │ └── ChangeBrowserForContentExtension.kt
│ │ │ │ ├── downloadprovider
│ │ │ │ │ └── RemoveXlDownload.kt
│ │ │ │ ├── home
│ │ │ │ │ ├── AllowMoveNonMIUIWidgetsToMinusScreen.kt
│ │ │ │ │ ├── EnableBlurForHome.kt
│ │ │ │ │ ├── EnablePerfectIcons.kt
│ │ │ │ │ ├── FakeNonDefaultIcon.kt
│ │ │ │ │ ├── FakeNonDisabledIcon.kt
│ │ │ │ │ ├── ForceAppliedLightWallpaper.kt
│ │ │ │ │ ├── HideLandscapeNavBar.kt
│ │ │ │ │ ├── IconLabel.kt
│ │ │ │ │ ├── RestoreGoogleAppIcon.kt
│ │ │ │ │ ├── RestoreSwitchMinusScreen.kt
│ │ │ │ │ ├── ShowMIUIWidgetsInAndroidWidgetsList.kt
│ │ │ │ │ ├── UnlockGrids.kt
│ │ │ │ │ └── WidgetTransitionAnimation.kt
│ │ │ │ ├── intentresolver
│ │ │ │ │ └── UseAOSPShareSheet.kt
│ │ │ │ ├── packageinstaller
│ │ │ │ │ └── AllowUnofficialSystemApplicationsInstallation.kt
│ │ │ │ ├── powerkeeper
│ │ │ │ │ └── EnableBatteryMonitorService.kt
│ │ │ │ ├── screenrecorder
│ │ │ │ │ ├── ForceEnableNativePlaybackCapture.kt
│ │ │ │ │ └── ModifyScreenRecorderConfig.kt
│ │ │ │ ├── securitycenter
│ │ │ │ │ ├── AddAOSPAppInfoEntry.kt
│ │ │ │ │ ├── AddAOSPAppManagerEntry.kt
│ │ │ │ │ ├── AddOpenByDefaultEntry.kt
│ │ │ │ │ ├── PreventDisablingDevMode.kt
│ │ │ │ │ ├── RemoveAdbInstallIntercept.kt
│ │ │ │ │ ├── RemoveGameToast.kt
│ │ │ │ │ ├── RemoveReportInApplicationInfo.kt
│ │ │ │ │ └── SkipCountDown.kt
│ │ │ │ ├── settings
│ │ │ │ │ ├── QuickManageOverlayPermission.kt
│ │ │ │ │ ├── QuickManageUnknownAppSources.kt
│ │ │ │ │ ├── ShowGoogleSettingsEntry.kt
│ │ │ │ │ ├── ShowNotificationHistoryAndLogEntry.kt
│ │ │ │ │ └── ShowWifiPassword.kt
│ │ │ │ ├── systemui
│ │ │ │ │ ├── DisableGestureRecorder.kt
│ │ │ │ │ ├── HideIconFromStatusBar.kt
│ │ │ │ │ ├── LockscreenChargingInfo.kt
│ │ │ │ │ ├── NotificationSettingsNoWhiteList.kt
│ │ │ │ │ ├── RedirectToNotificationChannelSetting.kt
│ │ │ │ │ ├── RestoreHiddenCustomMediaAction.kt
│ │ │ │ │ ├── RestoreNearbyTile.kt
│ │ │ │ │ ├── UnlockControlCenterStyle.kt
│ │ │ │ │ ├── UseAOSPClipboardOverlay.kt
│ │ │ │ │ └── WaveCharge.kt
│ │ │ │ └── voiceassist
│ │ │ │ │ └── ChangeBrowserForMiAi.kt
│ │ │ ├── subpackage
│ │ │ │ ├── SystemUIPlugin.kt
│ │ │ │ └── systemuiplugin
│ │ │ │ │ └── RestoreNearbyTile.kt
│ │ │ └── universal
│ │ │ │ └── RemoveMIUIStrokeFromAdaptiveIcon.kt
│ │ └── utils
│ │ │ ├── ClipboardUtils.kt
│ │ │ ├── DexKit.kt
│ │ │ ├── LoadPackageParam.kt
│ │ │ └── XSharedPreferences.kt
│ │ └── utils
│ │ ├── Build.kt
│ │ ├── ClassScanner.kt
│ │ ├── Object.kt
│ │ ├── SharedPreferences.kt
│ │ └── Terminal.kt
│ └── res
│ ├── drawable
│ ├── ic_foreground.xml
│ └── ic_splash.xml
│ ├── mipmap
│ └── ic_launcher.xml
│ ├── resources.properties
│ ├── values-night
│ └── themes.xml
│ ├── values-zh-rCN
│ └── strings.xml
│ └── values
│ ├── arrays.xml
│ ├── colors.xml
│ ├── strings.xml
│ └── themes.xml
├── build.gradle.kts
├── crowdin.yml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on:
4 | push:
5 | branches: [ "main" ]
6 | pull_request:
7 | branches: [ "main" ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v4
16 | with:
17 | fetch-depth: 0
18 | submodules: true
19 |
20 | - name: set up JDK 17
21 | uses: actions/setup-java@v3
22 | with:
23 | java-version: '17'
24 | distribution: 'temurin'
25 | cache: gradle
26 |
27 | - uses: actions/cache@v4
28 | with:
29 | path: |
30 | ~/.gradle/caches
31 | ~/.gradle/wrapper
32 | !~/.gradle/caches/build-cache-*
33 | key: gradle-deps-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
34 | restore-keys: gradle-deps
35 |
36 | - uses: actions/cache@v4
37 | with:
38 | path: |
39 | ~/.gradle/caches/build-cache-*
40 | key: gradle-builds-${{ github.sha }}
41 |
42 | - name: Grant execute permission for gradlew
43 | run: chmod +x gradlew
44 |
45 | - name: Build with Gradle
46 | run: ./gradlew build
47 |
48 | - name: Upload a Build Artifact
49 | uses: actions/upload-artifact@v4
50 | with:
51 | path: ./app/build/outputs/apk
52 |
53 | - name: Post to Telegram channel
54 | if: ${{ success() && github.event_name != 'pull_request' && github.ref == 'refs/heads/main' && github.ref_type != 'tag' }}
55 | env:
56 | CHANNEL_ID: ${{ secrets.TELEGRAM_TO }}
57 | BOT_TOKEN: ${{ secrets.TELEGRAM_TOKEN }}
58 | COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
59 | COMMIT_URL: ${{ github.event.head_commit.url }}
60 | run: |
61 | if [ ! -z "${{ secrets.TELEGRAM_TOKEN }}" ]; then
62 | OUTPUT="app/build/outputs/apk/debug/"
63 | export arm64_v8a=$(find $OUTPUT -name "WOMMO-arm64-v8a-*.apk")
64 | export armeabi_v7a=$(find $OUTPUT -name "WOMMO-armeabi-v7a-*.apk")
65 | export universal=$(find $OUTPUT -name "WOMMO-universal-*.apk")
66 | event_path=$GITHUB_EVENT_PATH
67 | commit_count=$(jq -r '.commits | length' $event_path)
68 | { echo -e 'Github CI\n'; git log -$commit_count --pretty=format:"%h %s"; } > ${{ github.workspace }}/git_log
69 | ESCAPED="$(cat ${{ github.workspace }}/git_log | gawk '{gsub(/[_*[\]()~`>#+=\|{}.!-]/,"\\\\\\\\&")}1' | sed -e 's|"|\\"|g' -e 's|^[0-9a-z]\+|__&__|' | hexdump -v -e '/1 "%02X"' | sed 's/\(..\)/%\1/g')"
70 | cd ${{ github.workspace }}
71 | curl -v "https://api.telegram.org/bot${BOT_TOKEN}/sendMediaGroup?chat_id=${CHANNEL_ID}&media=%5B%7B%22type%22%3A%22document%22%2C%22media%22%3A%22attach%3A%2F%2Farm64_v8a%22%7D%2C%7B%22type%22%3A%22document%22%2C%22media%22%3A%22attach%3A%2F%2Farmeabi_v7a%22%7D%2C%7B%22type%22%3A%22document%22%2C%22media%22%3A%22attach%3A%2F%2Funiversal%22%2C%22caption%22%3A%22${ESCAPED}%22%2C%22parse_mode%22%3A%22MarkdownV2%22%7D%5D" -F arm64_v8a="@$arm64_v8a" -F armeabi_v7a="@$armeabi_v7a" -F universal="@$universal"
72 | fi
73 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .idea
5 | .DS_Store
6 | /build
7 | /captures
8 | .externalNativeBuild
9 | .cxx
10 | local.properties
11 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "blockmiui"]
2 | path = blockmiui
3 | url = https://github.com/Block-Network/blockmiui.git
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WOMMO -
2 |
3 | 这是一个自用的小米大杂烩模块。
4 |
5 | ---
6 |
7 | ### 现有功能
8 |
9 | #### 系统框架
10 |
11 | - 允许所有应用使用强制深色模式
12 | - 使用原生打开方式界面
13 | - 使用原生截屏
14 | - 禁用高媒体音量安全警告
15 |
16 | #### 系统界面
17 |
18 | - 恢复附近分享磁贴
19 | - 移除通知设置白名单
20 | - 锁屏显示充电功率
21 | - 启用 Alpha 充电动画
22 | - 重定向通知设置到频道设置
23 | - 解锁控制中心样式
24 | - 恢复被隐藏的自定义媒体按钮
25 | - 使用原生复制悬浮窗
26 | - 隐藏手机信号图标
27 |
28 | #### 系统桌面
29 |
30 | - 恢复 Google 图标
31 | - 恢复切换负一屏
32 | - 允许将非 MIUI 小部件移至智能助理(负一屏)
33 | - 在安卓小部件中显示 MIUI 小部件
34 | - 为所有小部件添加启动动画
35 | - 伪装为非默认图标
36 | - 启用模糊
37 | - 启用完美图标
38 | - 隐藏横屏时的小白条
39 | - 图标标题大小
40 | - 图标标题滚动
41 | - 解锁桌面图标布局限制
42 |
43 | #### 手机管家/平板管家
44 |
45 | - 向应用管理页添加“原生应用管理”入口
46 | - 向应用详情页添加“原生应用信息”入口
47 | - 向应用详情页添加“默认打开”入口
48 | - 移除应用信息举报按钮
49 | - 跳过倒计时
50 | - 移除adb安装拦截弹窗
51 | - 防止禁用开发者模式
52 |
53 | #### 屏幕录制
54 |
55 | - 强制启用原生录音支持
56 | - 修改码率与帧数范围
57 |
58 | #### 应用包管理组件
59 |
60 | - 允许从非官方渠道安装系统应用
61 |
62 | #### 弹幕通知
63 |
64 | - 允许所有应用使用弹幕通知
65 | - 全局弹幕通知
66 | - 弹幕不可点击
67 | - 修改弹幕长度
68 |
69 | #### 设置
70 |
71 | - 快速管理未知来源安装权限
72 | - 快速管理悬浮窗权限
73 | - 在通知与控制中心中显示通知历史记录与日志入口
74 | - 查看已保存的 Wi-Fi 密码
75 | - 显示 Google 设置
76 |
77 | #### 下载管理程序
78 |
79 | - 移除在根目录创建的 .xldownload 文件夹
80 |
81 | #### 小爱同学
82 |
83 | - 修改小爱同学使用的浏览器
84 |
85 | #### 传送门
86 |
87 | - 修改传送门使用的浏览器
88 |
89 | #### 电量和性能
90 |
91 | - 启用电池监控服务
92 |
93 | #### 其他
94 |
95 | - 强制所有应用支持流转(投屏,MIUI+ Beta 版)
96 | - 为非 MIUI 小部件提供曝光刷新
97 | - 显示通知重要程度
98 | - 移除自适应图标边界线(所有已勾选的作用域)
99 |
100 | ---
101 |
102 | ### 第三方开源引用
103 |
104 | ##### GNU Lesser General Public License v2.1
105 |
106 | [577fkj/blockmiui](https://github.com/Block-Network/blockmiui)
107 |
108 | ##### GNU Lesser General Public License v3.0
109 |
110 | [LuckyPray/DexKit](https://github.com/LuckyPray/DexKit)
111 |
112 | ##### Apache License 2.0
113 |
114 | [KyuubiRan/EzXHelper](https://github.com/KyuubiRan/EzXHelper)
115 |
116 | ##### GNU General Public License v3.0
117 |
118 | [hosizoraru/StarVoyager](https://github.com/hosizoraru/StarVoyager)
119 |
120 | [Simplicity-Team/WooBoxForMIUI](https://github.com/Simplicity-Team/WooBoxForMIUI)
121 |
122 | [qqlittleice/MiuiHome_R](https://github.com/qqlittleice/MiuiHome_R)
123 |
124 | [YifePlayte/WaveCharge](https://github.com/YifePlayte/WaveCharge)
125 |
126 | ##### MIT License
127 |
128 | [Haocen2004/PortalHook](https://github.com/Haocen2004/PortalHook)
129 |
130 | ##### 啥也不知道,咱也不敢问(
131 |
132 | [chsbuffer/MIUIQOL](https://github.com/chsbuffer/MIUIQOL)
133 |
134 | [xiaowine/WineUI](https://github.com/xiaowine/WineUI)
135 |
136 | ---
137 |
138 | ### License
139 |
140 | [GNU General Public License v3.0](https://github.com/YifePlayte/WOMMO/blob/main/LICENSE)
141 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /release
3 | /debug
4 |
--------------------------------------------------------------------------------
/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import com.android.build.gradle.internal.api.BaseVariantOutputImpl
2 | import java.time.LocalDateTime
3 | import java.time.format.DateTimeFormatter
4 |
5 | plugins {
6 | id("com.android.application")
7 | id("org.jetbrains.kotlin.android")
8 | }
9 |
10 | android {
11 | compileSdk = 34
12 |
13 | namespace = "com.yifeplayte.wommo"
14 |
15 | defaultConfig {
16 | applicationId = "com.yifeplayte.wommo"
17 | minSdk = 33
18 | targetSdk = 34
19 | versionCode = 1
20 | versionName = "1.0.0"
21 |
22 | ndk {
23 | abiFilters.add("armeabi-v7a")
24 | abiFilters.add("arm64-v8a")
25 | }
26 |
27 | splits {
28 | abi {
29 | isEnable = true
30 | reset()
31 | include("armeabi-v7a", "arm64-v8a")
32 | isUniversalApk = true
33 | }
34 | }
35 |
36 | applicationVariants.configureEach {
37 | outputs.configureEach {
38 | if (this is BaseVariantOutputImpl) {
39 | outputFileName = outputFileName.replace("app", rootProject.name)
40 | .replace(Regex("debug|release"), versionName)
41 | }
42 | }
43 | }
44 | }
45 |
46 | buildTypes {
47 | named("release") {
48 | isShrinkResources = true
49 | isMinifyEnabled = true
50 | proguardFiles("proguard-rules.pro")
51 | }
52 | named("debug") {
53 | versionNameSuffix = "-debug-" + DateTimeFormatter.ofPattern("yyyyMMddHHmmss")
54 | .format(LocalDateTime.now())
55 | }
56 | }
57 |
58 | androidResources {
59 | additionalParameters += "--allow-reserved-package-id"
60 | additionalParameters += "--package-id"
61 | additionalParameters += "0x45"
62 | generateLocaleConfig = true
63 | }
64 |
65 | compileOptions {
66 | sourceCompatibility = JavaVersion.VERSION_17
67 | targetCompatibility = JavaVersion.VERSION_17
68 | }
69 |
70 | kotlinOptions {
71 | jvmTarget = JavaVersion.VERSION_17.toString()
72 | }
73 |
74 | externalNativeBuild {
75 | cmake {
76 | path = file("src/main/cpp/classhelper/CMakeLists.txt")
77 | version = "3.22.1"
78 | }
79 | }
80 |
81 | buildFeatures {
82 | buildConfig = true
83 | }
84 | }
85 |
86 | dependencies {
87 | compileOnly("de.robv.android.xposed:api:82")
88 | implementation("com.github.kyuubiran:EzXHelper:2.2.0")
89 | implementation("io.github.ranlee1:jpinyin:1.0.1")
90 | implementation("org.lsposed.hiddenapibypass:hiddenapibypass:4.3")
91 | implementation("org.luckypray:dexkit:2.0.1")
92 | implementation(project(":blockmiui"))
93 | }
94 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keep class com.yifeplayte.wommo.hook.MainHook { (); }
-keep class * extends com.yifeplayte.wommo.hook.hooks.* {
();
com.yifeplayte.wommo.hook.hooks.** INSTANCE;
}
-keepattributes RuntimeVisibleAnnotations
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
13 |
16 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | com.yifeplayte.wommo.hook.MainHook
--------------------------------------------------------------------------------
/app/src/main/cpp/classhelper/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.22.1)
2 |
3 | project("wommo")
4 |
5 | add_library(
6 | classhelper
7 | SHARED
8 | native-lib.cpp
9 | )
10 |
--------------------------------------------------------------------------------
/app/src/main/cpp/classhelper/native-lib.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #define INVOKE_NONVIRT_SUPER_TYPE_METHOD(_jtype, _jname) \
4 | extern "C" JNIEXPORT _jtype JNICALL \
5 | Java_com_yifeplayte_wommo_utils_Object_invokeSuper##_jname##Method(JNIEnv *env, \
6 | jobject /* this */, \
7 | jobject obj, \
8 | jstring methodName, \
9 | jstring methodSignature, \
10 | jobjectArray args) { \
11 | jclass superClazz = env->GetSuperclass(env->GetObjectClass(obj)); \
12 | jmethodID superMethod = env->GetMethodID(superClazz, \
13 | env->GetStringUTFChars(methodName, nullptr), \
14 | env->GetStringUTFChars(methodSignature, nullptr)); \
15 | env->ReleaseStringUTFChars(methodName, nullptr); \
16 | env->ReleaseStringUTFChars(methodSignature, nullptr); \
17 | return env->CallNonvirtual##_jname##MethodA(obj, superClazz, superMethod, getArgs(env, args)); \
18 | }
19 |
20 | JNIEXPORT jint JNICALL
21 | JNI_OnLoad(JavaVM *vm, void *reserved) {
22 | return JNI_VERSION_1_6;
23 | }
24 |
25 | jvalue *getArgs(JNIEnv *env, jobjectArray args) {
26 | auto *argsArray = new jvalue[env->GetArrayLength(args)];
27 | for (int i = 0; i < env->GetArrayLength(args); ++i) {
28 | argsArray[i].l = env->GetObjectArrayElement(args, i);
29 | }
30 | return argsArray;
31 | }
32 |
33 | INVOKE_NONVIRT_SUPER_TYPE_METHOD(jobject, Object)
34 | INVOKE_NONVIRT_SUPER_TYPE_METHOD(jboolean, Boolean)
35 | INVOKE_NONVIRT_SUPER_TYPE_METHOD(jbyte, Byte)
36 | INVOKE_NONVIRT_SUPER_TYPE_METHOD(jchar, Char)
37 | INVOKE_NONVIRT_SUPER_TYPE_METHOD(jshort, Short)
38 | INVOKE_NONVIRT_SUPER_TYPE_METHOD(jint, Int)
39 | INVOKE_NONVIRT_SUPER_TYPE_METHOD(jlong, Long)
40 | INVOKE_NONVIRT_SUPER_TYPE_METHOD(jfloat, Float)
41 | INVOKE_NONVIRT_SUPER_TYPE_METHOD(jdouble, Double)
42 |
43 | extern "C" JNIEXPORT void JNICALL
44 | Java_com_yifeplayte_wommo_utils_Object_invokeSuperVoidMethod(JNIEnv *env,
45 | jobject /* this */,
46 | jobject obj,
47 | jstring methodName,
48 | jstring methodSignature,
49 | jobjectArray args) {
50 | jclass superClazz = env->GetSuperclass(env->GetObjectClass(obj));
51 | jmethodID superMethod = env->GetMethodID(superClazz,
52 | env->GetStringUTFChars(methodName, nullptr),
53 | env->GetStringUTFChars(methodSignature, nullptr));
54 | env->ReleaseStringUTFChars(methodName, nullptr);
55 | env->ReleaseStringUTFChars(methodSignature, nullptr);
56 | env->CallNonvirtualVoidMethodA(obj, superClazz, superMethod, getArgs(env, args));
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/activity/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.activity
2 |
3 | import android.annotation.SuppressLint
4 | import android.os.Bundle
5 | import cn.fkj233.ui.activity.MIUIActivity
6 | import cn.fkj233.ui.dialog.MIUIDialog
7 | import com.yifeplayte.wommo.R
8 | import com.yifeplayte.wommo.activity.pages.MainPage
9 | import com.yifeplayte.wommo.hook.utils.XSharedPreferences.PREFERENCES_FILE_NAME
10 | import kotlin.system.exitProcess
11 |
12 | class MainActivity : MIUIActivity() {
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | checkLSPosed()
15 | super.onCreate(savedInstanceState)
16 | }
17 |
18 | @SuppressLint("WorldReadableFiles")
19 | private fun checkLSPosed() {
20 | try {
21 | @Suppress("DEPRECATION")
22 | setSP(getSharedPreferences(PREFERENCES_FILE_NAME, MODE_WORLD_READABLE))
23 | } catch (exception: SecurityException) {
24 | isLoad = false
25 | MIUIDialog(this) {
26 | setTitle(R.string.warning)
27 | setMessage(R.string.not_support)
28 | setCancelable(false)
29 | setRButton(R.string.done) {
30 | exitProcess(0)
31 | }
32 | }.show()
33 | }
34 | }
35 |
36 | init {
37 | activity = this
38 | registerPage(MainPage::class.java)
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/MainHook.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook
2 |
3 | import com.github.kyuubiran.ezxhelper.EzXHelper
4 | import com.yifeplayte.wommo.hook.hooks.BaseMultiHook
5 | import com.yifeplayte.wommo.hook.hooks.BasePackage
6 | import com.yifeplayte.wommo.hook.hooks.BaseSubPackage
7 | import com.yifeplayte.wommo.hook.hooks.BaseUniversalHook
8 | import com.yifeplayte.wommo.hook.utils.DexKit
9 | import com.yifeplayte.wommo.utils.ClassScanner.scanObjectOf
10 | import de.robv.android.xposed.IXposedHookLoadPackage
11 | import de.robv.android.xposed.IXposedHookZygoteInit
12 | import de.robv.android.xposed.callbacks.XC_LoadPackage
13 |
14 | private const val TAG = "WOMMO"
15 | private val singlePackagesHooked by lazy {
16 | scanObjectOf("com.yifeplayte.wommo.hook.hooks.singlepackage")
17 | }
18 | private val multiPackagesHooked by lazy {
19 | scanObjectOf("com.yifeplayte.wommo.hook.hooks.multipackage")
20 | }
21 | private val subPackagesHooked by lazy {
22 | scanObjectOf("com.yifeplayte.wommo.hook.hooks.subpackage")
23 | }
24 | private val universalHooks by lazy {
25 | scanObjectOf("com.yifeplayte.wommo.hook.hooks.universal")
26 | }
27 | val PACKAGE_NAME_HOOKED: Set
28 | get() {
29 | val packageNameHooked = mutableSetOf()
30 | singlePackagesHooked.forEach { packageNameHooked.add(it.packageName) }
31 | multiPackagesHooked.forEach { packageNameHooked.addAll(it.hooks.keys) }
32 | subPackagesHooked.forEach { packageNameHooked.add(it.packageName) }
33 | return packageNameHooked
34 | }
35 |
36 | @Suppress("unused")
37 | class MainHook : IXposedHookLoadPackage, IXposedHookZygoteInit {
38 | override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
39 |
40 | // init DexKit and EzXHelper
41 | if (lpparam.isFirstApplication) {
42 | if (lpparam.packageName != "android") DexKit.initDexKit(lpparam)
43 | EzXHelper.initHandleLoadPackage(lpparam)
44 | EzXHelper.setLogTag(TAG)
45 | }
46 |
47 | // single package
48 | singlePackagesHooked.forEach { it.init() }
49 |
50 | // multiple package
51 | multiPackagesHooked.forEach { it.init() }
52 |
53 | // single sub-package
54 | subPackagesHooked.forEach { it.init() }
55 |
56 | DexKit.closeDexKit()
57 | }
58 |
59 | override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) {
60 |
61 | // init EzXHelper
62 | EzXHelper.initZygote(startupParam)
63 | EzXHelper.setLogTag(TAG)
64 |
65 | // universal hook
66 | universalHooks.forEach { it.init() }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/BaseHook.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks
2 |
3 | import com.github.kyuubiran.ezxhelper.Log
4 | import com.github.kyuubiran.ezxhelper.LogExtensions.logexIfThrow
5 | import com.yifeplayte.wommo.hook.utils.XSharedPreferences.getBoolean
6 |
7 | abstract class BaseHook {
8 | private var isInit: Boolean = false
9 | abstract val key: String
10 | abstract fun hook()
11 | open val isEnabled get() = getBoolean(key, false)
12 | fun init() {
13 | if (isInit) return
14 | if (isEnabled) runCatching {
15 | hook()
16 | isInit = true
17 | Log.ix("Inited hook: ${this.javaClass.simpleName}")
18 | }.logexIfThrow("Failed init hook: ${this.javaClass.simpleName}")
19 | }
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/BaseMultiHook.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks
2 |
3 | import com.github.kyuubiran.ezxhelper.EzXHelper.hostPackageName
4 | import com.github.kyuubiran.ezxhelper.Log
5 | import com.github.kyuubiran.ezxhelper.LogExtensions.logexIfThrow
6 | import com.yifeplayte.wommo.hook.utils.XSharedPreferences.getBoolean
7 |
8 | abstract class BaseMultiHook {
9 | private var isInit: Boolean = false
10 | abstract val key: String
11 | abstract val hooks: Map Unit>
12 | open val isEnabled get() = getBoolean(key, false)
13 | fun init() {
14 | if (isInit) return
15 | if (!isEnabled) return
16 | hooks[hostPackageName]?.runCatching {
17 | invoke()
18 | isInit = true
19 | Log.ix("Inited hook: ${this@BaseMultiHook.javaClass.simpleName} in: $hostPackageName")
20 | }?.logexIfThrow("Failed init hook: ${this@BaseMultiHook.javaClass.simpleName} in: $hostPackageName")
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/BasePackage.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks
2 |
3 | import com.github.kyuubiran.ezxhelper.EzXHelper
4 | import com.github.kyuubiran.ezxhelper.Log
5 | import com.github.kyuubiran.ezxhelper.LogExtensions.logexIfThrow
6 | import com.yifeplayte.wommo.utils.ClassScanner.scanObjectOf
7 |
8 | abstract class BasePackage(val packageName: String) {
9 | private var isInit: Boolean = false
10 | open val hooks: List by lazy {
11 | scanObjectOf(javaClass.packageName + "." + javaClass.simpleName.lowercase())
12 | }
13 |
14 | fun init() {
15 | if (EzXHelper.hostPackageName != packageName) return
16 | if (isInit) return
17 | runCatching {
18 | hooks.forEach { it.init() }
19 | isInit = true
20 | Log.ix("Inited package: ${this.javaClass.simpleName}")
21 | }.logexIfThrow("Failed init package: ${this.javaClass.simpleName}")
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/BaseSubHook.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks
2 |
3 | import com.github.kyuubiran.ezxhelper.Log
4 | import com.github.kyuubiran.ezxhelper.LogExtensions.logexIfThrow
5 | import com.yifeplayte.wommo.hook.utils.XSharedPreferences.getBoolean
6 |
7 | abstract class BaseSubHook {
8 | private var isInit: Boolean = false
9 | abstract val key: String
10 | abstract fun hook(subClassLoader: ClassLoader)
11 | open val isEnabled get() = getBoolean(key, false)
12 | fun init(subClassLoader: ClassLoader) {
13 | if (isInit) return
14 | if (isEnabled) runCatching {
15 | hook(subClassLoader)
16 | isInit = true
17 | Log.ix("Inited hook: ${this.javaClass.simpleName}")
18 | }.logexIfThrow("Failed init hook: ${this.javaClass.simpleName}")
19 | }
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/BaseSubPackage.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks
2 |
3 | import com.github.kyuubiran.ezxhelper.EzXHelper.hostPackageName
4 | import com.github.kyuubiran.ezxhelper.EzXHelper.safeClassLoader
5 | import com.github.kyuubiran.ezxhelper.Log
6 | import com.github.kyuubiran.ezxhelper.LogExtensions.logexIfThrow
7 | import com.yifeplayte.wommo.utils.ClassScanner.scanObjectOf
8 |
9 | abstract class BaseSubPackage(
10 | val packageName: String,
11 | val subPackageName: String
12 | ) {
13 | private var isInit: Boolean = false
14 | private lateinit var subClassLoader: ClassLoader
15 | var safeSubClassLoader
16 | get() = if (this::subClassLoader.isInitialized) subClassLoader else safeClassLoader
17 | set(value) {
18 | if (this::subClassLoader.isInitialized) return
19 | subClassLoader = value
20 | initHook()
21 | }
22 | open val hooks: List by lazy {
23 | scanObjectOf(javaClass.packageName + "." + javaClass.simpleName.lowercase())
24 | }
25 |
26 | fun init() {
27 | if (hostPackageName != packageName) return
28 | if (isInit) return
29 | kotlin.runCatching {
30 | initClassLoader()
31 | }.logexIfThrow("Failed init sub-package classloader for: $subPackageName in: $packageName")
32 | }
33 |
34 | private fun initHook() {
35 | runCatching {
36 | if (isInit) return
37 | hooks.forEach { it.init(safeSubClassLoader) }
38 | isInit = true
39 | Log.ix("Inited sub-package: ${this.javaClass.simpleName} in: $packageName")
40 | }.logexIfThrow("Failed init sub-package: ${this.javaClass.simpleName} in: $packageName")
41 | }
42 |
43 | /**
44 | * Must call safeSubClassLoader setter
45 | */
46 | abstract fun initClassLoader()
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/BaseUniversalHook.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks
2 |
3 | import com.github.kyuubiran.ezxhelper.EzXHelper.hostPackageName
4 | import com.github.kyuubiran.ezxhelper.Log
5 | import com.github.kyuubiran.ezxhelper.LogExtensions.logexIfThrow
6 | import com.yifeplayte.wommo.hook.utils.XSharedPreferences.getBoolean
7 |
8 | abstract class BaseUniversalHook {
9 | abstract val key: String
10 | abstract fun hook()
11 | open val isEnabled get() = getBoolean(key, false)
12 | open val isPartialUniversalHook: Boolean = false
13 | open val scope: Set? = null
14 | fun init() {
15 | if (isEnabled) runCatching {
16 | if (isPartialUniversalHook) {
17 | if (scope == null) return
18 | if (hostPackageName !in scope!!) return
19 | }
20 | hook()
21 | Log.ix("Inited universal hook: ${this.javaClass.simpleName}")
22 | }.logexIfThrow("Failed init universal hook: ${this.javaClass.simpleName}")
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/multipackage/ExposureRefreshForNonMIUIWidget.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.multipackage
2 |
3 | import android.appwidget.AppWidgetManager
4 | import android.content.ComponentName
5 | import android.content.Intent
6 | import android.content.pm.PackageManager
7 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
8 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClassOrNull
9 | import com.github.kyuubiran.ezxhelper.EzXHelper.appContext
10 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
11 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
12 | import com.github.kyuubiran.ezxhelper.ObjectUtils.getObjectOrNull
13 | import com.github.kyuubiran.ezxhelper.ObjectUtils.setObject
14 | import com.github.kyuubiran.ezxhelper.ObjectUtils.setObjectUntilSuperclass
15 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
16 | import com.yifeplayte.wommo.hook.hooks.BaseMultiHook
17 | import de.robv.android.xposed.XposedHelpers.getAdditionalInstanceField
18 | import de.robv.android.xposed.XposedHelpers.setAdditionalInstanceField
19 |
20 | @Suppress("unused")
21 | object ExposureRefreshForNonMIUIWidget : BaseMultiHook() {
22 | override val key = "exposure_refresh_for_non_miui_widget"
23 | override val hooks = mapOf(
24 | "com.miui.personalassistant" to { personalAssistant() },
25 | "android" to { android() },
26 | )
27 |
28 | private fun personalAssistant() {
29 | val clazzAppWidgetItemInfo =
30 | loadClass("com.miui.personalassistant.widget.iteminfo.AppWidgetItemInfo")
31 | clazzAppWidgetItemInfo.methodFinder().filterByName("parseWidgetMetaData").single()
32 | .createHook {
33 | after {
34 | val receiverInfo = appContext.packageManager.getReceiverInfo(
35 | getObjectOrNull(it.thisObject, "provider") as ComponentName,
36 | PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA.toLong())
37 | )
38 | val isRealMIUIWidget = receiverInfo.metaData.getBoolean("miuiWidget")
39 | setAdditionalInstanceField(
40 | it.thisObject, "isRealMIUIWidget", isRealMIUIWidget
41 | )
42 | if (!isRealMIUIWidget) {
43 | setObjectUntilSuperclass(it.thisObject, "isMIUIWidget", true)
44 | setObject(it.thisObject, "miuiWidgetRefresh", "exposure")
45 | setObject(it.thisObject, "miuiWidgetRefreshMinInterval", 10000)
46 | }
47 | }
48 | }
49 | clazzAppWidgetItemInfo.methodFinder().filterByName("obtainMiuiWidgetUpdateIntent").single()
50 | .createHook {
51 | after { param ->
52 | if (!(getAdditionalInstanceField(
53 | param.thisObject, "isRealMIUIWidget"
54 | ) as Boolean)
55 | ) {
56 | (param.result as Intent).action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
57 | }
58 | appContext.sendBroadcast(param.result as Intent)
59 | }
60 | }
61 | }
62 |
63 | private fun android() {
64 | // try to bypass the permission for third-party apps to send update broadcast to other apps
65 | loadClass("com.android.server.am.ActivityManagerService").methodFinder()
66 | .filterByName("broadcastIntentLocked").toList().createHooks {
67 | before {
68 | val intent = it.args[3] as Intent
69 | if (intent.action in setOf(
70 | AppWidgetManager.ACTION_APPWIDGET_UPDATE,
71 | AppWidgetManager.ACTION_APPWIDGET_CONFIGURE
72 | )
73 | ) {
74 | it.args[1] = intent.component?.packageName
75 | }
76 | }
77 | }
78 | loadClassOrNull("com.android.server.appwidget.AppWidgetServiceImplStubImpl")?.methodFinder()
79 | ?.filterByName("isForMiui")?.single()?.createHook {
80 | returnConstant(false)
81 | }
82 | }
83 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/multipackage/ForceSupportBarrage.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.multipackage
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Notification
5 | import android.content.Context
6 | import android.content.pm.ApplicationInfo
7 | import android.service.notification.StatusBarNotification
8 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
9 | import com.github.kyuubiran.ezxhelper.ClassUtils.setStaticObject
10 | import com.github.kyuubiran.ezxhelper.EzXHelper.appContext
11 | import com.github.kyuubiran.ezxhelper.EzXHelper.safeClassLoader
12 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
13 | import com.github.kyuubiran.ezxhelper.Log
14 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
15 | import com.yifeplayte.wommo.hook.hooks.BaseMultiHook
16 | import com.yifeplayte.wommo.hook.utils.DexKit.dexKitBridge
17 | import io.github.ranlee1.jpinyin.PinyinFormat.WITHOUT_TONE
18 | import io.github.ranlee1.jpinyin.PinyinHelper.convertToPinyinString
19 | import java.io.Serial
20 |
21 | @Suppress("unused")
22 | object ForceSupportBarrage : BaseMultiHook() {
23 | override val key = "force_support_barrage"
24 | override val hooks = mapOf(
25 | "com.xiaomi.barrage" to { hookForBarrage() },
26 | "com.miui.securitycenter" to { hookForSecurityCenter() },
27 | )
28 |
29 | @SuppressLint("QueryPermissionsNeeded")
30 | private fun hookForSecurityCenter() {
31 | val clazzNotificationFilterHelper = loadClass("miui.util.NotificationFilterHelper")
32 | val methodAreNotificationsEnabled = clazzNotificationFilterHelper.getDeclaredMethod(
33 | "areNotificationsEnabled", Context::class.java, String::class.java
34 | ).apply { isAccessible = true }
35 | dexKitBridge.findMethod {
36 | matcher {
37 | usingStrings = listOf("getInstance().assets.open(_SUPPORT_APPS_FILE_NAME)")
38 | }
39 | }.single().getMethodInstance(safeClassLoader).createHook {
40 | after { param ->
41 | val barragePackageList = appContext.packageManager.getInstalledApplications(0)
42 | .filter { (it.flags and ApplicationInfo.FLAG_SYSTEM) != 1 }.filter {
43 | methodAreNotificationsEnabled.invoke(
44 | clazzNotificationFilterHelper, appContext, it.packageName
45 | ) == true
46 | }.associateWith {
47 | val label = it.loadLabel(appContext.packageManager).toString()
48 | convertToPinyinString(label, "", WITHOUT_TONE).lowercase()
49 | }.entries.sortedBy { it.value }.map { it.key.packageName }
50 | @Suppress("UNCHECKED_CAST") val supportedList = param.result as MutableList
51 | for (s in barragePackageList) {
52 | if (!supportedList.contains(s)) supportedList.add(s)
53 | }
54 | }
55 | }
56 | dexKitBridge.findMethod{
57 | matcher {
58 | usingStrings = listOf("isApplicationFloatNotificationEnable fail ")
59 | }
60 | }.single().getMethodInstance(safeClassLoader).createHook {
61 | returnConstant(true)
62 | }
63 | }
64 |
65 | private fun hookForBarrage() {
66 | val clazzNotificationMonitorService =
67 | loadClass("com.xiaomi.barrage.service.NotificationMonitorService")
68 | setStaticObject(
69 | clazzNotificationMonitorService,
70 | "mBarragePackageList",
71 | object : ArrayList() {
72 | @Serial
73 | private val serialVersionUID: Long = 1643198520517506969L
74 | override fun contains(element: String?): Boolean {
75 | return true
76 | }
77 | })
78 | clazzNotificationMonitorService.methodFinder().filterByName("filterNotification").single()
79 | .createHook {
80 | before { param ->
81 | val statusBarNotification = param.args[0] as StatusBarNotification
82 | if (statusBarNotification.shouldBeFiltered()) param.result = true
83 | }
84 | }
85 | }
86 |
87 | object NotificationCache {
88 | private const val MAX_SIZE = 100
89 | private val cache = LinkedHashSet()
90 | fun check(string: String): Boolean {
91 | val result = cache.add(string)
92 | if (cache.size > MAX_SIZE) cache.remove(cache.first())
93 | return result
94 | }
95 | }
96 |
97 | private fun StatusBarNotification.shouldBeFiltered(): Boolean {
98 | val extras = notification.extras
99 | val key =
100 | "${extras.getCharSequence("android.title")}: ${extras.getCharSequence("android.text")}"
101 | val isGroupSummary = notification.flags and Notification.FLAG_GROUP_SUMMARY != 0
102 | return !isClearable || isGroupSummary || !NotificationCache.check(key)
103 | }
104 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/multipackage/ForceSupportSendApp.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.multipackage
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.EzXHelper.safeClassLoader
5 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
6 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
7 | import com.github.kyuubiran.ezxhelper.ObjectHelper.Companion.objectHelper
8 | import com.github.kyuubiran.ezxhelper.ObjectUtils.setObject
9 | import com.github.kyuubiran.ezxhelper.finders.FieldFinder.`-Static`.fieldFinder
10 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
11 | import com.yifeplayte.wommo.hook.hooks.BaseMultiHook
12 | import com.yifeplayte.wommo.hook.utils.DexKit.dexKitBridge
13 |
14 | @Suppress("unused")
15 | object ForceSupportSendApp : BaseMultiHook() {
16 | override val key = "force_support_send_app"
17 | override val hooks = mapOf(
18 | "com.milink.service" to { milink() },
19 | "com.xiaomi.mirror" to { if (!mirror()) mirrorNew() },
20 | )
21 |
22 | private fun milink() {
23 | val clazzMiuiSynergySdk = loadClass("com.xiaomi.mirror.synergy.MiuiSynergySdk")
24 | clazzMiuiSynergySdk.methodFinder().filterByName("isSupportSendApp").toList().createHooks {
25 | after {
26 | it.result = true
27 | }
28 | }
29 | }
30 |
31 | private fun mirror(): Boolean = runCatching {
32 | val clazzRelayAppMessage = loadClass("com.xiaomi.mirror.message.RelayAppMessage")
33 | val clazzMiCloudUtils = loadClass("com.xiaomi.mirror.settings.micloud.MiCloudUtils")
34 | clazzRelayAppMessage.methodFinder().filterByAssignableReturnType(clazzRelayAppMessage)
35 | .toList().createHooks {
36 | after {
37 | it.result.objectHelper().setObject("isHideIcon", false)
38 | }
39 | }
40 | clazzMiCloudUtils.methodFinder().filterByName("isSupportSubScreen").single().createHook {
41 | returnConstant(true)
42 | }
43 | }.isSuccess
44 |
45 | private fun mirrorNew() {
46 | val clazzRelayApplication =
47 | loadClass("com.xiaomi.mirror.message.proto.RelayApp\$RelayApplication")
48 | clazzRelayApplication.methodFinder().filterByName("getIsHideIcon").filterNonAbstract()
49 | .single().createHook {
50 | returnConstant(false)
51 | }
52 | clazzRelayApplication.methodFinder().filterByName("getSupportHandOff").filterNonAbstract()
53 | .single().createHook {
54 | returnConstant(true)
55 | }
56 | clazzRelayApplication.methodFinder().filterByName("getSupportSubScreen").filterNonAbstract()
57 | .single().createHook {
58 | returnConstant(true)
59 | }
60 | dexKitBridge.findMethod {
61 | matcher {
62 | usingStrings = listOf("support_all_app_sub_screen")
63 | returnType = "boolean"
64 | }
65 | }.single().getMethodInstance(safeClassLoader).createHook {
66 | returnConstant(true)
67 | }
68 | val clazzRelayAppMessage = dexKitBridge.findClass {
69 | matcher {
70 | usingStrings = listOf("RelayAppMessage{type=", ", isRelay=")
71 | }
72 | }.single().getInstance(safeClassLoader)
73 | clazzRelayAppMessage.let { clazz ->
74 | val fieldNameIsHideIcon =
75 | clazz.fieldFinder().filterByType(Boolean::class.javaPrimitiveType!!).toList()
76 | .sortedBy { it.name }[1].name
77 | clazz.methodFinder().filterByReturnType(clazz).toList().createHooks {
78 | after {
79 | setObject(it.result, fieldNameIsHideIcon, false)
80 | }
81 | }
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/multipackage/ShowNotificationImportance.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.multipackage
2 |
3 | import android.app.NotificationChannel
4 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
5 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
6 | import com.github.kyuubiran.ezxhelper.ObjectUtils.getObjectOrNullAs
7 | import com.github.kyuubiran.ezxhelper.ObjectUtils.getObjectOrNullUntilSuperclass
8 | import com.github.kyuubiran.ezxhelper.ObjectUtils.getObjectOrNullUntilSuperclassAs
9 | import com.github.kyuubiran.ezxhelper.ObjectUtils.invokeMethodBestMatch
10 | import com.github.kyuubiran.ezxhelper.ObjectUtils.setObject
11 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
12 | import com.yifeplayte.wommo.hook.hooks.BaseMultiHook
13 | import de.robv.android.xposed.XposedHelpers.getAdditionalInstanceField
14 | import de.robv.android.xposed.XposedHelpers.setAdditionalInstanceField
15 |
16 | @Suppress("unused")
17 | object ShowNotificationImportance : BaseMultiHook() {
18 | override val key = "show_notification_importance"
19 | override val hooks = mapOf(
20 | "com.android.settings" to { settings() },
21 | "com.android.systemui" to { systemUi() },
22 | )
23 |
24 | private fun settings() {
25 | loadClass("com.android.settings.notification.ChannelNotificationSettings").methodFinder()
26 | .filterByName("removeDefaultPrefs").single().createHook {
27 | before {
28 | val importance =
29 | invokeMethodBestMatch(it.thisObject, "findPreference", null, "importance")
30 | ?: return@before
31 | val mChannel = getObjectOrNullUntilSuperclassAs(
32 | it.thisObject,
33 | "mChannel"
34 | )!!
35 | val index = invokeMethodBestMatch(
36 | importance, "findSpinnerIndexOfValue", null, mChannel.importance.toString()
37 | )!! as Int
38 | if (index < 0) return@before
39 | invokeMethodBestMatch(importance, "setValueIndex", null, index)
40 | setAdditionalInstanceField(
41 | importance,
42 | "channelNotificationSettings",
43 | it.thisObject
44 | )
45 | it.result = null
46 | }
47 | }
48 | loadClass("androidx.preference.Preference").methodFinder()
49 | .filterByName("callChangeListener")
50 | .filterByParamTypes(Any::class.java).single().createHook {
51 | after {
52 | val channelNotificationSettings =
53 | getAdditionalInstanceField(it.thisObject, "channelNotificationSettings")
54 | ?: return@after
55 | val mChannel =
56 | getObjectOrNullUntilSuperclassAs(
57 | channelNotificationSettings,
58 | "mChannel"
59 | )!!
60 | invokeMethodBestMatch(
61 | mChannel,
62 | "setImportance",
63 | null,
64 | (it.args[0] as String).toInt()
65 | )
66 | val mBackend =
67 | getObjectOrNullUntilSuperclass(channelNotificationSettings, "mBackend")!!
68 | val mPkg = getObjectOrNullUntilSuperclassAs(
69 | channelNotificationSettings,
70 | "mPkg"
71 | )
72 | val mUid =
73 | getObjectOrNullUntilSuperclassAs(channelNotificationSettings, "mUid")
74 | invokeMethodBestMatch(mBackend, "updateChannel", null, mPkg, mUid, mChannel)
75 | }
76 | }
77 | }
78 |
79 | private fun systemUi() {
80 | loadClass("com.android.systemui.statusbar.phone.NotificationIconAreaController").methodFinder()
81 | .filterByName("updateStatusBarIcons").single().createHook {
82 | before { param ->
83 | val mNotificationEntries = getObjectOrNullAs>(
84 | param.thisObject,
85 | "mNotificationEntries"
86 | )!!
87 | if (mNotificationEntries.isNotEmpty()) {
88 | val list = ArrayList()
89 | mNotificationEntries.forEach {
90 | val representativeEntry =
91 | invokeMethodBestMatch(it, "getRepresentativeEntry")!!
92 | val importance =
93 | invokeMethodBestMatch(representativeEntry, "getImportance") as Int
94 | if (importance > 1) list.add(it)
95 | }
96 | if (list.size != mNotificationEntries.size) {
97 | setObject(param.thisObject, "mNotificationEntries", list)
98 | }
99 | }
100 | }
101 | }
102 | }
103 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/Android.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object Android : BasePackage("android")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/Barrage.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object Barrage : BasePackage("com.xiaomi.barrage")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/ContentExtension.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object ContentExtension : BasePackage("com.miui.contentextension")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/DownloadProvider.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object DownloadProvider : BasePackage("com.android.providers.downloads")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/Home.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object Home : BasePackage("com.miui.home")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/IntentResolver.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object IntentResolver : BasePackage("com.android.intentresolver")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/PackageInstaller.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object PackageInstaller : BasePackage("com.miui.packageinstaller")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/PowerKeeper.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object PowerKeeper : BasePackage("com.miui.powerkeeper")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/ScreenRecorder.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object ScreenRecorder : BasePackage("com.miui.screenrecorder")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/SecurityCenter.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object SecurityCenter : BasePackage("com.miui.securitycenter")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/Settings.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object Settings : BasePackage("com.android.settings")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/SystemUI.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object SystemUI : BasePackage("com.android.systemui")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/VoiceAssist.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage
2 |
3 | import com.yifeplayte.wommo.hook.hooks.BasePackage
4 |
5 | @Suppress("unused")
6 | object VoiceAssist : BasePackage("com.miui.voiceassist")
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/android/DisableSafeMediaVolume.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.android
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
6 | import com.github.kyuubiran.ezxhelper.Log
7 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
8 | import com.yifeplayte.wommo.hook.hooks.BaseHook
9 |
10 | @Suppress("unused")
11 | object DisableSafeMediaVolume : BaseHook() {
12 | override val key = "disable_safe_media_volume"
13 | override fun hook() {
14 | loadClass("com.android.server.audio.SoundDoseHelperStubImpl").methodFinder()
15 | .filterByName("updateSafeMediaVolumeIndex").filterNonAbstract().filterByParamCount(1)
16 | .toList().createHooks {
17 | returnConstant(0x7ffffffe)
18 | }
19 | loadClass("com.android.server.audio.SoundDoseHelper").methodFinder()
20 | .filterByName("safeMediaVolumeIndex").filterNonAbstract().single().createHook {
21 | returnConstant(0x7ffffffe)
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/android/ForceDarkModeForAllApps.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.android
2 |
3 | import android.content.pm.ApplicationInfo
4 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
5 | import com.github.kyuubiran.ezxhelper.ClassUtils.setStaticObject
6 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
7 | import com.github.kyuubiran.ezxhelper.ObjectUtils.invokeMethodBestMatch
8 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
9 | import com.yifeplayte.wommo.hook.hooks.BaseHook
10 | import com.yifeplayte.wommo.utils.Build.IS_INTERNATIONAL_BUILD
11 |
12 | @Suppress("unused")
13 | object ForceDarkModeForAllApps : BaseHook() {
14 | override val key = "force_dark_mode_for_all_apps"
15 | override val isEnabled get() = !IS_INTERNATIONAL_BUILD && super.isEnabled
16 | private val clazzBuild by lazy { loadClass("miui.os.Build") }
17 | override fun hook() {
18 | val clazzForceDarkAppListManager = loadClass("com.android.server.ForceDarkAppListManager")
19 | clazzForceDarkAppListManager.methodFinder().filterByName("getDarkModeAppList").toList()
20 | .createHooks {
21 | before {
22 | setStaticObject(clazzBuild, "IS_INTERNATIONAL_BUILD", true)
23 | }
24 | after {
25 | setStaticObject(clazzBuild, "IS_INTERNATIONAL_BUILD", IS_INTERNATIONAL_BUILD)
26 | }
27 | }
28 | clazzForceDarkAppListManager.methodFinder().filterByName("shouldShowInSettings").toList()
29 | .createHooks {
30 | before { param ->
31 | val info = param.args[0] as ApplicationInfo?
32 | param.result = !(info == null || (invokeMethodBestMatch(
33 | info, "isSystemApp"
34 | ) as Boolean) || info.uid < 10000)
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/android/UseAOSPScreenshot.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.android
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.invokeStaticMethodBestMatch
4 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
5 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
6 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
7 | import com.yifeplayte.wommo.hook.hooks.BaseHook
8 |
9 | @Suppress("unused")
10 | object UseAOSPScreenshot : BaseHook() {
11 | override val key = "use_aosp_screenshot"
12 | override fun hook() {
13 | invokeStaticMethodBestMatch(
14 | loadClass("com.android.internal.util.ScreenshotHelperStub"), "getInstance"
15 | )?.let {
16 | it::class.java.methodFinder().filterByName("getServiceComponent").filterNonAbstract()
17 | .toList().createHooks {
18 | returnConstant("com.android.systemui/com.android.systemui.screenshot.TakeScreenshotService")
19 | }
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/android/UseAOSPShareSheet.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.android
2 |
3 | import android.provider.Settings
4 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
5 | import com.github.kyuubiran.ezxhelper.EzXHelper.appContext
6 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
7 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
8 | import com.yifeplayte.wommo.hook.hooks.BaseHook
9 | import com.yifeplayte.wommo.utils.Build.HYPER_OS_VERSION
10 |
11 | @Suppress("unused")
12 | object UseAOSPShareSheet : BaseHook() {
13 | override val key = "use_aosp_share_sheet"
14 | override val isEnabled = (HYPER_OS_VERSION < 2) && super.isEnabled
15 | override fun hook() {
16 | loadClass("com.android.internal.app.ResolverActivityStubImpl").methodFinder()
17 | .filterByName("useAospShareSheet").single().createHook {
18 | before {
19 | it.result = Settings.System.getInt(
20 | appContext.contentResolver,
21 | "mishare_enabled"
22 | ) != 1
23 | }
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/barrage/BarrageNotTouchable.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.barrage
2 |
3 | import android.view.View
4 | import android.view.WindowManager
5 | import android.view.WindowManager.LayoutParams
6 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
7 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
8 | import com.github.kyuubiran.ezxhelper.ObjectUtils.getObjectOrNull
9 | import com.github.kyuubiran.ezxhelper.ObjectUtils.setObject
10 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
11 | import com.yifeplayte.wommo.hook.hooks.BaseHook
12 | import java.lang.reflect.Method
13 |
14 | @Suppress("unused")
15 | object BarrageNotTouchable : BaseHook() {
16 | override val key = "barrage_not_touchable"
17 | override fun hook() {
18 | loadClass("com.xiaomi.barrage.utils.BarrageWindowUtils\$ComputeInternalInsetsHandler").methodFinder()
19 | .filterByName("invoke").filterNonAbstract().single().createHook {
20 | before { param ->
21 | val method = param.args[1] as Method
22 | if (!method.name.equals("onComputeInternalInsets")) return@before
23 |
24 | val barrageWindowUtils = getObjectOrNull(param.thisObject, "this$0")!!
25 |
26 | val mWindowParams =
27 | getObjectOrNull(barrageWindowUtils, "mWindowParams") as LayoutParams
28 | val mWindowManager =
29 | getObjectOrNull(barrageWindowUtils, "mWindowManager") as WindowManager
30 | val mView = getObjectOrNull(barrageWindowUtils, "mView") as View
31 | val mWindowTouchable = getObjectOrNull(barrageWindowUtils, "mWindowTouchable")
32 |
33 | if (mWindowTouchable == true || mWindowParams.flags and LayoutParams.FLAG_NOT_TOUCHABLE == 0) {
34 | setObject(barrageWindowUtils, "mWindowTouchable", false)
35 | mWindowParams.flags = mWindowParams.flags or LayoutParams.FLAG_NOT_TOUCHABLE
36 | mWindowManager.updateViewLayout(mView, mWindowParams)
37 | }
38 |
39 | param.result = null
40 | }
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/barrage/GlobalBarrage.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.barrage
2 |
3 | import android.content.ContentResolver
4 | import android.provider.Settings
5 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
6 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
7 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
8 | import com.yifeplayte.wommo.hook.hooks.BaseHook
9 |
10 | @Suppress("unused")
11 | object GlobalBarrage : BaseHook() {
12 | override val key = "global_barrage"
13 | override fun hook() {
14 | loadClass("android.provider.Settings\$Secure").methodFinder().filterByName("getInt")
15 | .toList().createHooks {
16 | after { param ->
17 | if ((param.args[1] as String) == "gb_boosting" && param.result != 1) {
18 | Settings.Secure.putInt(param.args[0] as ContentResolver?, "gb_boosting", 1)
19 | param.result = 1
20 | }
21 | }
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/barrage/ModifyBarrageLength.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.barrage
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.service.notification.StatusBarNotification
6 | import android.util.Log
7 | import com.github.kyuubiran.ezxhelper.ClassUtils.getStaticObjectOrNullAs
8 | import com.github.kyuubiran.ezxhelper.ClassUtils.invokeStaticMethodBestMatch
9 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
10 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
11 | import com.github.kyuubiran.ezxhelper.ObjectHelper.Companion.objectHelper
12 | import com.github.kyuubiran.ezxhelper.ObjectUtils.getObjectOrNull
13 | import com.github.kyuubiran.ezxhelper.ObjectUtils.getObjectOrNullAs
14 | import com.github.kyuubiran.ezxhelper.ObjectUtils.invokeMethodBestMatch
15 | import com.github.kyuubiran.ezxhelper.ObjectUtils.setObject
16 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
17 | import com.yifeplayte.wommo.hook.hooks.BaseHook
18 | import com.yifeplayte.wommo.hook.utils.XSharedPreferences.getInt
19 | import java.util.Random
20 |
21 | @Suppress("unused")
22 | object ModifyBarrageLength : BaseHook() {
23 | override val key = "modify_barrage_length"
24 | override val isEnabled get() = barrageLength != 36
25 | private val barrageLength by lazy { getInt("barrage_length", 36) }
26 | private const val TAG = "MiBarrage"
27 |
28 | @SuppressLint("DiscouragedApi")
29 | override fun hook() {
30 | val clazzUiUtils = loadClass("com.xiaomi.barrage.utils.UiUtils")
31 | val clazzAlphaValue = loadClass("com.xiaomi.barrage.danmu.model.AlphaValue")
32 | loadClass("com.xiaomi.barrage.utils.BarrageWindowUtils").methodFinder()
33 | .filterByName("addBarrageNotification").filterByParamCount(2).single().createHook {
34 | replace { param ->
35 | val thisObject = param.thisObject
36 | val statusBarNotification = param.args[0] as StatusBarNotification
37 | val isLive = param.args[1] as Boolean
38 |
39 | val mBarrageView = getObjectOrNull(thisObject, "mBarrageView")
40 | val maxLinesPair =
41 | getObjectOrNullAs>(thisObject, "maxLinesPair")!!
42 | val mPreferences = getObjectOrNull(thisObject, "mPreferences")!!
43 | val mBarrageContext = getObjectOrNull(thisObject, "mBarrageContext")!!
44 | val mContext = getObjectOrNull(thisObject, "mContext") as Context
45 | val mBarrageShowManager = getObjectOrNull(thisObject, "mBarrageShowManager")!!
46 |
47 | if (!getObjectOrNullAs(thisObject, "hasAddView")!!) {
48 | Log.d(TAG, "No barrage because view not added")
49 | return@replace null
50 | }
51 |
52 | maxLinesPair[1] =
53 | invokeMethodBestMatch(mPreferences, "getRowNumberIndex") as Int + 1
54 | var speedLevel = invokeMethodBestMatch(mPreferences, "getSpeedLevel")
55 | speedLevel =
56 | invokeStaticMethodBestMatch(clazzUiUtils, "getSpeedLevel", null, speedLevel)
57 | invokeMethodBestMatch(mBarrageContext, "setScrollSpeedFactor", null, speedLevel)
58 | invokeMethodBestMatch(mBarrageContext, "setMaximumLines", null, maxLinesPair)
59 |
60 | val mDanmuFactory = getObjectOrNull(mBarrageContext, "mDanmuFactory")!!
61 | val danmu = invokeMethodBestMatch(mDanmuFactory, "createDanmu", null, 1)
62 |
63 | if (danmu == null || mBarrageView == null) {
64 | Log.d(TAG, "No barrage because barrage or view is null")
65 | return@replace null
66 | }
67 |
68 | if (invokeMethodBestMatch(mBarrageView, "isPaused") as Boolean) {
69 | invokeMethodBestMatch(mBarrageView, "resume")
70 | }
71 |
72 | val extras = statusBarNotification.notification.extras
73 | val title = extras.getCharSequence("android.title").toString()
74 | Log.d(TAG, "Danmu title: $title")
75 | var content = extras.getCharSequence("android.text").toString()
76 | Log.d(TAG, "Danmu content length: " + content.length)
77 |
78 | if (title.isEmpty() || content.isEmpty()) {
79 | Log.d(TAG, "No barrage because title or content is empty")
80 | return@replace null
81 | }
82 |
83 | val packageName = statusBarNotification.packageName
84 |
85 | if ("com.tencent.mm" == packageName) {
86 | content = invokeMethodBestMatch(
87 | thisObject, "cutWeChatMsg", null, content
88 | ) as String
89 | }
90 |
91 | if ("com.whatsapp" == packageName && statusBarNotification.tag.isNullOrEmpty()) {
92 | Log.d(TAG, "NULL tag, removing it")
93 | return@replace null
94 | }
95 |
96 | val bubbleStylePosition =
97 | invokeMethodBestMatch(mPreferences, "getBubbleStyleSelectedPosition") as Int
98 | val textSizeLevel =
99 | invokeMethodBestMatch(mPreferences, "getTextSizeLevel") as Int
100 | var finalBubbleStylePosition = bubbleStylePosition
101 |
102 | var paddingTop = 15
103 | var paddingBottom = 15
104 |
105 | if (bubbleStylePosition == 4 && textSizeLevel == 3) {
106 | finalBubbleStylePosition = Random().nextInt(4)
107 | if (finalBubbleStylePosition == 0) {
108 | paddingTop = 0
109 | paddingBottom = 20
110 | }
111 | }
112 |
113 | var customAppTextColor = invokeStaticMethodBestMatch(
114 | clazzUiUtils,
115 | "getCustomAppTextColor",
116 | null,
117 | mContext.resources,
118 | finalBubbleStylePosition,
119 | invokeMethodBestMatch(mPreferences, "getDefaultEditColorPickedPosition")
120 | )
121 |
122 | if (bubbleStylePosition == 5) {
123 | val pickedPositionMap = invokeStaticMethodBestMatch(
124 | clazzUiUtils, "getPickedPosition", null, packageName, mPreferences
125 | ) as Map<*, *>
126 | setObject(thisObject, "pickedPositionMap", pickedPositionMap)
127 | if (pickedPositionMap["key_custom_app_bubble_style_picked_position"] == 0 && textSizeLevel == 3) {
128 | paddingTop = 0
129 | paddingBottom = 20
130 | }
131 | customAppTextColor = invokeStaticMethodBestMatch(
132 | clazzUiUtils,
133 | "getCustomAppTextColor",
134 | null,
135 | mContext.resources,
136 | pickedPositionMap["key_custom_app_bubble_style_picked_position"],
137 | pickedPositionMap["key_custom_app_color_picked_position"]
138 | )
139 | }
140 |
141 | var text = "$title: $content".replace("(\r\n|\r|\n|\n\r)".toRegex(), "")
142 | if (text.length > barrageLength) {
143 | text = text.substring(0, barrageLength) + "..."
144 | }
145 |
146 | val iconDrawable =
147 | statusBarNotification.notification.smallIcon.loadDrawable(mContext)!!
148 |
149 | val boundsBottomRight = invokeStaticMethodBestMatch(
150 | clazzUiUtils, "dip2px", null, mContext, invokeStaticMethodBestMatch(
151 | clazzUiUtils, "getFontSizeScale", null, textSizeLevel
152 | ) as Float * 18.0f
153 | ) as Int
154 | iconDrawable.setBounds(0, 0, boundsBottomRight, boundsBottomRight)
155 |
156 | @Suppress("DEPRECATION") danmu.objectHelper {
157 | setObjectUntilSuperclass("appUserId", statusBarNotification.userId)
158 | setObjectUntilSuperclass("packageName", packageName)
159 | setObjectUntilSuperclass(
160 | "text", invokeMethodBestMatch(
161 | thisObject, "createSpannable", null, iconDrawable, text
162 | )
163 | )
164 | setObjectUntilSuperclass("paddingtop", paddingTop)
165 | setObjectUntilSuperclass("paddingbottom", paddingBottom)
166 | setObjectUntilSuperclass("paddingright", 50)
167 | setObjectUntilSuperclass("paddingleft", 50)
168 | setObjectUntilSuperclass(
169 | "paintIconwidth", invokeStaticMethodBestMatch(
170 | clazzUiUtils, "dip2px", null, mContext, 15.0f
171 | )
172 | )
173 | setObjectUntilSuperclass("priority", 0.toByte())
174 | setObjectUntilSuperclass("isLive", isLive)
175 | invokeMethodBestMatch(
176 | "setTime", null, invokeMethodBestMatch(mBarrageView, "getCurrentTime")
177 | )
178 | setObjectUntilSuperclass(
179 | "textSize", invokeStaticMethodBestMatch(
180 | clazzUiUtils, "sp2px", null, mContext, invokeStaticMethodBestMatch(
181 | clazzUiUtils, "getFontSize", null, textSizeLevel
182 | )
183 | )
184 | )
185 | setObjectUntilSuperclass("textColor", customAppTextColor)
186 | setObjectUntilSuperclass(
187 | "textShadowColor", mContext.getColor(
188 | mContext.resources.getIdentifier(
189 | "color_border_text", "color", mContext.packageName
190 | )
191 | )
192 | )
193 | setObjectUntilSuperclass(
194 | "barrageAlpha", invokeMethodBestMatch(
195 | mPreferences, "getBarrageViewAlpha"
196 | ) as Float * getStaticObjectOrNullAs(
197 | clazzAlphaValue, "MAX"
198 | )!!
199 | )
200 | setObjectUntilSuperclass("bubbleStylePosition", bubbleStylePosition)
201 | runCatching { setObjectUntilSuperclass("barrageDrawable", iconDrawable) }
202 | runCatching { setObjectUntilSuperclass("barrageMsg", text) }
203 | runCatching {
204 | setObjectUntilSuperclass(
205 | "contentIntent", statusBarNotification.notification.contentIntent
206 | )
207 | }
208 | }
209 |
210 | invokeMethodBestMatch(mBarrageShowManager, "addDanmu", null, danmu)
211 |
212 | return@replace null
213 | }
214 | }
215 | }
216 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/contentextension/ChangeBrowserForContentExtension.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.contentextension
2 |
3 | import android.app.SearchManager
4 | import android.content.Intent
5 | import android.net.Uri
6 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
7 | import com.github.kyuubiran.ezxhelper.EzXHelper.appContext
8 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
9 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
10 | import com.yifeplayte.wommo.hook.hooks.BaseHook
11 |
12 | @Suppress("unused")
13 | object ChangeBrowserForContentExtension : BaseHook() {
14 | override val key = "change_browser_for_content_extension"
15 | override fun hook() {
16 | val clazzAppsUtils = loadClass("com.miui.contentextension.utils.AppsUtils")
17 | clazzAppsUtils.methodFinder().filterByName("openGlobalSearch").single().createHook {
18 | replace { param ->
19 | Intent(Intent.ACTION_WEB_SEARCH).apply {
20 | putExtra(SearchManager.QUERY, param.args[1].toString())
21 | flags = Intent.FLAG_ACTIVITY_NEW_TASK
22 | }.let {
23 | appContext.startActivity(it)
24 | }
25 | }
26 | }
27 | clazzAppsUtils.methodFinder().filterByName("getIntentWithBrowser").single().createHook {
28 | before {
29 | it.result = Intent(Intent.ACTION_VIEW, Uri.parse(it.args[0].toString()))
30 | }
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/downloadprovider/RemoveXlDownload.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.downloadprovider
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
5 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
6 | import com.yifeplayte.wommo.hook.hooks.BaseHook
7 |
8 | @Suppress("unused")
9 | object RemoveXlDownload : BaseHook() {
10 | override val key = "remove_xl_download"
11 | override fun hook() {
12 | val clazzXLConfig = loadClass("com.android.providers.downloads.config.XLConfig")
13 | clazzXLConfig.methodFinder().filter { name in setOf("setDebug", "setSoDebug") }.toList()
14 | .createHooks {
15 | returnConstant(null)
16 | }
17 | // val targetPath = File(Environment.getExternalStorageDirectory(), ".xlDownload").absoluteFile
18 | // File::class.java.methodFinder().filterByName("mkdirs").single().createHook {
19 | // before {
20 | // if ((it.thisObject as File).absoluteFile.equals(targetPath)) {
21 | // it.throwable = FileNotFoundException("blocked")
22 | // }
23 | // }
24 | // }
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/home/AllowMoveNonMIUIWidgetsToMinusScreen.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.home
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.github.kyuubiran.ezxhelper.ObjectUtils.getObjectOrNullUntilSuperclassAs
6 | import com.github.kyuubiran.ezxhelper.ObjectUtils.invokeMethodBestMatch
7 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
8 | import com.yifeplayte.wommo.hook.hooks.BaseHook
9 | import de.robv.android.xposed.XposedHelpers.callMethod
10 |
11 | @Suppress("unused")
12 | object AllowMoveNonMIUIWidgetsToMinusScreen : BaseHook() {
13 | override val key = "allow_move_non_miui_widgets_to_minus_screen"
14 | override fun hook() {
15 | loadClass("com.miui.home.launcher.widget.MIUIWidgetHelper").methodFinder()
16 | .filterByName("canDragToPa").filterByParamCount(2).single().createHook {
17 | before { param ->
18 | runCatching {
19 | val dragInfo = invokeMethodBestMatch(param.args[1], "getDragInfo")!!
20 | val spanX = getObjectOrNullUntilSuperclassAs(dragInfo, "spanX")!!
21 | val spanY = getObjectOrNullUntilSuperclassAs(dragInfo, "spanY")!!
22 | // val launcherCallBacks = invokeMethodBestMatch(param.args[0], "getLauncherCallbacks")
23 | val launcherCallBacks = callMethod(param.args[0], "getLauncherCallbacks")
24 | // val dragController = invokeMethodBestMatch(param.args[0], "getDragController")!!
25 | val dragController = callMethod(param.args[0], "getDragController")
26 | val isDraggingFromAssistant =
27 | invokeMethodBestMatch(dragController, "isDraggingFromAssistant") as Boolean
28 | val isDraggingToAssistant =
29 | invokeMethodBestMatch(dragController, "isDraggingToAssistant") as Boolean
30 | param.result =
31 | launcherCallBacks != null && !isDraggingFromAssistant && !isDraggingToAssistant && spanX % 2 == 0 && (spanX != 2 || spanY == 2)
32 | }
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/home/EnableBlurForHome.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.home
2 |
3 | import com.github.kyuubiran.ezxhelper.EzXHelper.safeClassLoader
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
5 | import com.yifeplayte.wommo.hook.hooks.BaseHook
6 | import com.yifeplayte.wommo.hook.utils.DexKit.dexKitBridge
7 | import org.luckypray.dexkit.query.matchers.base.StringMatcher
8 | import java.lang.reflect.Method
9 |
10 | @Suppress("unused")
11 | object EnableBlurForHome : BaseHook() {
12 | override val key = "enable_blur_for_home"
13 | override fun hook() {
14 | mutableListOf().apply {
15 | addAll(dexKitBridge.findMethod {
16 | matcher {
17 | name(StringMatcher("SupportBlur"))
18 | returnType = "boolean"
19 | }
20 | }.map { it.getMethodInstance(safeClassLoader) })
21 | addAll(dexKitBridge.findMethod {
22 | matcher {
23 | name(StringMatcher("BlurSupported"))
24 | returnType = "boolean"
25 | }
26 | }.map { it.getMethodInstance(safeClassLoader) })
27 | }.createHooks { returnConstant(true) }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/home/EnablePerfectIcons.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.home
2 |
3 | import android.app.Application
4 | import com.github.kyuubiran.ezxhelper.ClassUtils.invokeStaticMethodBestMatch
5 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
6 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
7 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
8 | import com.yifeplayte.wommo.hook.hooks.BaseHook
9 |
10 | @Suppress("unused")
11 | object EnablePerfectIcons : BaseHook() {
12 | override val key = "enable_perfect_icons"
13 | override fun hook() {
14 | runCatching {
15 | val clazzMiuiSettingsUtils = loadClass("com.miui.launcher.utils.MiuiSettingsUtils")
16 | loadClass("com.miui.home.launcher.Application").methodFinder()
17 | .filterByName("disablePerfectIcons").single()
18 | .createHook {
19 | before {
20 | val contentResolver = (it.thisObject as Application).contentResolver
21 | invokeStaticMethodBestMatch(
22 | clazzMiuiSettingsUtils,
23 | "putBooleanToSystem",
24 | null,
25 | contentResolver,
26 | "key_miui_mod_icon_enable",
27 | true
28 | )
29 | it.result = null
30 | }
31 | }
32 | }
33 | loadClass("miui.content.res.IconCustomizer").methodFinder()
34 | .filterByName("isModIconEnabledForPackageName")
35 | .single().createHook { returnConstant(true) }
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/home/FakeNonDisabledIcon.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.home
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
6 | import com.yifeplayte.wommo.hook.hooks.BaseHook
7 |
8 | @Suppress("unused")
9 | object FakeNonDisabledIcon : BaseHook() {
10 | override val key = "fake_non_disabled_icon"
11 | override fun hook() {
12 | loadClass("com.miui.home.launcher.ItemInfoWithIconAndMessage").methodFinder()
13 | .filterByName("isDisabled").filterNonAbstract().single().createHook {
14 | before { param ->
15 | if (Thread.currentThread().stackTrace.any { it.methodName == "getColorFilter" }) {
16 | param.result = false
17 | }
18 | }
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/home/ForceAppliedLightWallpaper.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.home
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
6 | import com.yifeplayte.wommo.hook.hooks.BaseHook
7 |
8 | @Suppress("unused")
9 | object ForceAppliedLightWallpaper : BaseHook() {
10 | override val key = "force_applied_light_wallpaper"
11 | override fun hook() {
12 | val clazzWallpaperUtils = loadClass("com.miui.home.launcher.WallpaperUtils")
13 | clazzWallpaperUtils.methodFinder()
14 | .filterByName("hasAppliedLightWallpaper").filterNonAbstract().single().createHook {
15 | returnConstant(true)
16 | }
17 | clazzWallpaperUtils.methodFinder()
18 | .filterByName("hasLightBgForStatusBar").filterNonAbstract().single().createHook {
19 | returnConstant(true)
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/home/HideLandscapeNavBar.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.home
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
6 | import com.yifeplayte.wommo.hook.hooks.BaseHook
7 |
8 | @Suppress("unused")
9 | object HideLandscapeNavBar : BaseHook() {
10 | override val key = "hide_landscape_nav_bar"
11 | override fun hook() {
12 | loadClass("com.miui.home.recents.views.RecentsContainer").methodFinder()
13 | .filterByName("hideFakeNavBarForHidingGestureLine")
14 | .single().createHook {
15 | before {
16 | it.args[0] = true
17 | }
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/home/IconLabel.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.home
2 |
3 | import android.annotation.SuppressLint
4 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
5 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
6 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
7 | import com.yifeplayte.wommo.hook.hooks.BaseHook
8 | import com.yifeplayte.wommo.hook.utils.XSharedPreferences.getInt
9 |
10 | @Suppress("unused")
11 | object IconLabel : BaseHook() {
12 | override val key = "icon_label"
13 | override val isEnabled = true
14 | private val labelSize by lazy { getInt("icon_label_size", 37).toFloat() }
15 |
16 | @SuppressLint("DiscouragedApi")
17 | override fun hook() {
18 | loadClass("com.miui.home.launcher.DeviceConfig").methodFinder()
19 | .filterByName("getIconTitleTextSize").single().createHook {
20 | before {
21 | it.result = labelSize
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/home/RestoreGoogleAppIcon.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.home
2 |
3 | import android.content.ComponentName
4 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
5 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
6 | import com.github.kyuubiran.ezxhelper.ObjectUtils.getObjectOrNullAs
7 | import com.yifeplayte.wommo.hook.hooks.BaseHook
8 |
9 | @Suppress("unused")
10 | object RestoreGoogleAppIcon : BaseHook() {
11 | override val key = "restore_google_app_icon"
12 | override fun hook() {
13 | loadClass("com.miui.home.launcher.AppFilter").declaredConstructors.createHooks {
14 | after { param ->
15 | getObjectOrNullAs>(
16 | param.thisObject,
17 | "mSkippedItems"
18 | )!!.removeIf {
19 | it.packageName in setOf(
20 | "com.google.android.googlequicksearchbox",
21 | "com.google.android.gms"
22 | )
23 | }
24 | }
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/home/RestoreSwitchMinusScreen.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.home
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import com.github.kyuubiran.ezxhelper.ClassUtils.invokeStaticMethodBestMatch
6 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
7 | import com.github.kyuubiran.ezxhelper.ClassUtils.setStaticObject
8 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
9 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
10 | import com.github.kyuubiran.ezxhelper.ObjectHelper.Companion.objectHelper
11 | import com.github.kyuubiran.ezxhelper.ObjectUtils.getObjectOrNull
12 | import com.github.kyuubiran.ezxhelper.ObjectUtils.invokeMethodBestMatch
13 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
14 | import com.yifeplayte.wommo.hook.hooks.BaseHook
15 |
16 | @Suppress("unused")
17 | object RestoreSwitchMinusScreen : BaseHook() {
18 | override val key = "restore_switch_minus_screen"
19 | override fun hook() {
20 | val clazzUtilities = loadClass("com.miui.home.launcher.common.Utilities")
21 | val clazzMiuiBuild = loadClass("miui.os.Build")
22 | val clazzLauncher = loadClass("com.miui.home.launcher.Launcher")
23 | val clazzMiuiHomeSettings = loadClass("com.miui.home.settings.MiuiHomeSettings")
24 | loadClass("com.miui.home.launcher.DeviceConfig").methodFinder()
25 | .filterByName("isUseGoogleMinusScreen").single()
26 | .createHook {
27 | before {
28 | setStaticObject(
29 | loadClass("com.miui.home.launcher.LauncherAssistantCompat"),
30 | "CAN_SWITCH_MINUS_SCREEN",
31 | true
32 | )
33 | }
34 | }
35 | loadClass("com.miui.home.launcher.LauncherAssistantCompat").methodFinder()
36 | .filterByName("newInstance")
37 | .filterByAssignableParamTypes(clazzLauncher).single().createHook {
38 | before {
39 | val isPersonalAssistantGoogle = (invokeStaticMethodBestMatch(
40 | clazzUtilities, "getCurrentPersonalAssistant"
41 | )!! as String) == "personal_assistant_google"
42 | setStaticObject(
43 | clazzMiuiBuild,
44 | "IS_INTERNATIONAL_BUILD",
45 | isPersonalAssistantGoogle
46 | )
47 | }
48 | after {
49 | setStaticObject(clazzMiuiBuild, "IS_INTERNATIONAL_BUILD", false)
50 | }
51 | }
52 | clazzLauncher.declaredConstructors.createHooks {
53 | before {
54 | setStaticObject(clazzMiuiBuild, "IS_INTERNATIONAL_BUILD", true)
55 | }
56 | after {
57 | setStaticObject(clazzMiuiBuild, "IS_INTERNATIONAL_BUILD", false)
58 | }
59 | }
60 | clazzMiuiHomeSettings.methodFinder().filterByName("onCreatePreferences")
61 | .filterByAssignableParamTypes(Bundle::class.java, String::class.java).single()
62 | .createHook {
63 | after { param ->
64 | val mSwitchPersonalAssistant =
65 | getObjectOrNull(param.thisObject, "mSwitchPersonalAssistant")!!
66 | mSwitchPersonalAssistant.objectHelper {
67 | invokeMethodBestMatch(
68 | "setIntent",
69 | null,
70 | Intent("com.miui.home.action.LAUNCHER_PERSONAL_ASSISTANT_SETTING")
71 | )
72 | invokeMethodBestMatch(
73 | "setOnPreferenceChangeListener",
74 | null,
75 | param.thisObject
76 | )
77 | }
78 | invokeMethodBestMatch(param.thisObject, "getPreferenceScreen")!!.objectHelper()
79 | .invokeMethodBestMatch("addPreference", null, mSwitchPersonalAssistant)
80 | }
81 | }
82 | clazzMiuiHomeSettings.methodFinder().filterByName("onResume").single().createHook {
83 | after { param ->
84 | getObjectOrNull(param.thisObject, "mSwitchPersonalAssistant")!!.objectHelper()
85 | .invokeMethodBestMatch("setVisible", null, true)
86 | }
87 | }
88 | }
89 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/home/ShowMIUIWidgetsInAndroidWidgetsList.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.home
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
6 | import com.yifeplayte.wommo.hook.hooks.BaseHook
7 |
8 | @Suppress("unused")
9 | object ShowMIUIWidgetsInAndroidWidgetsList : BaseHook() {
10 | override val key = "show_miui_widgets_in_android_widgets_list"
11 | override fun hook() {
12 | loadClass("com.miui.home.launcher.MIUIWidgetUtil").methodFinder()
13 | .filterByName("isMIUIWidgetSupport").single().createHook {
14 | after { param ->
15 | if (Thread.currentThread().stackTrace.any {
16 | it.className in setOf(
17 | "com.miui.home.launcher.widget.WidgetsVerticalAdapter",
18 | "com.miui.home.launcher.widget.BaseWidgetsVerticalAdapter"
19 | )
20 | }) {
21 | param.result = false
22 | }
23 | }
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/home/UnlockGrids.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.home
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
6 | import com.yifeplayte.wommo.hook.hooks.BaseHook
7 |
8 |
9 | @Suppress("unused")
10 | object UnlockGrids : BaseHook() {
11 | override val key = "unlock_grids"
12 | override fun hook() {
13 | val clazzSet = setOf(
14 | loadClass("com.miui.home.launcher.compat.LauncherCellCountCompatDevice"),
15 | loadClass("com.miui.home.launcher.compat.LauncherCellCountCompatJP"),
16 | loadClass("com.miui.home.launcher.compat.LauncherCellCountCompatNoWord"),
17 | loadClass("com.miui.home.launcher.compat.LauncherCellCountCompatResource")
18 | )
19 | clazzSet.forEach {
20 | it.methodFinder().findSuper().filterByName("getCellCountXMin").first().createHook {
21 | returnConstant(4)
22 | }
23 | it.methodFinder().findSuper().filterByName("getCellCountYMin").first().createHook {
24 | returnConstant(6)
25 | }
26 | it.methodFinder().findSuper().filterByName("getCellCountXMax").first().createHook {
27 | returnConstant(16)
28 | }
29 | it.methodFinder().findSuper().filterByName("getCellCountYMax").first().createHook {
30 | returnConstant(18)
31 | }
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/home/WidgetTransitionAnimation.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.home
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
5 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
6 | import com.yifeplayte.wommo.hook.hooks.BaseHook
7 |
8 | @Suppress("unused")
9 | object WidgetTransitionAnimation : BaseHook() {
10 | override val key = "widget_transition_animation"
11 | override fun hook() {
12 | loadClass("com.miui.home.launcher.LauncherWidgetView").methodFinder()
13 | .filterByName("isUseTransitionAnimation").toList().createHooks {
14 | returnConstant(true)
15 | }
16 | loadClass("com.miui.home.launcher.maml.MaMlWidgetView").methodFinder()
17 | .filterByName("isUseTransitionAnimation").toList().createHooks {
18 | returnConstant(true)
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/packageinstaller/AllowUnofficialSystemApplicationsInstallation.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.packageinstaller
2 |
3 | import android.content.pm.ApplicationInfo
4 | import com.github.kyuubiran.ezxhelper.EzXHelper.safeClassLoader
5 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
6 | import com.yifeplayte.wommo.hook.hooks.BaseHook
7 | import com.yifeplayte.wommo.hook.utils.DexKit.dexKitBridge
8 |
9 | @Suppress("unused")
10 | object AllowUnofficialSystemApplicationsInstallation : BaseHook() {
11 | override val key = "allow_unofficial_system_applications_installation"
12 | override fun hook() {
13 | dexKitBridge.findMethod {
14 | matcher {
15 | paramTypes = listOf("android.content.pm.ApplicationInfo")
16 | returnType = "boolean"
17 | }
18 | }.map { it.getMethodInstance(safeClassLoader) }.createHooks {
19 | before { param ->
20 | (param.args[0] as ApplicationInfo).flags =
21 | (param.args[0] as ApplicationInfo).flags.or(ApplicationInfo.FLAG_SYSTEM)
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/powerkeeper/EnableBatteryMonitorService.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.powerkeeper
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
6 | import com.yifeplayte.wommo.hook.hooks.BaseHook
7 |
8 | @Suppress("unused")
9 | object EnableBatteryMonitorService : BaseHook() {
10 | override val key = "enable_battery_monitor_service"
11 | override fun hook() {
12 | loadClass("com.miui.powerkeeper.utils.Utils").methodFinder()
13 | .filterByName("isDevelopmentOrDebugVersion").single().createHook {
14 | returnConstant(true)
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/screenrecorder/ForceEnableNativePlaybackCapture.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.screenrecorder
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.github.kyuubiran.ezxhelper.MemberExtensions.paramCount
6 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
7 | import com.yifeplayte.wommo.hook.hooks.BaseHook
8 |
9 | @Suppress("unused")
10 | object ForceEnableNativePlaybackCapture : BaseHook() {
11 | override val key = "force_enable_native_playback_capture"
12 | override fun hook() {
13 | loadClass("android.os.SystemProperties").methodFinder().first {
14 | name == "getBoolean"
15 | && paramCount == 2
16 | && parameterTypes[0] == String::class.java
17 | && parameterTypes[1] == Boolean::class.java
18 | }.createHook {
19 | before { param ->
20 | if (param.args[0] == "ro.vendor.audio.playbackcapture.screen") {
21 | param.result = true
22 | }
23 | }
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/screenrecorder/ModifyScreenRecorderConfig.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.screenrecorder
2 |
3 | import com.github.kyuubiran.ezxhelper.EzXHelper.safeClassLoader
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.github.kyuubiran.ezxhelper.MemberExtensions.isFinal
6 | import com.yifeplayte.wommo.hook.hooks.BaseHook
7 | import com.yifeplayte.wommo.hook.utils.DexKit.dexKitBridge
8 |
9 | @Suppress("unused")
10 | object ModifyScreenRecorderConfig : BaseHook() {
11 | override val key = "modify_screen_recorder_config"
12 | private val intArrayBitRateOld = intArrayOf(200, 100, 50, 32, 24, 16, 8, 6, 4, 1)
13 | private val intArrayBitRateNew =
14 | intArrayOf(3600, 2400, 1200, 800, 400, 200, 100, 50, 32, 24, 16, 8, 6, 4, 1)
15 | private val intArrayFrameRateOld = intArrayOf(15, 24, 30, 48, 60, 90)
16 | private val intArrayFrameRateNew = intArrayOf(15, 24, 30, 48, 60, 90, 120, 144)
17 |
18 | override fun hook() {
19 | dexKitBridge.findMethod {
20 | matcher {
21 | usingStrings = listOf("Error when set frame value, maxValue = ")
22 | paramTypes = listOf("int", "int")
23 | }
24 | }.single().getMethodInstance(safeClassLoader).createHook {
25 | before { param ->
26 | param.args[0] = 3600
27 | param.args[1] = 1
28 | param.method.declaringClass.declaredFields.firstOrNull { field ->
29 | field.also {
30 | it.isAccessible = true
31 | }.let { fieldAccessible ->
32 | fieldAccessible.isFinal && fieldAccessible.get(null).let {
33 | runCatching {
34 | (it as IntArray).contentEquals(intArrayFrameRateOld)
35 | }.getOrDefault(false)
36 | }
37 | }
38 | }?.set(null, intArrayFrameRateNew)
39 | }
40 | }
41 | dexKitBridge.findMethod {
42 | matcher {
43 | usingStrings = listOf("defaultBitRate = ")
44 | paramCount = 2
45 | paramTypes = listOf("int", "int")
46 | }
47 | }.singleOrNull()?.getMethodInstance(safeClassLoader)?.createHook {
48 | before { param ->
49 | param.args[0] = 3600
50 | param.args[1] = 1
51 | param.method.declaringClass.declaredFields.firstOrNull { field ->
52 | field.also {
53 | it.isAccessible = true
54 | }.let { fieldAccessible ->
55 | fieldAccessible.isFinal && fieldAccessible.get(null).let {
56 | runCatching {
57 | (it as IntArray).contentEquals(intArrayBitRateOld)
58 | }.getOrDefault(false)
59 | }
60 | }
61 | }?.set(null, intArrayBitRateNew)
62 | }
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/securitycenter/AddAOSPAppInfoEntry.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.securitycenter
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Activity
5 | import android.content.Intent
6 | import android.os.Bundle
7 | import android.os.UserHandle
8 | import android.view.Menu
9 | import android.view.MenuItem
10 | import com.github.kyuubiran.ezxhelper.ClassUtils.invokeStaticMethodBestMatch
11 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
12 | import com.github.kyuubiran.ezxhelper.EzXHelper.appContext
13 | import com.github.kyuubiran.ezxhelper.EzXHelper.hostPackageName
14 | import com.github.kyuubiran.ezxhelper.EzXHelper.initAppContext
15 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
16 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
17 | import com.yifeplayte.wommo.R
18 | import com.yifeplayte.wommo.hook.hooks.BaseHook
19 |
20 | @Suppress("unused")
21 | @SuppressLint("DiscouragedApi")
22 | object AddAOSPAppInfoEntry : BaseHook() {
23 | override val key = "add_aosp_app_info_entry"
24 | private val idIdMiuixActionEndMenuGroup by lazy {
25 | appContext.resources.getIdentifier("miuix_action_end_menu_group", "id", hostPackageName)
26 | }
27 | private val idDrawableIconSettings by lazy {
28 | appContext.resources.getIdentifier("icon_settings", "drawable", hostPackageName)
29 | }
30 | private val idStringAppManagerAppInfoLabel by lazy {
31 | appContext.resources.getIdentifier("app_manager_app_info_label", "string", hostPackageName)
32 | }
33 |
34 | override fun hook() {
35 | val clazzApplicationsDetailsActivity =
36 | loadClass("com.miui.appmanager.ApplicationsDetailsActivity")
37 | clazzApplicationsDetailsActivity.methodFinder().filterByName("onCreateOptionsMenu").single()
38 | .createHook {
39 | after {
40 | val activity = it.thisObject as Activity
41 | initAppContext(activity, true)
42 | val pkgName = activity.intent.getStringExtra("package_name")!!
43 | val myUserId =
44 | invokeStaticMethodBestMatch(UserHandle::class.java, "myUserId") as Int
45 | val uid = activity.intent.getIntExtra("miui.intent.extra.USER_ID", myUserId)
46 | val menuItem = (it.args[0] as Menu).add(
47 | idIdMiuixActionEndMenuGroup, 0, 0, R.string.aosp_app_info
48 | )
49 | menuItem.intent = Intent(Intent.ACTION_MAIN).apply {
50 | val bundle = Bundle().apply {
51 | putString("package", pkgName)
52 | putInt("uid", uid)
53 | }
54 | val stringAppManagerAppInfoLabel =
55 | activity.getString(idStringAppManagerAppInfoLabel)
56 | setClassName("com.android.settings", "com.android.settings.SubSettings")
57 | putExtra(
58 | ":settings:show_fragment",
59 | "com.android.settings.applications.appinfo.AppInfoDashboardFragment"
60 | )
61 | putExtra(":settings:show_fragment_title", stringAppManagerAppInfoLabel)
62 | putExtra(":settings:show_fragment_args", bundle)
63 | }
64 | menuItem.setIcon(idDrawableIconSettings)
65 | menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
66 | }
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/securitycenter/AddAOSPAppManagerEntry.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.securitycenter
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Activity
5 | import android.content.Intent
6 | import android.view.Menu
7 | import android.view.MenuItem
8 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
9 | import com.github.kyuubiran.ezxhelper.EzXHelper.appContext
10 | import com.github.kyuubiran.ezxhelper.EzXHelper.hostPackageName
11 | import com.github.kyuubiran.ezxhelper.EzXHelper.initAppContext
12 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
13 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
14 | import com.yifeplayte.wommo.R
15 | import com.yifeplayte.wommo.hook.hooks.BaseHook
16 |
17 | @Suppress("unused")
18 | @SuppressLint("DiscouragedApi")
19 | object AddAOSPAppManagerEntry : BaseHook() {
20 | override val key = "add_aosp_app_manager_entry"
21 | private val idIdMiuixActionEndMenuGroup by lazy {
22 | appContext.resources.getIdentifier("miuix_action_end_menu_group", "id", hostPackageName)
23 | }
24 | private val idDrawableIconSettings by lazy {
25 | appContext.resources.getIdentifier("icon_settings", "drawable", hostPackageName)
26 | }
27 |
28 | override fun hook() {
29 | val clazzAppManagerMainActivity = loadClass("com.miui.appmanager.AppManagerMainActivity")
30 | clazzAppManagerMainActivity.methodFinder().filterByName("onCreateOptionsMenu").single()
31 | .createHook {
32 | after {
33 | initAppContext(it.thisObject as Activity, true)
34 | val menuItem = (it.args[0] as Menu).add(
35 | idIdMiuixActionEndMenuGroup, 0, 0, R.string.aosp_app_manager
36 | )
37 | menuItem.intent = Intent(Intent.ACTION_MAIN).setClassName(
38 | "com.android.settings",
39 | "com.android.settings.applications.ManageApplications"
40 | )
41 | menuItem.setIcon(idDrawableIconSettings)
42 | menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
43 | }
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/securitycenter/AddOpenByDefaultEntry.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.securitycenter
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Activity
5 | import android.content.Intent
6 | import android.content.pm.verify.domain.DomainVerificationManager
7 | import android.view.Gravity
8 | import android.view.View
9 | import android.widget.LinearLayout
10 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
11 | import com.github.kyuubiran.ezxhelper.EzXHelper.appContext
12 | import com.github.kyuubiran.ezxhelper.EzXHelper.hostPackageName
13 | import com.github.kyuubiran.ezxhelper.EzXHelper.initAppContext
14 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
15 | import com.github.kyuubiran.ezxhelper.ObjectUtils.invokeMethodBestMatch
16 | import com.github.kyuubiran.ezxhelper.finders.ConstructorFinder.`-Static`.constructorFinder
17 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
18 | import com.yifeplayte.wommo.R
19 | import com.yifeplayte.wommo.hook.hooks.BaseHook
20 | import de.robv.android.xposed.XposedHelpers.getAdditionalInstanceField
21 | import de.robv.android.xposed.XposedHelpers.setAdditionalInstanceField
22 |
23 | @Suppress("unused")
24 | @SuppressLint("DiscouragedApi")
25 | object AddOpenByDefaultEntry : BaseHook() {
26 | override val key = "add_open_by_default_entry"
27 | private val domainVerificationManager: DomainVerificationManager by lazy {
28 | appContext.getSystemService(
29 | DomainVerificationManager::class.java
30 | )
31 | }
32 | private val idAmDetailDefault by lazy {
33 | appContext.resources.getIdentifier("am_detail_default", "id", hostPackageName)
34 | }
35 | private val idAmDetailDefaultTitle by lazy {
36 | appContext.resources.getIdentifier("am_detail_default_title", "id", hostPackageName)
37 | }
38 | private val drawableAmCardBgSelector by lazy {
39 | appContext.resources.getIdentifier("am_card_bg_selector", "drawable", hostPackageName)
40 | }
41 | private val dimenAmDetailsItemHeight by lazy {
42 | appContext.resources.getIdentifier("am_details_item_height", "dimen", hostPackageName)
43 | }
44 | private val dimenAmMainPageMarginSe by lazy {
45 | appContext.resources.getIdentifier("am_main_page_margin_se", "dimen", hostPackageName)
46 | }
47 |
48 | override fun hook() {
49 | val clazzApplicationsDetailsActivity =
50 | loadClass("com.miui.appmanager.ApplicationsDetailsActivity")
51 | clazzApplicationsDetailsActivity.methodFinder().filterByName("initView").single()
52 | .createHook {
53 | after { param ->
54 | val activity = param.thisObject as Activity
55 | initAppContext(activity, true)
56 | var cleanOpenByDefaultView: View? = activity.findViewById(idAmDetailDefault)
57 | if (cleanOpenByDefaultView == null) {
58 | val viewAmDetailDefaultTitle =
59 | activity.findViewById(idAmDetailDefaultTitle)
60 | val linearLayout = viewAmDetailDefaultTitle.parent as LinearLayout
61 | cleanOpenByDefaultView =
62 | (loadClass("com.miui.appmanager.widget.AppDetailBannerItemView").constructorFinder()
63 | .filterByParamCount(2).single()
64 | .newInstance(activity, null) as LinearLayout).apply {
65 | gravity = Gravity.CENTER_VERTICAL
66 | orientation = LinearLayout.HORIZONTAL
67 | setBackgroundResource(drawableAmCardBgSelector)
68 | isClickable = true
69 | minimumHeight = activity.resources.getDimensionPixelSize(
70 | dimenAmDetailsItemHeight
71 | )
72 | val dimensionPixelSize =
73 | activity.resources.getDimensionPixelSize(dimenAmMainPageMarginSe)
74 | setPadding(dimensionPixelSize, 0, dimensionPixelSize, 0)
75 | }
76 | cleanOpenByDefaultView.setOnClickListener {
77 | startActionAppOpenByDefaultSettings(activity)
78 | }
79 | linearLayout.addView(cleanOpenByDefaultView)
80 | }
81 | setAdditionalInstanceField(
82 | activity, "cleanOpenByDefaultView", cleanOpenByDefaultView
83 | )
84 | val pkgName = activity.intent.getStringExtra("package_name")!!
85 | val isLinkHandlingAllowed =
86 | domainVerificationManager.getDomainVerificationUserState(
87 | pkgName
88 | )?.isLinkHandlingAllowed ?: false
89 | invokeMethodBestMatch(
90 | cleanOpenByDefaultView, "setTitle", null, R.string.open_by_default
91 | )
92 | invokeMethodBestMatch(
93 | cleanOpenByDefaultView,
94 | "setSummary",
95 | null,
96 | if (isLinkHandlingAllowed) R.string.app_link_open_always else R.string.app_link_open_never
97 | )
98 | }
99 | }
100 | clazzApplicationsDetailsActivity.methodFinder().filterByName("onClick").single()
101 | .createHook {
102 | before { param ->
103 | val activity = param.thisObject as Activity
104 | initAppContext(activity, true)
105 | val clickedView = param.args[0]
106 | val cleanOpenByDefaultView =
107 | getAdditionalInstanceField(activity, "cleanOpenByDefaultView")
108 | if (clickedView == cleanOpenByDefaultView) {
109 | startActionAppOpenByDefaultSettings(activity)
110 | param.result = null
111 | }
112 | }
113 | }
114 | }
115 |
116 | private fun startActionAppOpenByDefaultSettings(activity: Activity) {
117 | val pkgName = activity.intent.getStringExtra("package_name")!!
118 | val intent = Intent().apply {
119 | action = android.provider.Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS
120 | addCategory(Intent.CATEGORY_DEFAULT)
121 | data = android.net.Uri.parse("package:${pkgName}")
122 | addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
123 | addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
124 | }
125 | activity.startActivity(intent)
126 | }
127 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/securitycenter/PreventDisablingDevMode.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.securitycenter
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
6 | import com.yifeplayte.wommo.hook.hooks.BaseHook
7 |
8 | @Suppress("unused")
9 | object PreventDisablingDevMode : BaseHook() {
10 | override val key = "prevent_disabling_dev_mode"
11 | override fun hook() {
12 | loadClass("com.miui.securityscan.model.system.DevModeModel").methodFinder()
13 | .filterByName("optimize").single().createHook {
14 | returnConstant(null)
15 | }
16 | loadClass("com.miui.securityscan.model.system.UsbModel").methodFinder()
17 | .filterByName("optimize").single().createHook {
18 | returnConstant(null)
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/securitycenter/RemoveAdbInstallIntercept.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.securitycenter
2 |
3 | import com.github.kyuubiran.ezxhelper.EzXHelper.safeClassLoader
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.yifeplayte.wommo.hook.hooks.BaseHook
6 | import com.yifeplayte.wommo.hook.utils.DexKit.dexKitBridge
7 |
8 | @Suppress("unused")
9 | object RemoveAdbInstallIntercept : BaseHook() {
10 | override val key = "remove_adb_install_intercept"
11 | override fun hook() {
12 | dexKitBridge.findMethod {
13 | matcher {
14 | usingStrings = listOf("permcenter_install_intercept_enabled")
15 | returnType = "boolean"
16 | }
17 | }.single().getMethodInstance(safeClassLoader).createHook {
18 | returnConstant(false)
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/securitycenter/RemoveGameToast.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.securitycenter
2 |
3 | import com.github.kyuubiran.ezxhelper.EzXHelper.safeClassLoader
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.yifeplayte.wommo.hook.hooks.BaseHook
6 | import com.yifeplayte.wommo.hook.utils.DexKit.dexKitBridge
7 |
8 | @Suppress("unused")
9 | object RemoveGameToast : BaseHook() {
10 | override val key = "remove_game_toast"
11 | override fun hook() {
12 | dexKitBridge.findMethod {
13 | matcher {
14 | usingStrings = listOf("showWildModeToastView: ")
15 | }
16 | }.single().getMethodInstance(safeClassLoader).createHook {
17 | returnConstant(null)
18 | }
19 | dexKitBridge.findMethod {
20 | matcher {
21 | usingStrings = listOf("cancel game toast , isCanceled : ")
22 | }
23 | }.single().getMethodInstance(safeClassLoader).createHook {
24 | returnConstant(null)
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/securitycenter/RemoveReportInApplicationInfo.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.securitycenter
2 |
3 | import com.github.kyuubiran.ezxhelper.EzXHelper.safeClassLoader
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.yifeplayte.wommo.hook.hooks.BaseHook
6 | import com.yifeplayte.wommo.hook.utils.DexKit.dexKitBridge
7 |
8 | @Suppress("unused")
9 | object RemoveReportInApplicationInfo : BaseHook() {
10 | override val key = "remove_report_in_application_info"
11 | override fun hook() {
12 | dexKitBridge.findMethod {
13 | matcher {
14 | usingStrings = listOf("com.xiaomi.market")
15 | declaredClass = "com.miui.appmanager.ApplicationsDetailsActivity"
16 | }
17 | }.singleOrNull()?.getMethodInstance(safeClassLoader)?.createHook {
18 | returnConstant(false)
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/securitycenter/SkipCountDown.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.securitycenter
2 |
3 | import android.os.Handler
4 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
5 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
6 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHooks
7 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
8 | import com.yifeplayte.wommo.hook.hooks.BaseHook
9 |
10 | @Suppress("unused")
11 | object SkipCountDown : BaseHook() {
12 | override val key = "skip_count_down"
13 | override fun hook() {
14 | val mInterceptBaseFragmentCls =
15 | loadClass("com.miui.permcenter.privacymanager.InterceptBaseFragment")
16 | val mInnerClasses = mInterceptBaseFragmentCls.declaredClasses
17 |
18 | loadClass("android.widget.TextView").methodFinder().filterByName("setEnabled").single()
19 | .createHook {
20 | before {
21 | it.args[0] = true
22 | }
23 | }
24 |
25 | mInnerClasses.firstOrNull { Handler::class.java.isAssignableFrom(it) }?.let { clazz ->
26 | clazz.declaredConstructors.filter { it.parameterCount == 2 }.createHooks {
27 | before {
28 | it.args[1] = 0
29 | }
30 | }
31 | clazz.methodFinder().filterByAssignableReturnType(Void.TYPE)
32 | .filterByAssignableParamTypes(Int::class.javaPrimitiveType)
33 | .single().createHook {
34 | before {
35 | it.args[0] = 0
36 | }
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/settings/QuickManageOverlayPermission.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.settings
2 |
3 | import android.app.Activity
4 | import android.provider.Settings
5 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
6 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
7 | import com.github.kyuubiran.ezxhelper.ObjectHelper.Companion.objectHelper
8 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
9 | import com.yifeplayte.wommo.hook.hooks.BaseHook
10 |
11 | @Suppress("unused")
12 | object QuickManageOverlayPermission : BaseHook() {
13 | override val key = "quick_manage_overlay_permission"
14 | override fun hook() {
15 | loadClass("com.android.settings.SettingsActivity").methodFinder()
16 | .filterByName("redirectTabletActivity").single().createHook {
17 | before {
18 | val activity = it.thisObject as Activity
19 | val intent = activity.intent
20 | val action = intent.action
21 | val data = intent.data
22 | if (action != Settings.ACTION_MANAGE_OVERLAY_PERMISSION || data == null || data.scheme != "package") return@before
23 | activity.objectHelper()
24 | .setObjectUntilSuperclass(
25 | "initialFragmentName",
26 | "com.android.settings.applications.appinfo.DrawOverlayDetails"
27 | )
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/settings/QuickManageUnknownAppSources.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.settings
2 |
3 | import android.app.Activity
4 | import android.provider.Settings
5 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
6 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
7 | import com.github.kyuubiran.ezxhelper.ObjectHelper.Companion.objectHelper
8 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
9 | import com.yifeplayte.wommo.hook.hooks.BaseHook
10 |
11 | @Suppress("unused")
12 | object QuickManageUnknownAppSources : BaseHook() {
13 | override val key = "quick_manage_unknown_app_sources"
14 | override fun hook() {
15 | loadClass("com.android.settings.SettingsActivity").methodFinder()
16 | .filterByName("redirectTabletActivity").single().createHook {
17 | before {
18 | val activity = it.thisObject as Activity
19 | val intent = activity.intent
20 | val action = intent.action
21 | val data = intent.data
22 | if (action != Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES || data == null || data.scheme != "package") return@before
23 | activity.objectHelper().setObjectUntilSuperclass(
24 | "initialFragmentName",
25 | "com.android.settings.applications.appinfo.ExternalSourcesDetails"
26 | )
27 | }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/settings/ShowGoogleSettingsEntry.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.settings
2 |
3 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
4 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
5 | import com.github.kyuubiran.ezxhelper.ObjectUtils.invokeMethodBestMatch
6 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
7 | import com.yifeplayte.wommo.hook.hooks.BaseHook
8 | import com.yifeplayte.wommo.utils.Build.IS_INTERNATIONAL_BUILD
9 |
10 | @Suppress("unused")
11 | object ShowGoogleSettingsEntry : BaseHook() {
12 | override val key = "show_google_settings_entry"
13 | override val isEnabled get() = !IS_INTERNATIONAL_BUILD && super.isEnabled
14 | override fun hook() {
15 | loadClass("com.android.settings.MiuiSettings").methodFinder()
16 | .filterByName("updateHeaderList").single().createHook {
17 | after {
18 | if (!IS_INTERNATIONAL_BUILD) invokeMethodBestMatch(
19 | it.thisObject, "AddGoogleSettingsHeaders", null, it.args[0]
20 | )
21 | }
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/settings/ShowNotificationHistoryAndLogEntry.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.settings
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.content.res.Resources
7 | import android.util.AttributeSet
8 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
9 | import com.github.kyuubiran.ezxhelper.EzXHelper.hostPackageName
10 | import com.github.kyuubiran.ezxhelper.HookFactory
11 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
12 | import com.github.kyuubiran.ezxhelper.ObjectHelper.Companion.objectHelper
13 | import com.github.kyuubiran.ezxhelper.ObjectUtils.invokeMethodBestMatch
14 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
15 | import com.yifeplayte.wommo.hook.hooks.BaseHook
16 | import de.robv.android.xposed.callbacks.XCallback.PRIORITY_DEFAULT
17 |
18 | @Suppress("unused")
19 | object ShowNotificationHistoryAndLogEntry : BaseHook() {
20 | override val key = "show_notification_history_and_log_entry"
21 | override fun hook() {
22 | val hook: HookFactory.() -> Unit = {
23 | after {
24 | val thisObject = it.thisObject
25 | val resources = invokeMethodBestMatch(thisObject, "getResources") as Resources
26 | val preferenceManager = invokeMethodBestMatch(thisObject, "getPreferenceManager")!!
27 | val context = invokeMethodBestMatch(preferenceManager, "getContext") as Context
28 | invokeMethodBestMatch(
29 | thisObject, "findPreference", null, "notification_managing"
30 | )?.objectHelper()?.invokeMethodBestMatch("getParent")?.objectHelper {
31 | invokeMethodBestMatch(
32 | "addPreference", null, generatePreferenceScreen(
33 | context,
34 | resources,
35 | "com.android.settings.notification.history.NotificationHistoryActivity",
36 | "notification_history_title"
37 | )
38 | )
39 | invokeMethodBestMatch(
40 | "addPreference", null, generatePreferenceScreen(
41 | context,
42 | resources,
43 | "com.android.settings.Settings\$NotificationStationActivity",
44 | "notification_log_title"
45 | )
46 |
47 | )
48 | }
49 | }
50 | }
51 | runCatching {
52 | loadClass("com.android.settings.NotificationControlCenterSettings").methodFinder()
53 | .filterByName("onCreate").single().createHook(PRIORITY_DEFAULT, hook)
54 | }
55 | runCatching {
56 | loadClass("com.android.settings.NotificationStatusBarSettings").methodFinder()
57 | .filterByName("onCreate").single().createHook(PRIORITY_DEFAULT, hook)
58 | }
59 | }
60 |
61 | @SuppressLint("DiscouragedApi")
62 | private fun generatePreferenceScreen(
63 | context: Context, resources: Resources, className: String, titleIdName: String
64 | ): Any {
65 | val preferenceScreenForNotificationHistory =
66 | loadClass("androidx.preference.Preference").getDeclaredConstructor(
67 | Context::class.java, AttributeSet::class.java
68 | ).newInstance(context, null)
69 | invokeMethodBestMatch(
70 | preferenceScreenForNotificationHistory,
71 | "setIntent",
72 | null,
73 | Intent().apply {
74 | action = Intent.ACTION_MAIN
75 | setClassName(
76 | "com.android.settings", className
77 | )
78 | })
79 | invokeMethodBestMatch(
80 | preferenceScreenForNotificationHistory,
81 | "setTitle",
82 | null,
83 | resources.getIdentifier(titleIdName, "string", hostPackageName)
84 | )
85 | return preferenceScreenForNotificationHistory
86 | }
87 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/yifeplayte/wommo/hook/hooks/singlepackage/settings/ShowWifiPassword.kt:
--------------------------------------------------------------------------------
1 | package com.yifeplayte.wommo.hook.hooks.singlepackage.settings
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Activity
5 | import android.content.DialogInterface
6 | import android.net.wifi.WifiConfiguration
7 | import android.view.View
8 | import android.widget.Button
9 | import com.github.kyuubiran.ezxhelper.ClassHelper.Companion.classHelper
10 | import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
11 | import com.github.kyuubiran.ezxhelper.ClassUtils.newInstanceBestMatch
12 | import com.github.kyuubiran.ezxhelper.EzXHelper.appContext
13 | import com.github.kyuubiran.ezxhelper.EzXHelper.hostPackageName
14 | import com.github.kyuubiran.ezxhelper.EzXHelper.initAppContext
15 | import com.github.kyuubiran.ezxhelper.HookFactory.`-Static`.createHook
16 | import com.github.kyuubiran.ezxhelper.ObjectHelper.Companion.objectHelper
17 | import com.github.kyuubiran.ezxhelper.ObjectUtils.getObjectOrNullAs
18 | import com.github.kyuubiran.ezxhelper.ObjectUtils.invokeMethodBestMatch
19 | import com.github.kyuubiran.ezxhelper.ObjectUtils.setObject
20 | import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
21 | import com.yifeplayte.wommo.hook.hooks.BaseHook
22 | import com.yifeplayte.wommo.hook.utils.ClipboardUtils.copy
23 | import de.robv.android.xposed.XposedHelpers
24 |
25 |
26 | @Suppress("unused", "DEPRECATION")
27 | @SuppressLint("DiscouragedApi")
28 | object ShowWifiPassword : BaseHook() {
29 | override val key = "show_wifi_password"
30 | override val isEnabled = true
31 | private val idStringWifiSsid by lazy {
32 | appContext.resources.getIdentifier("wifi_ssid", "string", hostPackageName)
33 | }
34 | private val idStringWifiSecurity by lazy {
35 | appContext.resources.getIdentifier("wifi_security", "string", hostPackageName)
36 | }
37 | private val idStringWifiPassword by lazy {
38 | appContext.resources.getIdentifier("wifi_password", "string", hostPackageName)
39 | }
40 | private val idStringWifiDetailsTitle by lazy {
41 | appContext.resources.getIdentifier("wifi_details_title", "string", hostPackageName)
42 | }
43 | private val idStringWifiMenuForget by lazy {
44 | appContext.resources.getIdentifier("wifi_menu_forget", "string", hostPackageName)
45 | }
46 | private val idStringCopy by lazy {
47 | appContext.resources.getIdentifier("copy", "string", hostPackageName)
48 | }
49 | private val idStringPreferenceCopied by lazy {
50 | appContext.resources.getIdentifier("preference_copied", "string", hostPackageName)
51 | }
52 | private val idStyleAlertDialogThemeDayNight by lazy {
53 | appContext.resources.getIdentifier("AlertDialog_Theme_DayNight", "style", hostPackageName)
54 | }
55 | private val idIdBtnDelete by lazy {
56 | appContext.resources.getIdentifier("btn_delete", "id", hostPackageName)
57 | }
58 |
59 | override fun hook() {
60 | loadClass("com.android.settings.wifi.SavedAccessPointPreference").methodFinder()
61 | .filterByName("onBindViewHolder").single().createHook {
62 | after { param ->
63 | val view = XposedHelpers.getObjectField(param.thisObject, "mView") as View
64 | val button = view.findViewById