├── .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 - Works On My Machine Only 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