├── .github └── workflows │ └── main.yml ├── .gitignore ├── .idea ├── .gitignore ├── .name ├── AndroidProjectSystem.xml ├── appInsightsSettings.xml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── compiler.xml ├── deploymentTargetSelector.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── kotlinc.xml ├── migrations.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── android-stub ├── .gitignore ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ ├── android │ ├── app │ │ ├── IActivityTaskManager.java │ │ └── ITaskStackListener.java │ ├── content │ │ └── pm │ │ │ ├── IPackageManagerHidden.java │ │ │ ├── PackageManagerHidden.java │ │ │ └── UserInfo.java │ ├── hardware │ │ └── input │ │ │ └── IInputManager.java │ ├── view │ │ ├── IRotationWatcher.java │ │ ├── IWindowManager.java │ │ ├── WindowLayoutParamsHidden.java │ │ └── WindowManagerHidden.java │ └── window │ │ └── TaskSnapshot.java │ └── com │ └── android │ └── internal │ └── statusbar │ └── IStatusBarService.java ├── app ├── .gitignore ├── build.gradle.kts ├── debug │ ├── app-debug.apk │ └── output-metadata.json ├── proguard-rules.pro ├── release │ ├── app-release.apk │ ├── app-release.zip │ ├── baselineProfiles │ │ ├── 0 │ │ │ └── app-release.dm │ │ └── 1 │ │ │ └── app-release.dm │ └── output-metadata.json └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── mja │ │ └── reyamf │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── aidl │ │ └── com │ │ │ └── mja │ │ │ └── reyamf │ │ │ └── xposed │ │ │ ├── IOpenCountListener.aidl │ │ │ └── IYAMFManager.aidl │ ├── assets │ │ └── xposed_init │ ├── java │ │ ├── android │ │ │ └── app │ │ │ │ └── ITaskStackListenerProxy.kt │ │ └── com │ │ │ ├── mja │ │ │ └── reyamf │ │ │ │ ├── Application.kt │ │ │ │ ├── common │ │ │ │ ├── Utils.kt │ │ │ │ └── model │ │ │ │ │ ├── AppInfo.kt │ │ │ │ │ ├── Config.kt │ │ │ │ │ ├── FavApps.kt │ │ │ │ │ └── StartCmd.kt │ │ │ │ ├── manager │ │ │ │ ├── Application.kt │ │ │ │ ├── adapter │ │ │ │ │ ├── AppListAdapter.kt │ │ │ │ │ ├── SideBarAdapter.kt │ │ │ │ │ └── VerticalSpaceItemDecoration.kt │ │ │ │ ├── broadcastreceiver │ │ │ │ │ └── BootReceiver.kt │ │ │ │ ├── providers │ │ │ │ │ └── ServiceProvider.kt │ │ │ │ ├── services │ │ │ │ │ ├── AccessibilityService.kt │ │ │ │ │ ├── CurrentToFloatingService.kt │ │ │ │ │ ├── QSEnterWindow.kt │ │ │ │ │ ├── QSNewWindowService.kt │ │ │ │ │ ├── QSResetAllWindow.kt │ │ │ │ │ ├── SidebarHiderService.kt │ │ │ │ │ └── YAMFManagerProxy.kt │ │ │ │ ├── sidebar │ │ │ │ │ └── SideBar.kt │ │ │ │ ├── ui │ │ │ │ │ ├── CurrentToFloatingActivity.kt │ │ │ │ │ ├── main │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ │ └── setting │ │ │ │ │ │ └── SettingActivity.kt │ │ │ │ └── utils │ │ │ │ │ ├── AppContext.kt │ │ │ │ │ ├── TipUtil.kt │ │ │ │ │ └── Utils.kt │ │ │ │ └── xposed │ │ │ │ ├── hook │ │ │ │ ├── HookLauncher.kt │ │ │ │ ├── HookPermission.kt │ │ │ │ ├── HookPermissionDefault.kt │ │ │ │ └── HookSystem.kt │ │ │ │ ├── services │ │ │ │ ├── UserService.kt │ │ │ │ └── YAMFManager.kt │ │ │ │ ├── ui │ │ │ │ └── window │ │ │ │ │ ├── AppListWindow.kt │ │ │ │ │ └── AppWindow.kt │ │ │ │ └── utils │ │ │ │ ├── AppInfoCache.kt │ │ │ │ ├── Instances.kt │ │ │ │ ├── RunMainThreadQueue.kt │ │ │ │ ├── TipUtil.kt │ │ │ │ └── Utils.kt │ │ │ └── qauxv │ │ │ ├── ui │ │ │ └── CommonContextWrapper.java │ │ │ └── util │ │ │ ├── Initiator.java │ │ │ └── SavedInstanceStatePatchedClassReferencer.java │ └── res │ │ ├── drawable │ │ ├── a_bg.xml │ │ ├── bar_corners_bg.xml │ │ ├── baseline_apps_24.xml │ │ ├── baseline_keyboard_double_arrow_left_24.xml │ │ ├── baseline_restart_alt_24.xml │ │ ├── demo.gif │ │ ├── ic_back.xml │ │ ├── ic_close_24.xml │ │ ├── ic_error_outline_24.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_maximize.xml │ │ ├── ic_minimize.xml │ │ ├── ic_picture_in_picture_alt_24.xml │ │ ├── ic_round_check_circle_24.xml │ │ ├── ic_settings_24.xml │ │ ├── ic_warning_amber_24.xml │ │ ├── menu_bg.xml │ │ ├── three_dot_horiz.xml │ │ └── work_icon.xml │ │ ├── layout-land │ │ └── sidebar_itemview.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_setting.xml │ │ ├── item_app.xml │ │ ├── sidebar_itemview.xml │ │ ├── sidebar_layout.xml │ │ ├── window_app.xml │ │ └── window_app_list.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-anydpi │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night │ │ ├── colors.xml │ │ └── themes.xml │ │ ├── values-zh │ │ └── strings.xml │ │ ├── values │ │ ├── arrays.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── ic_launcher_background.xml │ │ ├── ids.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── accessibility_service_config.xml │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ └── test │ └── java │ └── com │ └── mja │ └── reyamf │ └── ExampleUnitTest.kt ├── build.gradle.kts ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | 6 | jobs: 7 | contrib-readme-job: 8 | runs-on: ubuntu-latest 9 | name: A job to automate contrib in readme 10 | permissions: 11 | contents: write 12 | pull-requests: write 13 | steps: 14 | - name: Contribute List 15 | uses: akhilmhdh/contributors-readme-action@v2.3.10 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | reYAMF -------------------------------------------------------------------------------- /.idea/AndroidProjectSystem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/appInsightsSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 39 | 40 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 119 | 120 | 122 | 123 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Chat](https://img.shields.io/badge/Chat-Telegram-blue.svg?logo=telegram)](https://t.me/+HjGegWE9jBM0N2Rl) 2 | [![Size](https://img.shields.io/github/languages/code-size/JuanArton/reYAMF)](https://github.com/JuanArton/reYAMF) 3 | 4 | # reYAMF 5 | 6 | A fork of YAMF (forked from [YAMFSquared](https://github.com/kaii-lb/YAMFsquared), actually), with my changes. 7 | 8 | (project recreated. Check main-old branch to see previous commit by duzhaokun123 and kaii-lb) 9 | 10 | ## Requirements 11 | - Android 13+ (>= api 33) 12 | - LSPosed 13 | 14 | ## Features 15 | - Launch from recents app icon 16 | - Launch by home button long press (read further) 17 | - Launch from app icon long press from homescreen/app drawer 18 | - Launch from taskbar 19 | - Multiple window support 20 | - Minimize window to take up less space 21 | - Resize window 22 | - FLAG_SECURE support 23 | - Quick Settings tiles 24 | - App Rotation detection 25 | - Custom default window size 26 | - Bunch of others in app :D 27 | 28 | ## My Changes 29 | - Fix crash on Android 15 30 | - Added sidebar. From app list window, long press app icon until the phone vibrate to add app to sidebar. 31 | - Removed custom dpi, replace with auto density according to window size. Increase 'Reduce DPI' number from setting if you feel the app appearance is too big. Setting this value too big may cause crash (I recommended value between 50-100) 32 | 33 | ## Launch by home button long press (or swipe gesture) 34 | - Be willing to give up google assistant 35 | - Go to Settings -> Assistant App 36 | - Change it to reYAMF 37 | - Profit 38 | 39 | ## How to install 40 | - Grab the latest APK from the [releases section](https://github.com/JuanArton/YAMFsquared/releases) 41 | - Install it 42 | - Enable module in LSPosed 43 | - Go to Accessibility Settings and enable reYAMF accessibility service 44 | - Reboot 45 | 46 | ## "API" 47 | - Broadcast `com.mja.reyamf.action.CURRENT_TO_WINDOW` to float the currently visible app 48 | - Maybe more to come 49 | 50 | ## Issues 51 | - The system will crash if the module is different from the injected version, its an xposed thing 52 | - Some apps can't seem to launch in small windows 53 | - Some apps scale abnormally at certain sizes 54 | - Some app restart while being resized. (Will fix by adding lock DPI option) 55 | 56 | ## TODO 57 | - Minimize to app icon (half done? long press minimize button to try) 58 | - RtL support 59 | - Lock window DPI option 60 | - You tell me 61 | 62 | ## Contributors List 63 | 64 | 65 | 66 | 67 | 74 | 81 | 88 | 89 | 90 |
68 | 69 | JuanArton 70 |
71 | Juan Arton 72 |
73 |
75 | 76 | duzhaokun123 77 |
78 | o0kam1 79 |
80 |
82 | 83 | No-22-Github 84 |
85 | No.22 86 |
87 |
91 | 92 | 93 | ## Special Thanks 94 | - MASSIVE thanks to [duzhaokun123](https://github.com/duzhaokun123) and [kaii-lb](https://github.com/kaii-lb/YAMFsquared) 95 | 96 | - [AOSP](https://source.android.com/) 97 | - [EzXHelper](https://github.com/KyuubiRan/EzXHelper) 98 | - [FlexboxLayout](https://github.com/google/flexbox-layout) 99 | - [Hide-My-Applist](https://github.com/Dr-TSNG/Hide-My-Applist) 100 | - [LSPosed](https://github.com/LSPosed/LSPosed) 101 | - [Material](https://material.io/) 102 | - [Mi-FreeForm](https://github.com/sunshine0523/Mi-FreeForm) 103 | - [QAuxiliary](https://github.com/cinit/QAuxiliary) 104 | - [ViewBindingUtil](https://github.com/matsudamper/ViewBindingUtil) 105 | - [gson](https://github.com/google/gson) 106 | - [xposed](https://forum.xda-developers.com/xposed) 107 | -------------------------------------------------------------------------------- /android-stub/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /android-stub/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.library") 3 | } 4 | 5 | android { 6 | compileSdk = 35 7 | 8 | defaultConfig { 9 | minSdk = 31 10 | lint.targetSdk = 35 11 | 12 | consumerProguardFiles("consumer-rules.pro") 13 | } 14 | 15 | buildTypes { 16 | getByName("release") { 17 | isMinifyEnabled = false 18 | proguardFiles( 19 | getDefaultProguardFile("proguard-android-optimize.txt"), 20 | "proguard-rules.pro" 21 | ) 22 | } 23 | } 24 | compileOptions { 25 | sourceCompatibility = JavaVersion.VERSION_11 26 | targetCompatibility = JavaVersion.VERSION_11 27 | } 28 | 29 | namespace = "com.mja.android_stub" 30 | } 31 | 32 | dependencies { 33 | annotationProcessor(libs.rikka.annotation.processor) 34 | compileOnly(libs.rikka.annotation) 35 | compileOnly(libs.androidx.annotation) 36 | compileOnly(libs.rikka.hidden.stub) 37 | } 38 | -------------------------------------------------------------------------------- /android-stub/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/android-stub/consumer-rules.pro -------------------------------------------------------------------------------- /android-stub/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /android-stub/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android-stub/src/main/java/android/app/IActivityTaskManager.java: -------------------------------------------------------------------------------- 1 | package android.app; 2 | 3 | import android.os.Binder; 4 | import android.os.IBinder; 5 | import android.os.IInterface; 6 | import android.os.RemoteException; 7 | 8 | import java.util.List; 9 | 10 | public interface IActivityTaskManager extends IInterface { 11 | void moveRootTaskToDisplay(int taskId, int displayId) throws RemoteException; 12 | 13 | void registerTaskStackListener(ITaskStackListener listener) throws RemoteException; 14 | 15 | void unregisterTaskStackListener(ITaskStackListener listener) throws RemoteException; 16 | 17 | ActivityManager.TaskDescription getTaskDescription(int taskId) throws RemoteException; 18 | 19 | List getAllRootTaskInfosOnDisplay(int displayId) throws RemoteException; 20 | 21 | abstract class Stub extends Binder implements IActivityTaskManager { 22 | public static IActivityTaskManager asInterface(IBinder obj) { 23 | throw new UnsupportedOperationException(); 24 | } 25 | 26 | @Override 27 | public IBinder asBinder() { 28 | throw new UnsupportedOperationException(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /android-stub/src/main/java/android/app/ITaskStackListener.java: -------------------------------------------------------------------------------- 1 | package android.app; 2 | 3 | import android.content.ComponentName; 4 | import android.hardware.display.IDisplayManager; 5 | import android.os.Binder; 6 | import android.os.IBinder; 7 | import android.os.IInterface; 8 | import android.os.RemoteException; 9 | import android.window.TaskSnapshot; 10 | 11 | public interface ITaskStackListener extends IInterface { 12 | // https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/app/ITaskStackListener.aidl 13 | abstract class Stub extends Binder implements ITaskStackListener { 14 | @Override 15 | public IBinder asBinder() { 16 | throw new UnsupportedOperationException(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /android-stub/src/main/java/android/content/pm/IPackageManagerHidden.java: -------------------------------------------------------------------------------- 1 | package android.content.pm; 2 | 3 | import android.content.ComponentName; 4 | import android.os.RemoteException; 5 | 6 | import androidx.annotation.RequiresApi; 7 | 8 | import dev.rikka.tools.refine.RefineAs; 9 | 10 | @RefineAs(IPackageManager.class) 11 | public interface IPackageManagerHidden { 12 | ActivityInfo getActivityInfo(ComponentName className, long flags, int userId) 13 | throws RemoteException; 14 | 15 | ActivityInfo getActivityInfo(ComponentName className, int flags, int userId) 16 | throws RemoteException; 17 | } 18 | -------------------------------------------------------------------------------- /android-stub/src/main/java/android/content/pm/PackageManagerHidden.java: -------------------------------------------------------------------------------- 1 | package android.content.pm; 2 | 3 | import android.content.Intent; 4 | 5 | import java.util.List; 6 | 7 | import dev.rikka.tools.refine.RefineAs; 8 | 9 | @RefineAs(PackageManager.class) 10 | public abstract class PackageManagerHidden { 11 | public abstract List queryIntentActivitiesAsUser(Intent intent, int flags, int userId); 12 | 13 | public abstract PackageInfo getPackageInfoAsUser(String packageName, 14 | int flags, int userId) throws PackageManager.NameNotFoundException; 15 | 16 | public abstract ApplicationInfo getApplicationInfoAsUser(String packageName, 17 | int flags, int userId) throws PackageManager.NameNotFoundException; 18 | } 19 | -------------------------------------------------------------------------------- /android-stub/src/main/java/android/content/pm/UserInfo.java: -------------------------------------------------------------------------------- 1 | package android.content.pm; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | import android.os.UserHandle; 6 | 7 | public class UserInfo { 8 | 9 | public static final int FLAG_MANAGED_PROFILE = 0x00000020; 10 | 11 | public int id; 12 | public String name; 13 | public int flags; 14 | public int serialNumber; 15 | 16 | public String userType; 17 | 18 | public boolean isPrimary() { 19 | throw new RuntimeException("STUB"); 20 | } 21 | 22 | public boolean isAdmin() { 23 | throw new RuntimeException("STUB"); 24 | } 25 | 26 | public boolean isGuest() { 27 | throw new RuntimeException("STUB"); 28 | } 29 | 30 | public boolean isRestricted() { 31 | throw new RuntimeException("STUB"); 32 | } 33 | 34 | public boolean isProfile() { 35 | throw new RuntimeException("STUB"); 36 | } 37 | 38 | public boolean isManagedProfile() { 39 | throw new RuntimeException("STUB"); 40 | } 41 | 42 | public boolean isEnabled() { 43 | throw new RuntimeException("STUB"); 44 | } 45 | 46 | public UserHandle getUserHandle() { 47 | throw new RuntimeException("STUB"); 48 | } 49 | 50 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 51 | 52 | public UserInfo createFromParcel(Parcel in) { 53 | throw new UnsupportedOperationException(); 54 | } 55 | 56 | public UserInfo[] newArray(int size) { 57 | throw new UnsupportedOperationException(); 58 | } 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /android-stub/src/main/java/android/hardware/input/IInputManager.java: -------------------------------------------------------------------------------- 1 | package android.hardware.input; 2 | 3 | import android.os.Binder; 4 | import android.os.IBinder; 5 | import android.os.IInterface; 6 | import android.os.RemoteException; 7 | import android.view.InputEvent; 8 | 9 | public interface IInputManager extends IInterface { 10 | boolean injectInputEvent(InputEvent ev, int mode) throws RemoteException; 11 | 12 | abstract class Stub extends Binder implements IInputManager { 13 | public static IInputManager asInterface(IBinder obj) { 14 | throw new UnsupportedOperationException(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /android-stub/src/main/java/android/view/IRotationWatcher.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | import android.os.Binder; 4 | 5 | public interface IRotationWatcher { 6 | void onRotationChanged(int rotation); 7 | 8 | abstract class Stub extends Binder implements IRotationWatcher { 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /android-stub/src/main/java/android/view/IWindowManager.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | import android.os.Binder; 4 | import android.os.IBinder; 5 | import android.os.IInterface; 6 | import android.os.RemoteException; 7 | 8 | public interface IWindowManager extends IInterface { 9 | 10 | int watchRotation(IRotationWatcher watcher, int displayId) throws RemoteException; 11 | 12 | void removeRotationWatcher(IRotationWatcher watcher) throws RemoteException; 13 | 14 | abstract class Stub extends Binder implements IWindowManager { 15 | public static IWindowManager asInterface(IBinder obj) { 16 | throw new UnsupportedOperationException(); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /android-stub/src/main/java/android/view/WindowLayoutParamsHidden.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | import dev.rikka.tools.refine.RefineAs; 4 | 5 | @RefineAs(WindowManager.LayoutParams.class) 6 | public class WindowLayoutParamsHidden { 7 | public int privateFlags; 8 | 9 | public static final int PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY = 0x00100000; 10 | } 11 | -------------------------------------------------------------------------------- /android-stub/src/main/java/android/view/WindowManagerHidden.java: -------------------------------------------------------------------------------- 1 | package android.view; 2 | 3 | import androidx.annotation.IntDef; 4 | 5 | import dev.rikka.tools.refine.RefineAs; 6 | 7 | @RefineAs(WindowManager.class) 8 | public interface WindowManagerHidden { 9 | /** 10 | * Display IME Policy: The IME should appear on the local display. 11 | * @hide 12 | */ 13 | int DISPLAY_IME_POLICY_LOCAL = 0; 14 | 15 | /** 16 | * Display IME Policy: The IME should appear on the fallback display. 17 | * @hide 18 | */ 19 | int DISPLAY_IME_POLICY_FALLBACK_DISPLAY = 1; 20 | 21 | /** 22 | * Display IME Policy: The IME should be hidden. 23 | * 24 | * Setting this policy will prevent the IME from making a connection. This 25 | * will prevent any IME from receiving metadata about input. 26 | * @hide 27 | */ 28 | int DISPLAY_IME_POLICY_HIDE = 2; 29 | 30 | /** 31 | * @hide 32 | */ 33 | @IntDef({ 34 | DISPLAY_IME_POLICY_LOCAL, 35 | DISPLAY_IME_POLICY_FALLBACK_DISPLAY, 36 | DISPLAY_IME_POLICY_HIDE, 37 | }) 38 | @interface DisplayImePolicy {} 39 | 40 | /** 41 | * Sets the policy for how the display should show IME. 42 | * 43 | * @param displayId Display ID. 44 | * @param imePolicy Indicates the policy for how the display should show IME. 45 | * @hide 46 | */ 47 | default void setDisplayImePolicy(int displayId, @DisplayImePolicy int imePolicy) { 48 | } 49 | 50 | /** 51 | * Indicates the policy for how the display should show IME. 52 | * 53 | * @param displayId The id of the display. 54 | * @return The policy for how the display should show IME. 55 | * @hide 56 | */ 57 | default @DisplayImePolicy int getDisplayImePolicy(int displayId) { 58 | return DISPLAY_IME_POLICY_FALLBACK_DISPLAY; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /android-stub/src/main/java/android/window/TaskSnapshot.java: -------------------------------------------------------------------------------- 1 | package android.window; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | public class TaskSnapshot implements Parcelable { 7 | protected TaskSnapshot(Parcel in) {} 8 | 9 | @Override 10 | public void writeToParcel(Parcel dest, int flags) {} 11 | 12 | @Override 13 | public int describeContents() { 14 | return 0; 15 | } 16 | 17 | public static final Creator CREATOR = new Creator() { 18 | @Override 19 | public TaskSnapshot createFromParcel(Parcel in) { 20 | return new TaskSnapshot(in); 21 | } 22 | 23 | @Override 24 | public TaskSnapshot[] newArray(int size) { 25 | return new TaskSnapshot[size]; 26 | } 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /android-stub/src/main/java/com/android/internal/statusbar/IStatusBarService.java: -------------------------------------------------------------------------------- 1 | package com.android.internal.statusbar; 2 | 3 | import android.os.Binder; 4 | import android.os.IBinder; 5 | import android.os.IInterface; 6 | 7 | public interface IStatusBarService extends IInterface { 8 | 9 | void collapsePanels(); 10 | 11 | abstract class Stub extends Binder implements IStatusBarService { 12 | public static IStatusBarService asInterface(IBinder obj) { 13 | throw new UnsupportedOperationException(); 14 | } 15 | 16 | @Override 17 | public IBinder asBinder() { 18 | throw new UnsupportedOperationException(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.io.ByteArrayOutputStream 2 | 3 | plugins { 4 | alias(libs.plugins.android.application) 5 | alias(libs.plugins.kotlin.android) 6 | alias(libs.plugins.rikka.tools.refine) 7 | id("kotlin-parcelize") 8 | } 9 | 10 | android { 11 | val buildTime = System.currentTimeMillis() 12 | val baseVersionName = "0.9.8" 13 | namespace = "com.mja.reyamf" 14 | compileSdk = 35 15 | 16 | defaultConfig { 17 | applicationId = "com.mja.reyamf" 18 | minSdk = 33 19 | targetSdk = 35 20 | versionCode = 1 21 | versionName = "$baseVersionName-git.$gitHash${if (isDirty) "-dirty" else ""}" 22 | 23 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 24 | 25 | buildConfigField("long", "BUILD_TIME", buildTime.toString()) 26 | } 27 | packaging { 28 | resources.excludes.addAll( 29 | arrayOf( 30 | "META-INF/**", 31 | "kotlin/**" 32 | ) 33 | ) 34 | } 35 | buildTypes { 36 | release { 37 | isMinifyEnabled = false 38 | isShrinkResources = false 39 | proguardFiles( 40 | getDefaultProguardFile("proguard-android-optimize.txt"), 41 | "proguard-rules.pro" 42 | ) 43 | } 44 | } 45 | compileOptions { 46 | sourceCompatibility = JavaVersion.VERSION_11 47 | targetCompatibility = JavaVersion.VERSION_11 48 | } 49 | kotlinOptions { 50 | jvmTarget = "11" 51 | languageVersion = "2.0" 52 | } 53 | buildFeatures { 54 | viewBinding = true 55 | aidl = true 56 | buildConfig = true 57 | } 58 | lint { 59 | abortOnError = false 60 | } 61 | } 62 | 63 | dependencies { 64 | 65 | implementation(libs.androidx.core.ktx) 66 | implementation(libs.androidx.appcompat) 67 | implementation(libs.material) 68 | implementation(libs.androidx.activity) 69 | implementation(libs.androidx.constraintlayout) 70 | implementation(libs.androidx.wear) 71 | testImplementation(libs.junit) 72 | androidTestImplementation(libs.androidx.junit) 73 | androidTestImplementation(libs.androidx.espresso.core) 74 | implementation(libs.androidx.preference.ktx) 75 | 76 | compileOnly(project(":android-stub")) 77 | compileOnly(libs.rikka.hidden.stub) 78 | implementation(libs.rikka.hidden.compat) 79 | 80 | //never upgrade until new extension function 81 | //noinspection GradleDependency 82 | implementation(libs.ezxhelper) 83 | compileOnly(libs.xposed.api) 84 | 85 | //lifecycle 86 | implementation(libs.androidx.lifecycle.viewmodel.ktx) 87 | implementation(libs.androidx.lifecycle.livedata.ktx) 88 | 89 | //flexbox 90 | implementation(libs.flexbox) 91 | 92 | //dynamicanimation 93 | implementation(libs.androidx.dynamicanimation.ktx) 94 | 95 | //gson 96 | implementation(libs.gson) 97 | 98 | //material 99 | implementation(libs.material) 100 | 101 | //glide 102 | implementation (libs.glide) 103 | 104 | // byte buddy 105 | implementation(libs.byte.buddy.android) 106 | } 107 | 108 | val gitHash: String 109 | get() { 110 | val out = ByteArrayOutputStream() 111 | val cmd = exec { 112 | commandLine("git", "rev-parse", "--short", "HEAD") 113 | standardOutput = out 114 | isIgnoreExitValue = true 115 | } 116 | return if (cmd.exitValue == 0) 117 | out.toString().trim() 118 | else 119 | "(error)" 120 | } 121 | 122 | val isDirty: Boolean 123 | get() { 124 | val out = ByteArrayOutputStream() 125 | exec { 126 | commandLine("git", "diff", "--stat") 127 | standardOutput = out 128 | isIgnoreExitValue = true 129 | } 130 | return out.size() != 0 131 | } -------------------------------------------------------------------------------- /app/debug/app-debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/debug/app-debug.apk -------------------------------------------------------------------------------- /app/debug/output-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "artifactType": { 4 | "type": "APK", 5 | "kind": "Directory" 6 | }, 7 | "applicationId": "com.mja.reyamf", 8 | "variantName": "debug", 9 | "elements": [ 10 | { 11 | "type": "SINGLE", 12 | "filters": [], 13 | "attributes": [], 14 | "versionCode": 1, 15 | "versionName": "0.9.2-git.2b15d16-dirty", 16 | "outputFile": "app-debug.apk" 17 | } 18 | ], 19 | "elementType": "File", 20 | "minSdkVersionForDexing": 33 21 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class com.mja.reyamf.** { *; } 2 | -keepclassmembers class com.android.dx.dex.cf.CfTranslator { public static *** translate(...); } 3 | -dontwarn edu.umd.cs.findbugs.annotations.SuppressFBWarnings 4 | -dontwarn javax.annotation.Nonnull -------------------------------------------------------------------------------- /app/release/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/release/app-release.apk -------------------------------------------------------------------------------- /app/release/app-release.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/release/app-release.zip -------------------------------------------------------------------------------- /app/release/baselineProfiles/0/app-release.dm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/release/baselineProfiles/0/app-release.dm -------------------------------------------------------------------------------- /app/release/baselineProfiles/1/app-release.dm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/release/baselineProfiles/1/app-release.dm -------------------------------------------------------------------------------- /app/release/output-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "artifactType": { 4 | "type": "APK", 5 | "kind": "Directory" 6 | }, 7 | "applicationId": "com.mja.reyamf", 8 | "variantName": "release", 9 | "elements": [ 10 | { 11 | "type": "SINGLE", 12 | "filters": [], 13 | "attributes": [], 14 | "versionCode": 1, 15 | "versionName": "0.9.7-git.ced9113", 16 | "outputFile": "app-release.apk" 17 | } 18 | ], 19 | "elementType": "File", 20 | "baselineProfiles": [ 21 | { 22 | "minApi": 28, 23 | "maxApi": 30, 24 | "baselineProfiles": [ 25 | "baselineProfiles/1/app-release.dm" 26 | ] 27 | }, 28 | { 29 | "minApi": 31, 30 | "maxApi": 2147483647, 31 | "baselineProfiles": [ 32 | "baselineProfiles/0/app-release.dm" 33 | ] 34 | } 35 | ], 36 | "minSdkVersionForDexing": 33 37 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/mja/reyamf/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.mja.reyamf", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 19 | 20 | 23 | 24 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 44 | 50 | 51 | 52 | 53 | 54 | 60 | 61 | 62 | 63 | 64 | 70 | 71 | 72 | 73 | 74 | 79 | 80 | 81 | 82 | 83 | 86 | 87 | 88 | 89 | 93 | 94 | 98 | 99 | 100 | 101 | 102 | 103 | 106 | 109 | 112 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /app/src/main/aidl/com/mja/reyamf/xposed/IOpenCountListener.aidl: -------------------------------------------------------------------------------- 1 | // IOpenCountListener.aidl 2 | package com.mja.reyamf.xposed; 3 | 4 | // Declare any non-default types here with import statements 5 | 6 | interface IOpenCountListener { 7 | void onUpdate(int count); 8 | } -------------------------------------------------------------------------------- /app/src/main/aidl/com/mja/reyamf/xposed/IYAMFManager.aidl: -------------------------------------------------------------------------------- 1 | // IYAMFManager.aidl 2 | package com.mja.reyamf.xposed; 3 | 4 | import com.mja.reyamf.xposed.IOpenCountListener; 5 | // Declare any non-default types here with import statements 6 | 7 | interface IYAMFManager { 8 | String getVersionName(); 9 | 10 | int getVersionCode(); 11 | 12 | int getUid(); 13 | 14 | void createWindow(); 15 | 16 | long getBuildTime(); 17 | 18 | String getConfigJson(); 19 | 20 | void updateConfig(String newConfig); 21 | 22 | void registerOpenCountListener(IOpenCountListener iOpenCountListener); 23 | 24 | void unregisterOpenCountListener(IOpenCountListener iOpenCountListener); 25 | 26 | void openAppList(); 27 | 28 | void currentToWindow(); 29 | 30 | void resetAllWindow(); 31 | 32 | void launchSideBar(); 33 | 34 | void killSideBar(); 35 | } -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | com.mja.reyamf.xposed.hook.HookSystem 2 | com.mja.reyamf.xposed.hook.HookLauncher 3 | com.mja.reyamf.xposed.hook.HookPermission 4 | com.mja.reyamf.xposed.hook.HookPermissionDefault -------------------------------------------------------------------------------- /app/src/main/java/android/app/ITaskStackListenerProxy.kt: -------------------------------------------------------------------------------- 1 | package android.app 2 | 3 | import android.util.Log 4 | import com.github.kyuubiran.ezxhelper.init.EzXHelperInit 5 | import com.github.kyuubiran.ezxhelper.init.InitFields 6 | import com.mja.reyamf.xposed.ui.window.AppWindow 7 | import com.mja.reyamf.xposed.ui.window.AppWindow.Companion.TAG 8 | import com.mja.reyamf.xposed.utils.byteBuddyStrategy 9 | import net.bytebuddy.ByteBuddy 10 | import net.bytebuddy.implementation.MethodDelegation 11 | import net.bytebuddy.implementation.bind.annotation.AllArguments 12 | import net.bytebuddy.implementation.bind.annotation.Origin 13 | import net.bytebuddy.implementation.bind.annotation.RuntimeType 14 | import net.bytebuddy.matcher.ElementMatchers 15 | import java.lang.reflect.Method 16 | 17 | object ITaskStackListenerProxy { 18 | fun newInstance( 19 | classLoader: ClassLoader, 20 | intercept: (Array, Method) -> Any? 21 | ): ITaskStackListener { 22 | return ByteBuddy() 23 | .subclass(ITaskStackListener.Stub::class.java) 24 | .method(ElementMatchers.any()) 25 | .intercept(MethodDelegation.to(object { 26 | @RuntimeType 27 | fun intercept( 28 | @AllArguments allArguments: Array, 29 | @Origin method: Method 30 | ) { 31 | intercept(allArguments, method) 32 | } 33 | })) 34 | .make() 35 | .load(classLoader, byteBuddyStrategy) 36 | .loaded 37 | .getDeclaredConstructor() 38 | .newInstance() 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/Application.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf 2 | 3 | import android.app.Application 4 | import com.google.android.material.color.DynamicColors 5 | import com.mja.reyamf.manager.utils.AppContext 6 | 7 | lateinit var application: Application 8 | 9 | class Application: Application() { 10 | 11 | init { 12 | application = this 13 | AppContext.context = this 14 | } 15 | 16 | override fun onCreate() { 17 | super.onCreate() 18 | 19 | DynamicColors.applyToActivitiesIfAvailable(this) 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/common/Utils.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.common 2 | 3 | import android.content.res.Resources 4 | import android.util.TypedValue 5 | import androidx.annotation.AttrRes 6 | import androidx.recyclerview.widget.RecyclerView 7 | import com.google.gson.Gson 8 | import kotlinx.coroutines.CoroutineScope 9 | import kotlinx.coroutines.DelicateCoroutinesApi 10 | import kotlinx.coroutines.Dispatchers 11 | import kotlinx.coroutines.GlobalScope 12 | import kotlinx.coroutines.launch 13 | 14 | val gson by lazy { Gson() } 15 | 16 | fun RecyclerView.resetAdapter() { 17 | this.adapter = adapter 18 | } 19 | 20 | inline fun Result.onException(action: (exception: Exception) -> Unit): Result = 21 | this.onFailure { t -> 22 | if (t is Error) throw t 23 | action(t as Exception) 24 | } 25 | 26 | @OptIn(DelicateCoroutinesApi::class) 27 | fun runMain(block: suspend CoroutineScope.() -> Unit) = 28 | GlobalScope.launch(Dispatchers.Main, block = block) 29 | 30 | @OptIn(DelicateCoroutinesApi::class) 31 | fun runIO(block: suspend CoroutineScope.() -> Unit) = 32 | GlobalScope.launch(Dispatchers.IO, block = block) 33 | 34 | fun Resources.Theme.getAttr(@AttrRes id: Int) = 35 | TypedValue().apply { resolveAttribute(id, this, true) } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/common/model/AppInfo.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.common.model 2 | 3 | import android.content.ComponentName 4 | import android.graphics.drawable.Drawable 5 | import android.os.Parcelable 6 | import kotlinx.parcelize.Parcelize 7 | import kotlinx.parcelize.RawValue 8 | 9 | @Parcelize 10 | data class AppInfo( 11 | val id: Int, 12 | val icon: @RawValue Drawable, 13 | val label: CharSequence, 14 | val componentName: ComponentName, 15 | val userId: Int 16 | ) : Parcelable 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/common/model/Config.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.common.model 2 | 3 | data class Config( 4 | var reduceDPI: Int = 50, 5 | /* 6 | * VIRTUAL_DISPLAY_FLAG_SECURE 1 << 2 7 | * VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT 1 << 7 8 | * VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS 1 << 9 9 | * VIRTUAL_DISPLAY_FLAG_TRUSTED 1 << 10 10 | */ 11 | var flags: Int = 1668, 12 | var coloredController: Boolean = false, 13 | /* 14 | * 0: move task only 15 | * 1: start activity only 16 | * 2: move task, failback to start activity 17 | */ 18 | var windowfy: Int = 0, 19 | /* 20 | * 0: TextureView 21 | * 1: SurfaceView 22 | */ 23 | var surfaceView: Int = 0, 24 | var recentBackHome: Boolean = false, 25 | var showImeInWindow: Boolean = false, 26 | var defaultWindowWidth: Int = 280, 27 | var defaultWindowHeight: Int = 380, 28 | var hookLauncher: HookLauncher = HookLauncher(), 29 | var showForceShowIME: Boolean = false, 30 | var portraitY: Int = 0, 31 | var landscapeY: Int = 0, 32 | var favApps: MutableList = mutableListOf(), 33 | var launchSideBarAtBoot: Boolean = false, 34 | var enableSidebar: Boolean = true, 35 | var sidebarTransparency: Int = 80, 36 | var windowRoundedCorner: Int = 20, 37 | var sidebarPosition: Boolean = false //false=left, true=right 38 | ) { 39 | data class HookLauncher( 40 | var hookRecents: Boolean = true, 41 | var hookTaskbar: Boolean = true, 42 | var hookPopup: Boolean = true, 43 | var hookTransientTaskbar: Boolean = false, 44 | ) 45 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/common/model/FavApps.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.common.model 2 | 3 | import android.os.Parcelable 4 | import kotlinx.parcelize.Parcelize 5 | 6 | @Parcelize 7 | data class FavApps( 8 | val packageName: String, 9 | val userId: Int 10 | ): Parcelable 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/common/model/StartCmd.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.common.model 2 | 3 | import android.content.ComponentName 4 | 5 | data class StartCmd( 6 | val componentName: ComponentName? = null, 7 | val userId: Int? = null, 8 | val taskId: Int? = null 9 | ) { 10 | val canStartActivity 11 | get() = componentName != null && userId != null 12 | 13 | val canMoveTask 14 | get() = taskId != null && taskId != 0 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/Application.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager 2 | 3 | import com.google.android.material.color.DynamicColors 4 | import com.mja.reyamf.manager.utils.AppContext 5 | 6 | lateinit var application: Application 7 | 8 | class Application: android.app.Application() { 9 | init { 10 | application = this 11 | AppContext.context = this 12 | } 13 | 14 | override fun onCreate() { 15 | super.onCreate() 16 | DynamicColors.applyToActivitiesIfAvailable(this) 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/adapter/AppListAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.adapter 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.recyclerview.widget.RecyclerView 7 | import com.mja.reyamf.R 8 | import com.mja.reyamf.common.model.AppInfo 9 | import com.mja.reyamf.databinding.ItemAppBinding 10 | 11 | class AppListAdapter ( 12 | private val onClick: (AppInfo) -> Unit, 13 | private val appList: ArrayList, 14 | private val onLongClick: (AppInfo) -> Unit 15 | ) : RecyclerView.Adapter() { 16 | 17 | fun setData(items: List?) { 18 | appList.apply { 19 | clear() 20 | items?.let { addAll(it) } 21 | } 22 | } 23 | override fun onCreateViewHolder( 24 | parent: ViewGroup, 25 | viewType: Int 26 | ): ViewHolder { 27 | val view = LayoutInflater.from(parent.context).inflate(R.layout.item_app, parent, false) 28 | return ViewHolder(view) 29 | } 30 | override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(appList[position]) 31 | 32 | override fun getItemCount(): Int = appList.size 33 | 34 | inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){ 35 | private val binding = ItemAppBinding.bind(itemView) 36 | fun bind(appInfo: AppInfo){ 37 | binding.apply { 38 | val icon = appInfo.icon 39 | val label = appInfo.label 40 | ivIcon.setImageDrawable(icon) 41 | tvLabel.text = label 42 | 43 | ll.setOnClickListener { 44 | onClick(appInfo) 45 | } 46 | 47 | ll.setOnLongClickListener { 48 | onLongClick(appInfo) 49 | true 50 | } 51 | } 52 | } 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/adapter/SideBarAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.adapter 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.recyclerview.widget.RecyclerView 7 | import com.github.kyuubiran.ezxhelper.utils.Log 8 | import com.mja.reyamf.R 9 | import com.mja.reyamf.common.model.AppInfo 10 | import com.mja.reyamf.databinding.SidebarItemviewBinding 11 | 12 | class SideBarAdapter ( 13 | private val onClick: (AppInfo) -> Unit, 14 | private val sideBarApp: ArrayList, 15 | private val onLongClick: (Int) -> Unit 16 | ) : RecyclerView.Adapter() { 17 | 18 | fun setData(items: List?) { 19 | android.util.Log.d("XPOSED", items?.size.toString()) 20 | sideBarApp.apply { 21 | clear() 22 | items?.let { addAll(it) } 23 | } 24 | } 25 | 26 | override fun onCreateViewHolder( 27 | parent: ViewGroup, 28 | viewType: Int 29 | ): ViewHolder { 30 | val view = LayoutInflater.from(parent.context).inflate(R.layout.sidebar_itemview, parent, false) 31 | return ViewHolder(view) 32 | } 33 | 34 | override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(sideBarApp[position]) 35 | 36 | override fun getItemCount(): Int = sideBarApp.size 37 | 38 | inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){ 39 | private val binding = SidebarItemviewBinding.bind(itemView) 40 | fun bind(appInfo: AppInfo){ 41 | binding.apply { 42 | ivAppIcon.setImageDrawable(appInfo.icon) 43 | ivAppIcon.setOnClickListener { 44 | onClick(appInfo) 45 | } 46 | ivAppIcon.setOnLongClickListener { 47 | onLongClick(adapterPosition) 48 | true 49 | } 50 | if (appInfo.userId == 0) { 51 | ivWorkIcon.visibility = View.INVISIBLE 52 | } 53 | } 54 | } 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/adapter/VerticalSpaceItemDecoration.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.adapter 2 | 3 | import android.graphics.Rect 4 | import android.view.View 5 | import androidx.recyclerview.widget.RecyclerView 6 | 7 | class VerticalSpaceItemDecoration(private val verticalSpaceHeight: Int) : RecyclerView.ItemDecoration() { 8 | override fun getItemOffsets( 9 | outRect: Rect, 10 | view: View, 11 | parent: RecyclerView, 12 | state: RecyclerView.State 13 | ) { 14 | outRect.bottom = verticalSpaceHeight 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/broadcastreceiver/BootReceiver.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.broadcastreceiver 2 | 3 | import android.content.BroadcastReceiver 4 | import android.content.Context 5 | import android.content.Intent 6 | import com.mja.reyamf.common.gson 7 | import com.mja.reyamf.common.model.Config 8 | import com.mja.reyamf.manager.services.YAMFManagerProxy 9 | 10 | class BootReceiver : BroadcastReceiver() { 11 | 12 | lateinit var config: Config 13 | 14 | override fun onReceive(context: Context, intent: Intent) { 15 | if (intent.action == Intent.ACTION_BOOT_COMPLETED) { 16 | config = gson.fromJson(YAMFManagerProxy.configJson, Config::class.java) 17 | 18 | if (config.launchSideBarAtBoot) { 19 | YAMFManagerProxy.launchSideBar() 20 | } 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/providers/ServiceProvider.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.providers 2 | 3 | import android.content.ContentProvider 4 | import android.content.ContentValues 5 | import android.net.Uri 6 | import android.os.Bundle 7 | import com.mja.reyamf.manager.services.YAMFManagerProxy 8 | 9 | class ServiceProvider: ContentProvider() { 10 | override fun onCreate() = false 11 | 12 | override fun query( 13 | uri: Uri, 14 | projection: Array?, 15 | selection: String?, 16 | selectionArgs: Array?, 17 | sortOrder: String? 18 | ) = null 19 | 20 | override fun getType(uri: Uri) = null 21 | 22 | override fun insert(uri: Uri, values: ContentValues?) = null 23 | 24 | override fun delete(uri: Uri, selection: String?, selectionArgs: Array?) = 0 25 | 26 | override fun update( 27 | uri: Uri, 28 | values: ContentValues?, 29 | selection: String?, 30 | selectionArgs: Array? 31 | ) = 0 32 | 33 | override fun call(method: String, arg: String?, extras: Bundle?): Bundle? { 34 | if (callingPackage != "android" || extras == null) return null 35 | val binder = extras.getBinder("binder") ?: return null 36 | YAMFManagerProxy.linkService(binder) 37 | return Bundle() 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/services/AccessibilityService.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.services 2 | 3 | import android.accessibilityservice.AccessibilityService 4 | import android.view.accessibility.AccessibilityEvent 5 | 6 | class AccessibilityService : AccessibilityService() { 7 | override fun onAccessibilityEvent(event: AccessibilityEvent?) { 8 | 9 | } 10 | 11 | override fun onInterrupt() { 12 | 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/services/CurrentToFloatingService.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.services 2 | 3 | import android.content.Intent 4 | import android.service.voice.VoiceInteractionService 5 | import android.util.Log 6 | 7 | class CurrentToFloatingService : VoiceInteractionService() { 8 | override fun onCreate() { 9 | super.onCreate() 10 | 11 | val intent = Intent() 12 | intent.action = "com.mja.reyamf.action.CURRENT_TO_WINDOW" 13 | intent.addCategory(Intent.CATEGORY_DEFAULT) 14 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 15 | 16 | Log.d("reYAMFDWOO", "long pressed") 17 | 18 | sendBroadcast(intent) 19 | } 20 | 21 | override fun onReady() { 22 | super.onReady() 23 | 24 | Log.d("reYAMFWOO", "readyyyyyyyy") 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/services/QSEnterWindow.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.services 2 | 3 | import android.service.quicksettings.TileService 4 | 5 | class QSEnterWindow: TileService() { 6 | override fun onClick() { 7 | super.onClick() 8 | YAMFManagerProxy.currentToWindow() 9 | } 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/services/QSNewWindowService.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.services 2 | 3 | import android.service.quicksettings.TileService 4 | import androidx.preference.PreferenceManager 5 | 6 | class QSNewWindowService : TileService() { 7 | override fun onClick() { 8 | super.onClick() 9 | if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("useAppList", true)) 10 | YAMFManagerProxy.openAppList() 11 | else YAMFManagerProxy.createWindow() 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/services/QSResetAllWindow.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.services 2 | 3 | import android.service.quicksettings.TileService 4 | 5 | class QSResetAllWindow: TileService() { 6 | override fun onClick() { 7 | YAMFManagerProxy.resetAllWindow() 8 | } 9 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/services/SidebarHiderService.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.services 2 | 3 | import android.app.Service 4 | import android.content.Intent 5 | import android.os.IBinder 6 | 7 | class SidebarHiderService : Service() { 8 | override fun onBind(intent: Intent?): IBinder? { 9 | return null 10 | } 11 | 12 | override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { 13 | val receivedString = intent?.getStringExtra("act") 14 | receivedString?.let { 15 | if (it == "KILL") { 16 | YAMFManagerProxy.killSideBar() 17 | } else { 18 | YAMFManagerProxy.launchSideBar() 19 | } 20 | stopSelf() 21 | } 22 | return START_NOT_STICKY 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/services/YAMFManagerProxy.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.services 2 | 3 | import android.os.IBinder 4 | import android.os.IBinder.DeathRecipient 5 | import android.util.Log 6 | import com.mja.reyamf.xposed.IOpenCountListener 7 | import com.mja.reyamf.xposed.IYAMFManager 8 | import java.lang.reflect.InvocationHandler 9 | import java.lang.reflect.Method 10 | import java.lang.reflect.Proxy 11 | 12 | object YAMFManagerProxy : IYAMFManager, DeathRecipient { 13 | private const val TAG = "reYAMFManagerProxy" 14 | 15 | private class ServiceProxy(private val obj: IYAMFManager) : InvocationHandler { 16 | override fun invoke(proxy: Any?, method: Method, args: Array?): Any? { 17 | val result = method.invoke(obj, *args.orEmpty()) 18 | if (result == null) Log.i(TAG, "Call service method ${method.name}") 19 | else Log.i( 20 | TAG, 21 | "Call service method ${method.name} with result " + result.toString().take(20) 22 | ) 23 | return result 24 | } 25 | } 26 | 27 | @Volatile 28 | private var service: IYAMFManager? = null 29 | 30 | fun linkService(binder: IBinder) { 31 | service = Proxy.newProxyInstance( 32 | javaClass.classLoader, 33 | arrayOf(IYAMFManager::class.java), 34 | ServiceProxy(IYAMFManager.Stub.asInterface(binder)) 35 | ) as IYAMFManager 36 | binder.linkToDeath(this, 0) 37 | } 38 | 39 | override fun binderDied() { 40 | service = null 41 | Log.e(TAG, "Binder died") 42 | } 43 | 44 | override fun asBinder() = service?.asBinder() 45 | 46 | override fun getVersionName(): String? { 47 | return service?.versionName 48 | } 49 | 50 | override fun getVersionCode() = service?.versionCode ?: 0 51 | 52 | override fun getUid() = service?.uid ?: -1 53 | 54 | override fun createWindow() { 55 | service?.createWindow() 56 | } 57 | 58 | override fun getBuildTime(): Long { 59 | return service?.buildTime ?: 0 60 | } 61 | 62 | override fun getConfigJson(): String { 63 | return service?.configJson ?: "{}" 64 | } 65 | 66 | override fun updateConfig(newConfig: String) { 67 | service?.updateConfig(newConfig) 68 | } 69 | 70 | override fun registerOpenCountListener(iOpenCountListener: IOpenCountListener) { 71 | service?.registerOpenCountListener(iOpenCountListener) 72 | } 73 | 74 | override fun unregisterOpenCountListener(iOpenCountListener: IOpenCountListener) { 75 | service?.unregisterOpenCountListener(iOpenCountListener) 76 | } 77 | 78 | override fun openAppList() { 79 | service?.openAppList() 80 | } 81 | 82 | override fun currentToWindow() { 83 | service?.currentToWindow() 84 | } 85 | 86 | override fun resetAllWindow() { 87 | service?.resetAllWindow() 88 | } 89 | 90 | override fun launchSideBar() { 91 | service?.launchSideBar() 92 | } 93 | 94 | override fun killSideBar() { 95 | service?.killSideBar() 96 | } 97 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/ui/CurrentToFloatingActivity.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.ui 2 | 3 | import android.app.Activity 4 | import android.os.Bundle 5 | import android.util.Log 6 | import com.mja.reyamf.manager.services.YAMFManagerProxy 7 | 8 | 9 | class CurrentToFloatingActivity : Activity() { 10 | override fun onCreate(savedInstanceState: Bundle?) { 11 | super.onCreate(savedInstanceState) 12 | finish() 13 | 14 | // val intent = Intent(this, CurrentToFloatingService::class.java) 15 | // intent.setAction(Intent.ACTION_ASSIST) 16 | 17 | // val intent = Intent() 18 | // intent.action = "com.mja.reyamf.action.ACTION_OPEN_IN_YAMF" 19 | // intent.addCategory(Intent.CATEGORY_DEFAULT) 20 | // intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 21 | 22 | Log.d("reYAMFWOO", "long pressed") 23 | 24 | // startService(intent) 25 | // sendBroadcast(intent) 26 | 27 | YAMFManagerProxy.currentToWindow() 28 | 29 | // finish() 30 | } 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/ui/main/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.ui.main 2 | 3 | import android.content.Intent 4 | import android.os.Build 5 | import android.os.Bundle 6 | import android.os.Handler 7 | import android.os.Looper 8 | import android.util.Log 9 | import android.util.TypedValue 10 | import android.view.Menu 11 | import android.view.MenuItem 12 | import android.view.View 13 | import androidx.activity.enableEdgeToEdge 14 | import androidx.appcompat.app.AppCompatActivity 15 | import androidx.core.net.toUri 16 | import androidx.core.view.ViewCompat 17 | import androidx.core.view.WindowInsetsCompat 18 | import com.bumptech.glide.Glide 19 | import com.google.android.material.color.MaterialColors 20 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 21 | import com.google.android.material.slider.Slider 22 | import com.mja.reyamf.BuildConfig 23 | import com.mja.reyamf.R 24 | import com.mja.reyamf.common.getAttr 25 | import com.mja.reyamf.common.gson 26 | import com.mja.reyamf.common.model.Config 27 | import com.mja.reyamf.common.runMain 28 | import com.mja.reyamf.databinding.ActivityMainBinding 29 | import com.mja.reyamf.manager.services.YAMFManagerProxy 30 | import com.mja.reyamf.manager.sidebar.SideBar 31 | import com.mja.reyamf.manager.ui.setting.SettingActivity 32 | import com.mja.reyamf.manager.utils.TipUtil 33 | import com.mja.reyamf.xposed.IOpenCountListener 34 | import com.mja.reyamf.xposed.utils.log 35 | import kotlinx.coroutines.CoroutineScope 36 | import kotlinx.coroutines.Dispatchers 37 | import kotlinx.coroutines.delay 38 | import kotlinx.coroutines.launch 39 | 40 | class MainActivity : AppCompatActivity() { 41 | 42 | private var _binding: ActivityMainBinding? = null 43 | private val binding get() = _binding 44 | lateinit var config: Config 45 | 46 | companion object { 47 | const val TAG = "reYAMF_MainActivity" 48 | } 49 | 50 | private val openCountListener = object : IOpenCountListener.Stub() { 51 | override fun onUpdate(count: Int) { 52 | runMain { 53 | binding?.tvOpenCount?.text = count.toString() 54 | } 55 | } 56 | } 57 | 58 | override fun onCreate(savedInstanceState: Bundle?) { 59 | super.onCreate(savedInstanceState) 60 | enableEdgeToEdge() 61 | _binding = ActivityMainBinding.inflate(layoutInflater) 62 | setContentView(binding?.root) 63 | ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> 64 | val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) 65 | v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) 66 | insets 67 | } 68 | val typedValue = TypedValue() 69 | this@MainActivity.theme.resolveAttribute(android.R.attr.textColor, typedValue, true) 70 | binding?.toolbar?.overflowIcon?.setTint(typedValue.data) 71 | 72 | setSupportActionBar(binding?.toolbar) 73 | supportActionBar?.setDisplayShowTitleEnabled(false) 74 | 75 | YAMFManagerProxy.registerOpenCountListener(openCountListener) 76 | initUi() 77 | } 78 | 79 | private fun initUi() { 80 | config = gson.fromJson(YAMFManagerProxy.configJson, Config::class.java) 81 | val buildTime = YAMFManagerProxy.buildTime 82 | when(buildTime) { 83 | 0L -> { 84 | binding?.apply { 85 | ivIcon.setImageResource(R.drawable.ic_error_outline_24) 86 | tvActive.setText(R.string.not_activated) 87 | tvVersion.visibility = View.GONE 88 | val colorError = theme.getAttr(com.google.android.material.R.attr.colorError).data 89 | val colorOnError = theme.getAttr(com.google.android.material.R.attr.colorOnError).data 90 | mcvStatus.setCardBackgroundColor(colorError) 91 | mcvStatus.outlineAmbientShadowColor = colorError 92 | mcvStatus.outlineSpotShadowColor = colorError 93 | tvActive.setTextColor(colorOnError) 94 | tvVersion.setTextColor(colorOnError) 95 | mcvInfo.visibility = View.GONE 96 | mcvSideBar.visibility = View.GONE 97 | } 98 | } 99 | BuildConfig.BUILD_TIME -> { 100 | binding?.apply { 101 | ivIcon.setImageResource(R.drawable.ic_round_check_circle_24) 102 | tvActive.setText(R.string.activated) 103 | tvVersion.text = buildString { 104 | append(YAMFManagerProxy.versionName) 105 | append(" (${YAMFManagerProxy.versionCode})") 106 | } 107 | } 108 | } 109 | else -> { 110 | binding?.apply { 111 | ivIcon.setImageResource(R.drawable.ic_warning_amber_24) 112 | tvActive.setText(R.string.need_reboot) 113 | tvVersion.text = buildString { 114 | append("system: ${YAMFManagerProxy.versionName} (${YAMFManagerProxy.versionCode})\n") 115 | append("module: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})") 116 | } 117 | mcvStatus.setCardBackgroundColor(MaterialColors.harmonizeWithPrimary(this@MainActivity, getColor(R.color.color_warning))) 118 | mcvStatus.setOnClickListener { 119 | MaterialAlertDialogBuilder(this@MainActivity) 120 | .setTitle(R.string.need_reboot) 121 | .setMessage(R.string.need_reboot_message) 122 | .setPositiveButton(R.string.reboot) { _, _-> 123 | TipUtil.showTip(this@MainActivity, "do it yourself") 124 | } 125 | .show() 126 | } 127 | sliderTransparency.value = config.sidebarTransparency.toFloat() 128 | tvTransparencyValue.text = "${config.sidebarTransparency}" 129 | } 130 | } 131 | } 132 | 133 | if (Build.VERSION.PREVIEW_SDK_INT != 0) { 134 | binding?.systemVersion?.text = buildString { 135 | append(Build.VERSION.CODENAME) 136 | append("Preview (API ${Build.VERSION.SDK_INT})") 137 | } 138 | } else { 139 | binding?.systemVersion?.text = buildString { 140 | append(Build.VERSION.RELEASE) 141 | append("(API ${Build.VERSION.SDK_INT})") 142 | } 143 | } 144 | binding?.tvBuildType?.text = BuildConfig.BUILD_TYPE 145 | 146 | binding?.apply { 147 | btLaunchSideBar.setOnClickListener { 148 | YAMFManagerProxy.launchSideBar() 149 | } 150 | 151 | msSideBar.isChecked = config.launchSideBarAtBoot 152 | msSideBar.setOnCheckedChangeListener { _, isChecked -> 153 | config.launchSideBarAtBoot = isChecked 154 | YAMFManagerProxy.updateConfig(gson.toJson(config)) 155 | } 156 | 157 | msSideBarPosition.isChecked = config.sidebarPosition 158 | msSideBarPosition.setOnCheckedChangeListener { _, isChecked -> 159 | config.sidebarPosition = isChecked 160 | YAMFManagerProxy.updateConfig(gson.toJson(config)) 161 | CoroutineScope(Dispatchers.IO).launch { 162 | YAMFManagerProxy.killSideBar() 163 | delay(1000) 164 | YAMFManagerProxy.launchSideBar() 165 | } 166 | } 167 | 168 | ivDemo.let { 169 | Glide.with(this@MainActivity) 170 | .load(R.drawable.demo) 171 | .into(it) 172 | } 173 | 174 | if (config.enableSidebar) { 175 | innerClSidebar.visibility = View.VISIBLE 176 | } else { 177 | innerClSidebar.visibility = View.GONE 178 | } 179 | 180 | msEnableSideBar.isChecked = config.enableSidebar 181 | 182 | msEnableSideBar.setOnCheckedChangeListener { _, isChecked -> 183 | if (isChecked) { 184 | innerClSidebar.visibility = View.VISIBLE 185 | } else { 186 | innerClSidebar.visibility = View.GONE 187 | } 188 | 189 | config.enableSidebar = isChecked 190 | YAMFManagerProxy.updateConfig(gson.toJson(config)) 191 | } 192 | 193 | sliderTransparency.addOnSliderTouchListener(object : Slider.OnSliderTouchListener { 194 | override fun onStartTrackingTouch(slider: Slider) {} 195 | 196 | override fun onStopTrackingTouch(slider: Slider) { 197 | tvTransparencyValue.text = "${slider.value.toInt()}" 198 | config.sidebarTransparency = slider.value.toInt() 199 | YAMFManagerProxy.updateConfig(gson.toJson(config)) 200 | YAMFManagerProxy.killSideBar() 201 | 202 | Handler(Looper.getMainLooper()).postDelayed({ 203 | try { 204 | Log.d(SideBar.TAG, "updateConfig: restart") 205 | YAMFManagerProxy.launchSideBar() 206 | } catch (e: Exception) { 207 | log(SideBar.TAG, "Failed restart sidebar") 208 | } 209 | }, 500) 210 | } 211 | }) 212 | } 213 | } 214 | 215 | override fun onCreateOptionsMenu(menu: Menu?): Boolean { 216 | menuInflater.inflate(R.menu.menu_main, menu) 217 | return true 218 | } 219 | 220 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 221 | return when(item.itemId) { 222 | R.id.new_window -> { 223 | YAMFManagerProxy.createWindow() 224 | true 225 | } 226 | R.id.channel -> { 227 | startActivity(Intent(Intent.ACTION_VIEW).apply { 228 | data = "https://t.me/+HjGegWE9jBM0N2Rl".toUri() 229 | }) 230 | true 231 | } 232 | R.id.open_app_list -> { 233 | YAMFManagerProxy.openAppList() 234 | true 235 | } 236 | R.id.settings -> { 237 | startActivity(Intent(this, SettingActivity::class.java)) 238 | true 239 | } 240 | R.id.github -> { 241 | startActivity(Intent(Intent.ACTION_VIEW).apply { 242 | data = "https://github.com/JuanArton/reYAMF".toUri() 243 | }) 244 | true 245 | } 246 | R.id.donate -> { 247 | startActivity(Intent(Intent.ACTION_VIEW).apply { 248 | data = "https://duzhaokun123.github.io/donate.html".toUri() 249 | }) 250 | true 251 | } 252 | R.id.current_to_window -> { 253 | YAMFManagerProxy.currentToWindow() 254 | true 255 | } 256 | else -> false 257 | } 258 | } 259 | 260 | override fun onDestroy() { 261 | super.onDestroy() 262 | YAMFManagerProxy.unregisterOpenCountListener(openCountListener) 263 | } 264 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/ui/setting/SettingActivity.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.ui.setting 2 | 3 | import android.content.Intent 4 | import android.content.SharedPreferences 5 | import android.content.res.ColorStateList 6 | import android.graphics.Color 7 | import android.os.Build 8 | import android.os.Bundle 9 | import android.os.Handler 10 | import android.os.Looper 11 | import android.util.Log 12 | import androidx.activity.enableEdgeToEdge 13 | import androidx.appcompat.app.AppCompatActivity 14 | import androidx.appcompat.widget.PopupMenu 15 | import androidx.core.content.ContextCompat 16 | import androidx.core.net.toUri 17 | import androidx.core.view.ViewCompat 18 | import androidx.core.view.WindowInsetsCompat 19 | import androidx.preference.PreferenceManager 20 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 21 | import com.google.android.material.slider.Slider 22 | import com.mja.reyamf.R 23 | import com.mja.reyamf.common.gson 24 | import com.mja.reyamf.databinding.ActivitySettingBinding 25 | import com.mja.reyamf.manager.services.YAMFManagerProxy 26 | import com.mja.reyamf.manager.sidebar.SideBar 27 | import com.mja.reyamf.xposed.utils.log 28 | import com.mja.reyamf.common.model.Config as YAMFConfig 29 | 30 | class SettingActivity : AppCompatActivity() { 31 | 32 | private var _binding: ActivitySettingBinding? = null 33 | private val binding get() = _binding 34 | 35 | companion object { 36 | val flags = listOf( 37 | "VIRTUAL_DISPLAY_FLAG_PUBLIC", // 1 << 0 38 | "VIRTUAL_DISPLAY_FLAG_PRESENTATION", // 1 << 1 39 | "VIRTUAL_DISPLAY_FLAG_SECURE", // 1 << 2 40 | "VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY", // 1 << 3 41 | "VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR", // 1 << 4 42 | "VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD", // 1 << 5 43 | "VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH", // 1 << 6 44 | "VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT", // 1 << 7 45 | "VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL", // 1 << 8 46 | "VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS", // 1 << 9 47 | "VIRTUAL_DISPLAY_FLAG_TRUSTED", // 1 << 10 48 | "VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP", // 1 << 11 49 | "VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED", // 1 << 12 50 | "VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED", // 1 << 13 51 | ) 52 | } 53 | 54 | lateinit var config: YAMFConfig 55 | private val preference: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) } 56 | 57 | override fun onCreate(savedInstanceState: Bundle?) { 58 | super.onCreate(savedInstanceState) 59 | enableEdgeToEdge() 60 | _binding = ActivitySettingBinding.inflate(layoutInflater) 61 | setContentView(binding?.root) 62 | ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> 63 | val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) 64 | v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) 65 | insets 66 | } 67 | 68 | initData() 69 | } 70 | 71 | private fun initData() { 72 | binding?.apply { 73 | config = gson.fromJson(YAMFManagerProxy.configJson, YAMFConfig::class.java) 74 | etReduceDPI.setText(config.reduceDPI.toString()) 75 | btnFlags.text = config.flags.toString() 76 | sColoerd.isChecked = config.coloredController 77 | sBackHome.isChecked = config.recentBackHome 78 | sShowIMEinWindow.isChecked = config.showImeInWindow 79 | etSizeH.setText(config.defaultWindowHeight.toString()) 80 | etSizeW.setText(config.defaultWindowWidth.toString()) 81 | sHookLauncherHookRecents.isChecked = config.hookLauncher.hookRecents 82 | sHookLauncherHookTaskbar.isChecked = config.hookLauncher.hookTaskbar 83 | sHookLauncherHookPopup.isChecked = config.hookLauncher.hookPopup 84 | sHookLauncherHookTransientTaskbar.isChecked = config.hookLauncher.hookTransientTaskbar 85 | sUseAppList.isChecked = preference.getBoolean("useAppList", true) 86 | sForceShowIME.isChecked = config.showForceShowIME 87 | sliderRounded.value = config.windowRoundedCorner.toFloat() 88 | tvRoundedValue.text = "${config.windowRoundedCorner}" 89 | 90 | btnSurface.text = when (config.surfaceView) { 91 | 0 -> { 92 | "Texture View" 93 | } 94 | 1 -> { 95 | "Surface View" 96 | } 97 | else -> { 98 | Log.d("reYAMF", "surfaceView: " + config.surfaceView.toString()) 99 | "Unavailable" 100 | } 101 | } 102 | 103 | btnWindowsfy.text = when (config.windowfy) { 104 | 0 -> { 105 | "Move Task" 106 | } 107 | 1 -> { 108 | "Start Activity" 109 | } 110 | 2 -> { 111 | "Hybrid" 112 | } 113 | else -> { 114 | Log.d("reYAMF", "windowfy: " + config.windowfy.toString()) 115 | "Unavailable" 116 | } 117 | } 118 | 119 | btnFlags.setOnClickListener { 120 | val checks = BooleanArray(flags.size) { i -> 121 | config.flags and (1 shl i) != 0 122 | } 123 | MaterialAlertDialogBuilder(this@SettingActivity) 124 | .setMultiChoiceItems(flags.toTypedArray(), checks) { _, i, c -> 125 | checks[i] = c 126 | btnFlags.text = checks.foldIndexed(0) { i, f, b -> 127 | if (b) 128 | f + (1 shl i) 129 | else 130 | f 131 | }.toString() 132 | } 133 | .setPositiveButton("about") { _, _ -> 134 | startActivity(Intent(Intent.ACTION_VIEW).apply { 135 | data = "https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/hardware/display/DisplayManager.java".toUri() 136 | }) 137 | } 138 | .show() 139 | } 140 | btnWindowsfy.setOnClickListener { 141 | PopupMenu(this@SettingActivity, btnWindowsfy).apply { 142 | listOf("Move Task", "Start Activity", "Hybrid").forEach { i -> 143 | menu.add(i).setOnMenuItemClickListener { 144 | btnWindowsfy.text = i 145 | true 146 | } 147 | } 148 | }.show() 149 | } 150 | btnSurface.setOnClickListener { 151 | PopupMenu(this@SettingActivity, btnSurface).apply { 152 | listOf("Texture View", "Surface View").forEach { i -> 153 | menu.add(i).setOnMenuItemClickListener { 154 | btnSurface.text = i 155 | true 156 | } 157 | } 158 | }.show() 159 | } 160 | sliderRounded.addOnSliderTouchListener(object : Slider.OnSliderTouchListener { 161 | override fun onStartTrackingTouch(slider: Slider) {} 162 | 163 | override fun onStopTrackingTouch(slider: Slider) { 164 | tvRoundedValue.text = "${slider.value.toInt()}" 165 | config.windowRoundedCorner = slider.value.toInt() 166 | YAMFManagerProxy.updateConfig(gson.toJson(config)) 167 | } 168 | }) 169 | } 170 | } 171 | 172 | override fun onDestroy() { 173 | super.onDestroy() 174 | binding?.apply { 175 | config.reduceDPI = etReduceDPI.text.toString().toIntOrNull() ?: config.reduceDPI 176 | config.flags = btnFlags.text.toString().toIntOrNull() ?: config.flags 177 | config.surfaceView = when (val surface = btnSurface.text.toString()) { 178 | "Texture View" -> { 179 | 0 180 | } 181 | "Surface View" -> { 182 | 1 183 | } 184 | else -> { 185 | Log.d("YAMF", "surface value: $surface") 186 | 0 187 | } 188 | } 189 | 190 | config.windowfy = when (val window = btnWindowsfy.text.toString()) { 191 | "Move Task" -> { 192 | 0 193 | } 194 | "Start Activity" -> { 195 | 1 196 | } 197 | "Hybrid" -> { 198 | 2 199 | } 200 | else -> { 201 | Log.d("reYAMF", "window value: $window") 202 | 0 203 | } 204 | } 205 | config.coloredController = sColoerd.isChecked 206 | config.recentBackHome = sBackHome.isChecked 207 | config.showImeInWindow = sShowIMEinWindow.isChecked 208 | config.defaultWindowHeight = etSizeH.text.toString().toIntOrNull() ?: config.defaultWindowHeight 209 | config.defaultWindowWidth = etSizeW.text.toString().toIntOrNull() ?: config.defaultWindowWidth 210 | config.hookLauncher.hookRecents = sHookLauncherHookRecents.isChecked 211 | config.hookLauncher.hookTaskbar = sHookLauncherHookTaskbar.isChecked 212 | config.hookLauncher.hookPopup = sHookLauncherHookPopup.isChecked 213 | config.hookLauncher.hookTransientTaskbar = sHookLauncherHookTransientTaskbar.isChecked 214 | config.showForceShowIME = sForceShowIME.isChecked 215 | preference.edit().putBoolean("useAppList", sUseAppList.isChecked).apply() 216 | YAMFManagerProxy.updateConfig(gson.toJson(config)) 217 | } 218 | } 219 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/utils/AppContext.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.utils 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | 6 | @SuppressLint("StaticFieldLeak") 7 | object AppContext { 8 | lateinit var context: Context 9 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/utils/TipUtil.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.utils 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.widget.TextView 6 | import android.widget.Toast 7 | import androidx.annotation.StringRes 8 | import androidx.coordinatorlayout.widget.CoordinatorLayout 9 | import androidx.core.view.isVisible 10 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 11 | import com.google.android.material.snackbar.BaseTransientBottomBar 12 | import com.google.android.material.snackbar.Snackbar 13 | import com.mja.reyamf.R 14 | import com.mja.reyamf.common.runMain 15 | import com.mja.reyamf.manager.application 16 | 17 | object TipUtil { 18 | private val map = mutableMapOf() 19 | 20 | fun registerCoordinatorLayout(context: Context, coordinatorLayout: CoordinatorLayout?) { 21 | coordinatorLayout?.let { map[context.hashCode()] = it } 22 | } 23 | 24 | fun unregisterCoordinatorLayout(context: Context) { 25 | map.remove(context.hashCode()) 26 | } 27 | 28 | fun showToast(msg: CharSequence?) { 29 | runMain { 30 | Toast.makeText(application, "$msg", Toast.LENGTH_LONG).show() 31 | } 32 | } 33 | 34 | fun showToast(@StringRes resId: Int) = 35 | showToast(application.getText(resId)) 36 | 37 | private fun showSnackbar(coordinatorLayout: CoordinatorLayout, msg: CharSequence?) { 38 | runMain { 39 | Snackbar.make(coordinatorLayout, "$msg", BaseTransientBottomBar.LENGTH_LONG).show() 40 | } 41 | } 42 | 43 | fun showSnackbar(coordinatorLayout: CoordinatorLayout, @StringRes resId: Int) = 44 | showSnackbar(coordinatorLayout, application.getText(resId)) 45 | 46 | private fun showSnackbar(coordinatorLayout: CoordinatorLayout, t: Throwable) { 47 | runMain { 48 | val msg = t.localizedMessage ?: t.message ?: application.getString(R.string.unknown_error) 49 | Snackbar.make(coordinatorLayout, msg, BaseTransientBottomBar.LENGTH_LONG) 50 | .setAction(R.string.details) { 51 | MaterialAlertDialogBuilder(coordinatorLayout.context) 52 | .setTitle(msg) 53 | .setMessage("${t.message}\n${t.stackTraceToString()}") 54 | .show() 55 | .findViewById(android.R.id.message) 56 | ?.setTextIsSelectable(true) 57 | }.show() 58 | } 59 | } 60 | 61 | fun showTip(context: Context?, t: Throwable) { 62 | val msg = t.localizedMessage ?: t.message ?: "Unknown Error" 63 | if (context == null || (context is Activity && context.window.decorView.isVisible.not())) { 64 | showToast(msg) 65 | return 66 | } 67 | map[context.hashCode()]?.let { 68 | showSnackbar(it, t) 69 | return 70 | } 71 | showToast(msg) 72 | } 73 | 74 | fun showTip(context: Context?, msg: CharSequence?) { 75 | if (context == null || (context is Activity && context.window.decorView.isVisible.not())) { 76 | showToast(msg) 77 | return 78 | } 79 | map[context.hashCode()]?.let { 80 | showSnackbar(it, msg) 81 | return 82 | } 83 | showToast(msg) 84 | } 85 | 86 | fun showTip(context: Context?, @StringRes resId: Int) = 87 | showTip(context, application.getText(resId)) 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/manager/utils/Utils.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.manager.utils 2 | 3 | import androidx.core.view.WindowInsetsCompat 4 | 5 | val WindowInsetsCompat.maxSystemBarsDisplayCutout 6 | get() = getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()) 7 | 8 | val WindowInsetsCompat.maxSystemBarsDisplayCutoutIme 9 | get() = getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() or WindowInsetsCompat.Type.ime()) 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/xposed/hook/HookPermission.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.xposed.hook 2 | 3 | import android.app.AndroidAppHelper 4 | import android.app.Application 5 | import android.content.ComponentName 6 | import android.content.Context 7 | import android.content.Intent 8 | import android.os.Bundle 9 | import android.util.Log 10 | import com.mja.reyamf.manager.services.YAMFManagerProxy 11 | import com.mja.reyamf.xposed.utils.Instances.systemContext 12 | import de.robv.android.xposed.IXposedHookLoadPackage 13 | import de.robv.android.xposed.XC_MethodHook 14 | import de.robv.android.xposed.XposedBridge 15 | import de.robv.android.xposed.XposedHelpers 16 | import de.robv.android.xposed.callbacks.XC_LoadPackage 17 | 18 | class HookPermission : IXposedHookLoadPackage { 19 | private var classLoader: ClassLoader? = null 20 | 21 | 22 | override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { 23 | if (lpparam.packageName !="com.google.android.permissioncontroller") { 24 | return 25 | } 26 | 27 | XposedHelpers.findAndHookMethod(Application::class.java, "attach", Context::class.java, object : XC_MethodHook() { 28 | override fun afterHookedMethod(param: MethodHookParam) { 29 | classLoader = (param.thisObject as Application).classLoader 30 | XposedBridge.log("Hooked into ${lpparam.packageName}") 31 | intentHook() 32 | } 33 | }) 34 | } 35 | 36 | private fun intentHook() { 37 | try { 38 | 39 | XposedHelpers.findAndHookMethod( 40 | "com.android.permissioncontroller.permission.ui.GrantPermissionsActivity", 41 | classLoader, 42 | "onCreate", 43 | Bundle::class.java, 44 | object : XC_MethodHook() { 45 | override fun beforeHookedMethod(param: MethodHookParam) { 46 | 47 | val serviceIntent = Intent().apply { 48 | setComponent( 49 | ComponentName( 50 | "com.mja.reyamf", 51 | "com.mja.reyamf.manager.services.SidebarHiderService" 52 | ) 53 | ) 54 | putExtra("act", "KILL") 55 | } 56 | AndroidAppHelper.currentApplication().startService(serviceIntent) 57 | } 58 | } 59 | ) 60 | 61 | XposedHelpers.findAndHookMethod( 62 | "com.android.permissioncontroller.permission.ui.GrantPermissionsActivity", 63 | classLoader, 64 | "onDestroy", 65 | object : XC_MethodHook() { 66 | override fun afterHookedMethod(param: MethodHookParam) { 67 | 68 | val serviceIntent = Intent().apply { 69 | setComponent( 70 | ComponentName( 71 | "com.mja.reyamf", 72 | "com.mja.reyamf.manager.services.SidebarHiderService" 73 | ) 74 | ) 75 | putExtra("act", "LAUNCH") 76 | } 77 | AndroidAppHelper.currentApplication().startService(serviceIntent) 78 | } 79 | } 80 | ) 81 | } catch (e: Throwable) { 82 | XposedBridge.log(e) 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/xposed/hook/HookPermissionDefault.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.xposed.hook 2 | 3 | import android.app.AndroidAppHelper 4 | import android.app.Application 5 | import android.content.ComponentName 6 | import android.content.Context 7 | import android.content.Intent 8 | import android.os.Bundle 9 | import de.robv.android.xposed.IXposedHookLoadPackage 10 | import de.robv.android.xposed.XC_MethodHook 11 | import de.robv.android.xposed.XposedBridge 12 | import de.robv.android.xposed.XposedHelpers 13 | import de.robv.android.xposed.callbacks.XC_LoadPackage 14 | 15 | class HookPermissionDefault : IXposedHookLoadPackage { 16 | private var classLoader: ClassLoader? = null 17 | 18 | 19 | override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { 20 | if (lpparam.packageName !="com.android.permissioncontroller") { 21 | return 22 | } 23 | 24 | XposedHelpers.findAndHookMethod(Application::class.java, "attach", Context::class.java, object : XC_MethodHook() { 25 | override fun afterHookedMethod(param: MethodHookParam) { 26 | classLoader = (param.thisObject as Application).classLoader 27 | XposedBridge.log("Hooked into ${lpparam.packageName}") 28 | intentHook() 29 | } 30 | }) 31 | } 32 | 33 | private fun intentHook() { 34 | try { 35 | 36 | XposedHelpers.findAndHookMethod( 37 | "com.android.permissioncontroller.permission.ui.GrantPermissionsActivity", 38 | classLoader, 39 | "onCreate", 40 | Bundle::class.java, 41 | object : XC_MethodHook() { 42 | override fun beforeHookedMethod(param: MethodHookParam) { 43 | 44 | val serviceIntent = Intent().apply { 45 | setComponent( 46 | ComponentName( 47 | "com.mja.reyamf", 48 | "com.mja.reyamf.manager.services.SidebarHiderService" 49 | ) 50 | ) 51 | putExtra("act", "KILL") 52 | } 53 | AndroidAppHelper.currentApplication().startService(serviceIntent) 54 | } 55 | } 56 | ) 57 | 58 | XposedHelpers.findAndHookMethod( 59 | "com.android.permissioncontroller.permission.ui.GrantPermissionsActivity", 60 | classLoader, 61 | "onDestroy", 62 | object : XC_MethodHook() { 63 | override fun afterHookedMethod(param: MethodHookParam) { 64 | 65 | val serviceIntent = Intent().apply { 66 | setComponent( 67 | ComponentName( 68 | "com.mja.reyamf", 69 | "com.mja.reyamf.manager.services.SidebarHiderService" 70 | ) 71 | ) 72 | putExtra("act", "LAUNCH") 73 | } 74 | AndroidAppHelper.currentApplication().startService(serviceIntent) 75 | } 76 | } 77 | ) 78 | } catch (e: Throwable) { 79 | XposedBridge.log(e) 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/xposed/hook/HookSystem.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.xposed.hook 2 | 3 | import android.content.Intent 4 | import android.content.pm.IPackageManager 5 | import com.github.kyuubiran.ezxhelper.init.EzXHelperInit 6 | import com.github.kyuubiran.ezxhelper.utils.findMethod 7 | import com.github.kyuubiran.ezxhelper.utils.hookAfter 8 | import com.github.kyuubiran.ezxhelper.utils.hookBefore 9 | import com.mja.reyamf.BuildConfig 10 | import com.mja.reyamf.xposed.services.UserService 11 | import com.mja.reyamf.xposed.services.YAMFManager 12 | import com.mja.reyamf.xposed.utils.log 13 | import com.qauxv.util.Initiator 14 | import de.robv.android.xposed.IXposedHookLoadPackage 15 | import de.robv.android.xposed.IXposedHookZygoteInit 16 | import de.robv.android.xposed.XC_MethodHook 17 | import de.robv.android.xposed.callbacks.XC_LoadPackage 18 | import kotlin.concurrent.thread 19 | 20 | 21 | class HookSystem : IXposedHookZygoteInit, IXposedHookLoadPackage { 22 | companion object { 23 | private const val TAG = "reYAMF_HookSystem" 24 | } 25 | 26 | override fun initZygote(startupParam: IXposedHookZygoteInit.StartupParam) { 27 | EzXHelperInit.initZygote(startupParam) 28 | } 29 | 30 | override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { 31 | if (lpparam.packageName != "android") return 32 | log(TAG, "xposed init") 33 | log(TAG, "buildtype: ${BuildConfig.VERSION_NAME}(${BuildConfig.VERSION_CODE}) ${BuildConfig.BUILD_TYPE}") 34 | EzXHelperInit.initHandleLoadPackage(lpparam) 35 | Initiator.init(lpparam.classLoader) 36 | 37 | var serviceManagerHook: XC_MethodHook.Unhook? = null 38 | serviceManagerHook = findMethod("android.os.ServiceManager") { 39 | name == "addService" 40 | }.hookBefore { param -> 41 | if (param.args[0] == "package") { 42 | serviceManagerHook?.unhook() 43 | val pms = param.args[1] as IPackageManager 44 | log(TAG, "Got pms: $pms") 45 | thread { 46 | runCatching { 47 | UserService.register(pms) 48 | log(TAG, "UserService started") 49 | }.onFailure { 50 | log(TAG, "UserService failed to start", it) 51 | } 52 | } 53 | } 54 | } 55 | 56 | var activityManagerServiceSystemReadyHook: XC_MethodHook.Unhook? = null 57 | activityManagerServiceSystemReadyHook = findMethod("com.android.server.am.ActivityManagerService") { 58 | name == "systemReady" 59 | }.hookAfter { 60 | activityManagerServiceSystemReadyHook?.unhook() 61 | YAMFManager.activityManagerService = it.thisObject 62 | YAMFManager.systemReady() 63 | log(TAG, "system ready") 64 | } 65 | 66 | findMethod("com.android.server.am.ActivityManagerService") { 67 | name == "checkBroadcastFromSystem" 68 | }.hookBefore { 69 | val intent = it.args[0] as Intent 70 | if (intent.action == HookLauncher.ACTION_RECEIVE_LAUNCHER_CONFIG) 71 | it.result = Unit // bypass check 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/xposed/services/UserService.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.xposed.services 2 | 3 | import android.app.ActivityManagerHidden 4 | import android.content.AttributionSource 5 | import android.content.pm.IPackageManager 6 | import android.os.Bundle 7 | import android.os.ServiceManager 8 | import com.mja.reyamf.BuildConfig 9 | import com.mja.reyamf.xposed.utils.log 10 | import rikka.hidden.compat.ActivityManagerApis 11 | import rikka.hidden.compat.adapter.UidObserverAdapter 12 | 13 | object UserService { 14 | const val TAG = "reYAMFUserService" 15 | const val PROVIDER_AUTHORITY = "com.mja.reyamf.ServiceProvider" 16 | 17 | private var appUid = -1 18 | 19 | private val uidObserver = object : UidObserverAdapter() { 20 | override fun onUidActive(uid: Int) { 21 | if (uid != appUid) return 22 | try { 23 | val provider = ActivityManagerApis.getContentProviderExternal( 24 | PROVIDER_AUTHORITY, 25 | 0, 26 | null, 27 | null 28 | ) 29 | if (provider == null) { 30 | log(TAG, "Failed to get content provider") 31 | return 32 | } 33 | val extras = Bundle() 34 | extras.putBinder("binder", YAMFManager) 35 | val attr = AttributionSource.Builder(1000).setPackageName("android").build() 36 | val reply = provider.call(attr, PROVIDER_AUTHORITY, "", null, extras) 37 | if (reply == null) { 38 | log(TAG, "Failed to send binder to app") 39 | return 40 | } 41 | log(TAG, "Send binder to app") 42 | } catch (e: Throwable) { 43 | log(TAG, "Failed to send binder to app", e) 44 | } 45 | } 46 | } 47 | 48 | fun register(pms: IPackageManager) { 49 | log(TAG, "Init YAMFService") 50 | appUid = 51 | pms.getPackageUid(BuildConfig.APPLICATION_ID, 0L, 0) 52 | log(TAG, "App uid: $appUid") 53 | log(TAG, "Register uid observer") 54 | 55 | waitSystemService("activity") 56 | ActivityManagerApis.registerUidObserver( 57 | uidObserver, 58 | ActivityManagerHidden.UID_OBSERVER_ACTIVE, 59 | ActivityManagerHidden.PROCESS_STATE_UNKNOWN, 60 | null 61 | ) 62 | } 63 | 64 | private fun waitSystemService(name: String) { 65 | while (ServiceManager.getService(name) == null) { 66 | Thread.sleep(1000) 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/xposed/utils/AppInfoCache.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.xposed.utils 2 | 3 | import android.content.pm.ActivityInfo 4 | import android.graphics.drawable.Drawable 5 | import androidx.wear.widget.RoundedDrawable 6 | 7 | object AppInfoCache { 8 | fun getIconLabel(info: ActivityInfo): Pair { 9 | return Pair( 10 | RoundedDrawable().apply { 11 | isClipEnabled = true 12 | radius = 100 13 | drawable = info.loadIcon(Instances.packageManager) 14 | }, 15 | info.loadLabel(Instances.packageManager) 16 | ) 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/xposed/utils/Instances.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.xposed.utils 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.ActivityManager 5 | import android.app.IActivityTaskManager 6 | import android.content.Context 7 | import android.content.pm.IPackageManager 8 | import android.content.pm.PackageManager 9 | import android.hardware.display.DisplayManager 10 | import android.hardware.input.IInputManager 11 | import android.os.ServiceManager 12 | import android.os.UserManager 13 | import android.view.IWindowManager 14 | import android.view.WindowManager 15 | import android.widget.FrameLayout 16 | import androidx.constraintlayout.widget.ConstraintLayout 17 | import com.android.internal.statusbar.IStatusBarService 18 | import com.github.kyuubiran.ezxhelper.utils.getObjectAs 19 | 20 | @SuppressLint("StaticFieldLeak") 21 | object Instances { 22 | lateinit var windowManager: WindowManager 23 | private set 24 | lateinit var iWindowManager: IWindowManager 25 | private set 26 | lateinit var inputManager: IInputManager 27 | private set 28 | lateinit var displayManager: DisplayManager 29 | private set 30 | lateinit var activityTaskManager: IActivityTaskManager 31 | private set 32 | lateinit var packageManager: PackageManager 33 | private set 34 | lateinit var activityManager: ActivityManager 35 | private set 36 | lateinit var userManager: UserManager 37 | private set 38 | lateinit var iPackageManager: IPackageManager 39 | private set 40 | lateinit var iStatusBarService: IStatusBarService 41 | private set 42 | private lateinit var activityManagerService: Any 43 | private set 44 | lateinit var systemContext: Context 45 | private set 46 | val systemUiContext: Context 47 | get() = activityManagerService.getObjectAs("mUiContext") 48 | 49 | 50 | fun init(activityManagerService: Any) { 51 | Instances.activityManagerService = activityManagerService 52 | systemContext = activityManagerService.getObjectAs("mContext") 53 | windowManager = systemContext.getSystemService(WindowManager::class.java) 54 | iWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window")) 55 | inputManager = IInputManager.Stub.asInterface(ServiceManager.getService("input")) 56 | displayManager = systemContext.getSystemService(DisplayManager::class.java) 57 | activityTaskManager = 58 | IActivityTaskManager.Stub.asInterface(ServiceManager.getService("activity_task")) 59 | packageManager = systemContext.packageManager 60 | activityManager = systemContext.getSystemService(ActivityManager::class.java) 61 | userManager = systemContext.getSystemService(UserManager::class.java) 62 | iPackageManager = IPackageManager.Stub.asInterface(ServiceManager.getService("package")) 63 | iStatusBarService = 64 | IStatusBarService.Stub.asInterface(ServiceManager.getService("statusbar")) 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/xposed/utils/RunMainThreadQueue.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.xposed.utils 2 | 3 | import com.mja.reyamf.common.runMain 4 | import kotlinx.coroutines.CoroutineScope 5 | import java.util.LinkedList 6 | 7 | object RunMainThreadQueue { 8 | private val queue = LinkedList Unit>() 9 | 10 | @Synchronized 11 | fun add(run: suspend CoroutineScope.() -> Unit) { 12 | queue.offer(run) 13 | if (queue.size == 1) { 14 | runMain { 15 | while (queue.isNotEmpty()) { 16 | queue.poll()?.invoke(this) 17 | } 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/xposed/utils/TipUtil.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.xposed.utils 2 | 3 | import android.annotation.SuppressLint 4 | import android.widget.Toast 5 | 6 | @SuppressLint("StaticFieldLeak") 7 | object TipUtil { 8 | fun showToast(msg: String) { 9 | Toast.makeText(Instances.systemContext, "[reYAMF] $msg", Toast.LENGTH_LONG).show() 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/java/com/mja/reyamf/xposed/utils/Utils.kt: -------------------------------------------------------------------------------- 1 | package com.mja.reyamf.xposed.utils 2 | 3 | import android.animation.Animator 4 | import android.animation.AnimatorListenerAdapter 5 | import android.animation.AnimatorSet 6 | import android.animation.ValueAnimator 7 | import android.annotation.SuppressLint 8 | import android.app.ActivityOptions 9 | import android.app.ActivityTaskManager 10 | import android.content.BroadcastReceiver 11 | import android.content.ComponentName 12 | import android.content.Context 13 | import android.content.ContextParams 14 | import android.content.Intent 15 | import android.content.pm.ActivityInfo 16 | import android.content.pm.IPackageManagerHidden 17 | import android.content.res.Resources 18 | import android.os.Bundle 19 | import android.os.UserHandle 20 | import android.os.VibrationEffect 21 | import android.os.Vibrator 22 | import android.provider.Settings 23 | import android.util.TypedValue 24 | import android.view.View 25 | import android.view.animation.AccelerateDecelerateInterpolator 26 | import android.view.animation.AlphaAnimation 27 | import android.view.animation.Animation 28 | import android.view.animation.ScaleAnimation 29 | import com.github.kyuubiran.ezxhelper.utils.Log 30 | import com.github.kyuubiran.ezxhelper.utils.argTypes 31 | import com.github.kyuubiran.ezxhelper.utils.args 32 | import com.github.kyuubiran.ezxhelper.utils.invokeMethod 33 | import com.github.kyuubiran.ezxhelper.utils.newInstance 34 | import com.mja.reyamf.common.model.StartCmd 35 | import com.mja.reyamf.common.onException 36 | import com.mja.reyamf.xposed.services.YAMFManager 37 | import net.bytebuddy.android.AndroidClassLoadingStrategy 38 | import java.io.File 39 | import de.robv.android.xposed.XposedBridge 40 | 41 | fun log(tag: String, message: String) { 42 | XposedBridge.log("[$tag] $message") 43 | } 44 | 45 | fun log(tag: String, message: String, t: Throwable) { 46 | XposedBridge.log("[$tag] $message") 47 | XposedBridge.log(t) 48 | } 49 | 50 | @SuppressLint("MissingPermission") 51 | fun moveTask(taskId: Int, displayId: Int) { 52 | Instances.activityTaskManager.moveRootTaskToDisplay(taskId, displayId) 53 | Instances.activityManager.moveTaskToFront(taskId, 0) 54 | } 55 | 56 | fun Number.dpToPx() = 57 | TypedValue.applyDimension( 58 | TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics 59 | ) 60 | 61 | val emptyContextParams = ContextParams.Builder().build() 62 | 63 | fun Context.createContext() = createContext(emptyContextParams) 64 | 65 | fun startActivity(context: Context, componentName: ComponentName, userId: Int, displayId: Int) { 66 | context.invokeMethod( 67 | "startActivityAsUser", 68 | args( 69 | Intent().apply { 70 | addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 71 | component = componentName 72 | `package` = component!!.packageName 73 | action = Intent.ACTION_VIEW 74 | }, 75 | ActivityOptions.makeBasic().apply { 76 | launchDisplayId = displayId 77 | this.invokeMethod("setCallerDisplayId", args(displayId), argTypes(Integer.TYPE)) 78 | }.toBundle(), 79 | UserHandle::class.java.newInstance( 80 | args(userId), 81 | argTypes(Integer.TYPE) 82 | ) 83 | ), argTypes(Intent::class.java, Bundle::class.java, UserHandle::class.java) 84 | ) 85 | } 86 | 87 | fun moveToDisplay(context: Context, taskId: Int, componentName: ComponentName, userId: Int, displayId: Int) { 88 | when (YAMFManager.config.windowfy) { 89 | 0 -> { 90 | runCatching { 91 | moveTask(taskId, displayId) 92 | }.onException { 93 | TipUtil.showToast("Unable to move task $taskId") 94 | } 95 | } 96 | 1 -> { 97 | runCatching { 98 | startActivity(context, componentName, userId, displayId) 99 | }.onException { 100 | TipUtil.showToast("Unable to start activity $componentName") 101 | } 102 | } 103 | 2 -> { 104 | runCatching { 105 | moveTask(taskId, displayId) 106 | }.onException { 107 | TipUtil.showToast("Unable to move task $taskId") 108 | runCatching { 109 | startActivity(context, componentName, userId, displayId) 110 | }.onException { 111 | TipUtil.showToast("Unable to start activity $componentName") 112 | } 113 | } 114 | } 115 | } 116 | } 117 | 118 | fun StartCmd.startAuto(displayId: Int) { 119 | when { 120 | canStartActivity && canMoveTask -> 121 | moveToDisplay(Instances.systemContext, taskId!!, componentName!!, userId!!, displayId) 122 | canMoveTask -> { 123 | runCatching { 124 | moveTask(taskId!!, displayId) 125 | }.onException { 126 | TipUtil.showToast("can't move task $taskId") 127 | } 128 | } 129 | canStartActivity -> { 130 | runCatching { 131 | startActivity(Instances.systemContext, componentName!!, userId!!, displayId) 132 | }.onException { 133 | TipUtil.showToast("can't start activity $componentName") 134 | } 135 | } 136 | } 137 | } 138 | 139 | fun getTopRootTask(displayId: Int): ActivityTaskManager.RootTaskInfo? { 140 | Instances.activityTaskManager.getAllRootTaskInfosOnDisplay(displayId).forEach { task -> 141 | if (task.visible) 142 | return task 143 | } 144 | return null 145 | } 146 | 147 | fun Context.registerReceiver(action: String, onReceive: BroadcastReceiver.(Context, Intent) -> Unit) { 148 | registerReceiver(object : BroadcastReceiver() { 149 | override fun onReceive(context: Context, intent: Intent) { 150 | onReceive(this, context, intent) 151 | } 152 | }, android.content.IntentFilter(action), Context.RECEIVER_EXPORTED) 153 | } 154 | 155 | 156 | val ActivityInfo.componentName: ComponentName 157 | get() = ComponentName(packageName, name) 158 | 159 | fun IPackageManagerHidden.getActivityInfoCompat(className: ComponentName, flags: Int, userId: Int): ActivityInfo = 160 | getActivityInfo(className, flags.toLong(), userId) 161 | 162 | fun vibratePhone(context: Context) { 163 | val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator 164 | vibrator.vibrate(VibrationEffect.createOneShot(25, VibrationEffect.DEFAULT_AMPLITUDE)) 165 | } 166 | 167 | fun animateResize( 168 | view: View, 169 | startWidth: Int, 170 | endWidth: Int, 171 | startHeight: Int, 172 | endHeight: Int, 173 | context: Context, 174 | baseDuration: Long = 300L, 175 | onEnd: (() -> Unit)? = null 176 | ) { 177 | val scale = try { 178 | Settings.Global.getFloat(context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE) 179 | } catch (e: Settings.SettingNotFoundException) { 180 | 1.0f // fallback to normal scale if not found 181 | } 182 | 183 | val adjustedDuration = (baseDuration * scale).toLong() 184 | 185 | val widthAnimator = ValueAnimator.ofInt(startWidth, endWidth).apply { 186 | addUpdateListener { animator -> 187 | val value = animator.animatedValue as Int 188 | val params = view.layoutParams 189 | params.width = value 190 | view.layoutParams = params 191 | } 192 | } 193 | 194 | val heightAnimator = ValueAnimator.ofInt(startHeight, endHeight).apply { 195 | addUpdateListener { animator -> 196 | val value = animator.animatedValue as Int 197 | val params = view.layoutParams 198 | params.height = value 199 | view.layoutParams = params 200 | } 201 | } 202 | 203 | AnimatorSet().apply { 204 | playTogether(widthAnimator, heightAnimator) 205 | duration = adjustedDuration 206 | interpolator = AccelerateDecelerateInterpolator() 207 | addListener(object : AnimatorListenerAdapter() { 208 | override fun onAnimationEnd(animation: Animator) { 209 | onEnd?.invoke() 210 | } 211 | }) 212 | start() 213 | } 214 | } 215 | 216 | fun animateScaleThenResize( 217 | view: View, 218 | startX: Float, 219 | startY: Float, 220 | endX: Float, 221 | endY: Float, 222 | pivotX: Float, 223 | pivotY: Float, 224 | endWidth: Int, 225 | endHeight: Int, 226 | context: Context, 227 | baseDuration: Long = 300L, 228 | onEnd: (() -> Unit)? = null 229 | ) { 230 | val scale = try { 231 | Settings.Global.getFloat(context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE) 232 | } catch (e: Settings.SettingNotFoundException) { 233 | 1.0f 234 | } 235 | 236 | val adjustedDuration = (baseDuration * scale).toLong() 237 | 238 | val scaleAnimation = ScaleAnimation( 239 | startX, endX, 240 | startY, endY, 241 | Animation.RELATIVE_TO_SELF, pivotX, 242 | Animation.RELATIVE_TO_SELF, pivotY 243 | ).apply { 244 | duration = adjustedDuration 245 | fillAfter = false 246 | interpolator = AccelerateDecelerateInterpolator() 247 | setAnimationListener(object : Animation.AnimationListener { 248 | override fun onAnimationStart(animation: Animation?) {} 249 | 250 | override fun onAnimationEnd(animation: Animation?) { 251 | val params = view.layoutParams 252 | params.width = endWidth 253 | params.height = endHeight 254 | view.layoutParams = params 255 | onEnd?.invoke() 256 | } 257 | 258 | override fun onAnimationRepeat(animation: Animation?) {} 259 | }) 260 | } 261 | 262 | view.startAnimation(scaleAnimation) 263 | } 264 | 265 | 266 | fun animateAlpha(view: View, startAlpha: Float, endAlpha: Float, onEnd: (() -> Unit)? = null) { 267 | if (endAlpha == 1F) view.visibility = View.VISIBLE 268 | val animation1 = AlphaAnimation(startAlpha, endAlpha) 269 | animation1.duration = 300 270 | 271 | animation1.setAnimationListener(object : Animation.AnimationListener { 272 | override fun onAnimationStart(animation: Animation?) {} 273 | 274 | override fun onAnimationEnd(animation: Animation?) { 275 | onEnd?.invoke() 276 | } 277 | 278 | override fun onAnimationRepeat(animation: Animation?) {} 279 | }) 280 | 281 | view.startAnimation(animation1) 282 | if (endAlpha == 1F) view.visibility = View.VISIBLE else view.visibility = View.GONE 283 | } 284 | 285 | val byteBuddyStrategy = AndroidClassLoadingStrategy.Wrapping(File("/data/system/reYAMF").also { it.mkdirs() }) 286 | -------------------------------------------------------------------------------- /app/src/main/java/com/qauxv/ui/CommonContextWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * QAuxiliary - An Xposed module for QQ/TIM 3 | * Copyright (C) 2019-2022 qwq233@qwq2333.top 4 | * https://github.com/cinit/QAuxiliary 5 | * 6 | * This software is non-free but opensource software: you can redistribute it 7 | * and/or modify it under the terms of the GNU Affero General Public License 8 | * as published by the Free Software Foundation; either 9 | * version 3 of the License, or any later version and our eula as published 10 | * by QAuxiliary contributors. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Affero General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Affero General Public License 18 | * and eula along with this software. If not, see 19 | * 20 | * . 21 | */ 22 | 23 | package com.qauxv.ui; 24 | 25 | import android.annotation.SuppressLint; 26 | import android.content.Context; 27 | import android.content.res.Configuration; 28 | import android.content.res.Resources; 29 | import android.content.res.TypedArray; 30 | import android.view.ContextThemeWrapper; 31 | 32 | import androidx.annotation.NonNull; 33 | import androidx.annotation.Nullable; 34 | import androidx.appcompat.app.AppCompatActivity; 35 | 36 | import com.github.kyuubiran.ezxhelper.init.EzXHelperInit; 37 | import com.mja.reyamf.R; 38 | import com.qauxv.util.SavedInstanceStatePatchedClassReferencer; 39 | 40 | import java.util.Objects; 41 | 42 | /** 43 | * If you just want to create a MaterialDialog or AppCompatDialog, see {@link #createMaterialDesignContext(Context)} and 44 | * {@link #createAppCompatContext(Context)} 45 | **/ 46 | public class CommonContextWrapper extends ContextThemeWrapper { 47 | 48 | /** 49 | * Creates a new context wrapper with the specified theme with correct module ClassLoader. 50 | * 51 | * @param base the base context 52 | * @param theme the resource ID of the theme to be applied on top of the base context's theme 53 | */ 54 | public CommonContextWrapper(@NonNull Context base, int theme) { 55 | this(base, theme, null); 56 | } 57 | 58 | /** 59 | * Creates a new context wrapper with the specified theme with correct module ClassLoader. 60 | * 61 | * @param base the base context 62 | * @param theme the resource ID of the theme to be applied on top of the base context's theme 63 | * @param configuration the configuration to override the base one 64 | */ 65 | public CommonContextWrapper(@NonNull Context base, int theme, 66 | @Nullable Configuration configuration) { 67 | super(base, theme); 68 | if (configuration != null) { 69 | mOverrideResources = base.createConfigurationContext(configuration).getResources(); 70 | } 71 | EzXHelperInit.INSTANCE.addModuleAssetPath(getResources()); 72 | } 73 | 74 | private ClassLoader mXref = null; 75 | private Resources mOverrideResources; 76 | 77 | @NonNull 78 | @Override 79 | public ClassLoader getClassLoader() { 80 | if (mXref == null) { 81 | mXref = new SavedInstanceStatePatchedClassReferencer( 82 | CommonContextWrapper.class.getClassLoader()); 83 | } 84 | return mXref; 85 | } 86 | 87 | @Nullable 88 | private static Configuration recreateNighModeConfig(@NonNull Context base, int uiNightMode) { 89 | Objects.requireNonNull(base, "base is null"); 90 | Configuration baseConfig = base.getResources().getConfiguration(); 91 | if ((baseConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) == uiNightMode) { 92 | // config for base context is already what we want, 93 | // just return null to avoid unnecessary override 94 | return null; 95 | } 96 | Configuration conf = new Configuration(); 97 | conf.uiMode = uiNightMode | (baseConfig.uiMode & ~Configuration.UI_MODE_NIGHT_MASK); 98 | return conf; 99 | } 100 | 101 | @NonNull 102 | @Override 103 | public Resources getResources() { 104 | if (mOverrideResources == null) { 105 | return super.getResources(); 106 | } else { 107 | return mOverrideResources; 108 | } 109 | } 110 | 111 | public static boolean isAppCompatContext(@NonNull Context context) { 112 | if (!checkContextClassLoader(context)) { 113 | return false; 114 | } 115 | TypedArray a = context.obtainStyledAttributes(androidx.appcompat.R.styleable.AppCompatTheme); 116 | try { 117 | return a.hasValue(androidx.appcompat.R.styleable.AppCompatTheme_windowActionBar); 118 | } finally { 119 | a.recycle(); 120 | } 121 | } 122 | 123 | private static final int[] MATERIAL_CHECK_ATTRS = {com.google.android.material.R.attr.colorPrimaryVariant}; 124 | 125 | public static boolean isMaterialDesignContext(@NonNull Context context) { 126 | if (!isAppCompatContext(context)) { 127 | return false; 128 | } 129 | @SuppressLint("ResourceType") TypedArray a = context.obtainStyledAttributes(MATERIAL_CHECK_ATTRS); 130 | try { 131 | return a.hasValue(0); 132 | } finally { 133 | a.recycle(); 134 | } 135 | } 136 | 137 | public static boolean checkContextClassLoader(@NonNull Context context) { 138 | try { 139 | ClassLoader cl = context.getClassLoader(); 140 | if (cl == null) { 141 | return false; 142 | } 143 | return cl.loadClass(AppCompatActivity.class.getName()) == AppCompatActivity.class; 144 | } catch (ClassNotFoundException e) { 145 | return false; 146 | } 147 | } 148 | 149 | @NonNull 150 | public static Context createAppCompatContext(@NonNull Context base) { 151 | if (isAppCompatContext(base)) { 152 | return base; 153 | } 154 | return new CommonContextWrapper(base, R.style.Base_Theme_Reyamf, 155 | recreateNighModeConfig(base, base.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)); 156 | } 157 | 158 | @NonNull 159 | public static Context createMaterialDesignContext(@NonNull Context base) { 160 | if (isMaterialDesignContext(base)) { 161 | return base; 162 | } 163 | // currently all themes by createAppCompatContext are material themes 164 | // change this if you have a AppCompat theme that is not material theme 165 | return createAppCompatContext(base); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /app/src/main/java/com/qauxv/util/Initiator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * QAuxiliary - An Xposed module for QQ/TIM 3 | * Copyright (C) 2019-2022 qwq233@qwq2333.top 4 | * https://github.com/cinit/QAuxiliary 5 | * 6 | * This software is non-free but opensource software: you can redistribute it 7 | * and/or modify it under the terms of the GNU Affero General Public License 8 | * as published by the Free Software Foundation; either 9 | * version 3 of the License, or any later version and our eula as published 10 | * by QAuxiliary contributors. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Affero General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Affero General Public License 18 | * and eula along with this software. If not, see 19 | * 20 | * . 21 | */ 22 | package com.qauxv.util; 23 | 24 | public class Initiator { 25 | private static ClassLoader sHostClassLoader; 26 | 27 | private Initiator() { 28 | throw new AssertionError("No instance for you!"); 29 | } 30 | 31 | public static void init(ClassLoader classLoader) { 32 | sHostClassLoader = classLoader; 33 | } 34 | 35 | public static ClassLoader getPluginClassLoader() { 36 | return Initiator.class.getClassLoader(); 37 | } 38 | 39 | public static ClassLoader getHostClassLoader() { 40 | return sHostClassLoader; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/qauxv/util/SavedInstanceStatePatchedClassReferencer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * QAuxiliary - An Xposed module for QQ/TIM 3 | * Copyright (C) 2019-2022 qwq233@qwq2333.top 4 | * https://github.com/cinit/QAuxiliary 5 | * 6 | * This software is non-free but opensource software: you can redistribute it 7 | * and/or modify it under the terms of the GNU Affero General Public License 8 | * as published by the Free Software Foundation; either 9 | * version 3 of the License, or any later version and our eula as published 10 | * by QAuxiliary contributors. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Affero General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Affero General Public License 18 | * and eula along with this software. If not, see 19 | * 20 | * . 21 | */ 22 | 23 | package com.qauxv.util; 24 | 25 | import android.content.Context; 26 | 27 | import java.util.Objects; 28 | 29 | public class SavedInstanceStatePatchedClassReferencer extends ClassLoader { 30 | 31 | private static final ClassLoader mBootstrap = Context.class.getClassLoader(); 32 | private final ClassLoader mBaseReferencer; 33 | private final ClassLoader mHostReferencer; 34 | 35 | public SavedInstanceStatePatchedClassReferencer(ClassLoader referencer) { 36 | super(mBootstrap); 37 | mBaseReferencer = Objects.requireNonNull(referencer); 38 | mHostReferencer = Initiator.getHostClassLoader(); 39 | } 40 | 41 | @Override 42 | protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { 43 | try { 44 | return mBootstrap.loadClass(name); 45 | } catch (ClassNotFoundException ignored) {} 46 | if (mHostReferencer != null) { 47 | try { 48 | //start: overloaded 49 | if ("androidx.lifecycle.ReportFragment".equals(name)) { 50 | return mHostReferencer.loadClass(name); 51 | } 52 | } catch (ClassNotFoundException ignored) {} 53 | } 54 | //with ClassNotFoundException 55 | return mBaseReferencer.loadClass(name); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/a_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bar_corners_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_apps_24.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_keyboard_double_arrow_left_24.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_restart_alt_24.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/src/main/res/drawable/demo.gif -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_back.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_error_outline_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_maximize.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_minimize.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_picture_in_picture_alt_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_check_circle_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_warning_amber_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/three_dot_horiz.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/work_icon.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout-land/sidebar_itemview.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 19 | 20 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_app.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/sidebar_itemview.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 19 | 20 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/sidebar_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 26 | 27 | 36 | 37 | 46 | 47 | 59 | 60 | 70 | 71 | 81 | 82 | 98 | 99 | 111 | 112 | 113 | 114 | 126 | 127 | 128 | 129 | 139 | 140 | 144 | 145 | 153 | 154 | 163 | 164 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /app/src/main/res/layout/window_app.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 23 | 24 | 32 | 38 | 39 | 40 | 50 | 51 | 58 | 59 | 66 | 67 | 75 | 76 | 86 | 87 | 98 | 99 | 111 | 112 | 122 | 123 | 124 | 125 | 135 | 136 | 137 | 138 | 144 | 145 | 155 | 156 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /app/src/main/res/layout/window_app_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 22 | 23 | 32 | 33 | 41 | 42 | 49 | 50 | 55 | 56 | 57 | 68 | 69 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | 14 | 18 | 22 | 26 | 31 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JuanArton/reYAMF/7304df7dbb912f560876e2cdf86b5d8fa22851a0/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #20FFFFFF 4 | #60FFFFFF 5 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | reYAMF 3 | 详情 4 | 未知错误 5 | 模块已激活 6 | 模块已更新,需要重启 7 | 模块未激活 8 | 现有窗口可以正常使用\n但新窗口可能导致系统崩溃 9 | 重启 10 | 设置 11 | 打开次数 12 | 新建窗口 13 | 打开应用列表 14 | Telegram 频道 15 | 捐赠 16 | 返回 17 | 最小化 18 | 调整窗口大小 19 | 最大化 20 | 关闭 21 | 为类 AOSP 系统提供自由窗口 22 | 系统版本 23 | 自由窗口 24 | 进入窗口 25 | 构建类型 26 | 重置所有窗口 27 | x 28 | 默认窗口大小 29 | 在窗口中显示输入法\n必须启用 VIRTUAL_DISPLAY_FLAG_PUBLIC 30 | 保持 reYAMF 在后台运行 31 | 折叠视图的应用图标 32 | 哇!\n空荡荡~ 33 | 启用侧边栏 34 | 开机自启 35 | 注意: 36 | 如果你无法接受任何应用的权限请求, 这是因为侧边栏覆盖了屏幕 37 | 点击侧边栏上的此按钮关闭侧边栏 38 | 或点击此按钮临时关闭侧边栏,侧边栏会在5秒后重新出现 39 | reYAMF 40 | a YAMF fork 41 | 视图类型 42 | DPI 密度 43 | 高级参数 44 | 彩色控制按钮 45 | 启动方式 46 | 最近任务返回主页 47 | 支持在最近任务界面启动小窗 48 | 支持任务栏启动小窗 49 | 支持长按应用启动小窗 50 | 支持临时任务栏启动小窗 51 | 使用应用列表 52 | 强制显示输入法 53 | * 桌面启动器可能需要重启两次才能生效 54 | 将当前应用切换为小窗 55 | 启动侧边栏 56 | DPI 缩减 57 | 侧边栏透明度 58 | 80 59 | 窗口圆角大小 60 | 20 61 | 右置侧边栏 62 | 63 | -------------------------------------------------------------------------------- /app/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | android 5 | com.motorola.launcher3 6 | com.android.launcher3 7 | com.google.android.apps.nexuslauncher 8 | com.google.android.permissioncontroller 9 | com.android.permissioncontroller 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FBC02D 4 | #FF000000 5 | 6 | //dark theme 7 | #cdcccc 8 | #20000000 9 | #60000000 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0dp 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #000000 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | reYAMF 3 | Details 4 | Unknown Error 5 | Module Is Activated! 6 | Version change, reboot required 7 | Module is not activated. 8 | Existing windows are fine\nBut new window may make system crash 9 | Reboot 10 | Settings 11 | Open Count 12 | New window 13 | Open app list 14 | Telegram channel 15 | donate 16 | back 17 | minimize 18 | resize window 19 | maximize 20 | close 21 | Freeform window for AOSP-like systems 22 | System version 23 | Freeform 24 | enter window 25 | Build Type 26 | reset all window 27 | x 28 | Default Window Size 29 | Show IME in window\nVIRTUAL_DISPLAY_FLAG_PUBLIC must be true 30 | Keeps reYAMF alive in the background 31 | app icon for collapsed view 32 | Wow! \nSuch empty 33 | Enable Sidebar 34 | Launch at startup 35 | Note : 36 | IF YOU CAN\'T ACCEPT ANY APP PERMISSION REQUEST. That\'s because the sidebar is overlaying the screen. 37 | Close the sidebar using this button on the sidebar 38 | Or use this button to close sidebar for 5 seconds. Sidebar will reappaer automatically 39 | reYAMF 40 | a YAMF fork 41 | View Type 42 | DPI Density 43 | Flags 44 | Colored Controller 45 | Launch Method 46 | Recents Back Home 47 | Recents App Icon Hook 48 | Taskbar Hook 49 | App Long Press Hook 50 | Transient Taskbar Hook 51 | Use App List 52 | Force Show IME 53 | * Launcher might need to be restarted twice for hooks to take effect 54 | Current to window 55 | Launch sidebar 56 | Reduce DPI 57 | Sidebar Transparency 58 | 80 59 | Window Rounded Corner 60 | 20 61 | Sidebar Position 62 | 63 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 |