├── .gitattributes ├── .gitignore ├── 1.png ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── suspension-fab-1.1.0.aar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── config │ │ ├── cn.kuwo.player.json │ │ ├── com.kugou.android.json │ │ ├── com.tencent.karaoke.json │ │ ├── com.tencent.qqmusiclocalplayer.json │ │ ├── me.singleneuron.originalmusicnotification_debugtool.json │ │ ├── packages.json │ │ └── version.json │ └── xposed_init │ ├── java │ ├── cn │ │ └── nexus6p │ │ │ ├── QQMusicNotify │ │ │ ├── BackgroundActivity.kt │ │ │ ├── Base │ │ │ │ ├── BasicInit.java │ │ │ │ ├── BasicNotification.java │ │ │ │ ├── BasicParam.kt │ │ │ │ ├── BasicViewNotification.java │ │ │ │ └── HookInterface.java │ │ │ ├── ContentProvider.kt │ │ │ ├── Fragment │ │ │ │ ├── AppsFragment.java │ │ │ │ ├── DetailFragment.kt │ │ │ │ ├── ExperimentalFragment.java │ │ │ │ ├── JsonDetailFragment.kt │ │ │ │ ├── LogFragment.kt │ │ │ │ ├── MediaNotificationFragment.java │ │ │ │ ├── MusicNotificationFragment.java │ │ │ │ ├── PlayingFragment.kt │ │ │ │ ├── SettingFragment.kt │ │ │ │ ├── SettingsFragment.java │ │ │ │ ├── ThirdPartySourceFragment.kt │ │ │ │ └── ThirdPartySourceListFragment.kt │ │ │ ├── Hook │ │ │ │ ├── cnkuwoplayer.java │ │ │ │ ├── comkugouandroid.java │ │ │ │ ├── comneteasecloudmusic.java │ │ │ │ ├── comsingclient.java │ │ │ │ ├── comtencentkaraoke.java │ │ │ │ ├── comtencentqqmusic.java │ │ │ │ ├── comtencentqqmusiclocalplayer.java │ │ │ │ └── mesingleneuronoriginalmusicnotification_debugtool.kt │ │ │ ├── MainActivity.java │ │ │ ├── SharedPreferences │ │ │ │ ├── BasePreference.kt │ │ │ │ └── ContentProviderPreference.kt │ │ │ ├── SimpleAlcatrazInteractiveCardView.kt │ │ │ ├── Utils │ │ │ │ ├── GeneralUtils.java │ │ │ │ ├── HookStatue.java │ │ │ │ ├── LogUtils.kt │ │ │ │ ├── MediaSessionTokenHashMap.java │ │ │ │ └── PreferenceUtil.java │ │ │ └── initHook.java │ │ │ └── removewhitenotificationforbugme │ │ │ └── main.java │ ├── me │ │ └── qiwu │ │ │ └── MusicNotification │ │ │ ├── ColorUtil.java │ │ │ └── NotificationHook.java │ ├── name │ │ └── mikanoshi │ │ │ └── customiuizer │ │ │ └── mods │ │ │ └── System.java │ └── soptqs │ │ └── medianotification │ │ └── utils │ │ ├── ColorUtils.java │ │ ├── ImageUtils.java │ │ ├── NotificationUtils.java │ │ ├── PaletteUtils.java │ │ └── PreferenceUtils.java │ └── res │ ├── anim │ ├── slide_left_in.xml │ ├── slide_left_out.xml │ ├── slide_right_in.xml │ └── slide_right_out.xml │ ├── drawable-hdpi │ ├── ic_add.png │ ├── ic_check.png │ ├── ic_music.png │ ├── ic_pause.png │ ├── ic_play.png │ ├── ic_skip_next.png │ ├── ic_skip_previous.png │ ├── ic_stop.png │ ├── ic_thumb_down.png │ └── ic_thumb_up.png │ ├── drawable-mdpi │ ├── ic_add.png │ ├── ic_check.png │ ├── ic_music.png │ ├── ic_pause.png │ ├── ic_play.png │ ├── ic_skip_next.png │ ├── ic_skip_previous.png │ ├── ic_stop.png │ ├── ic_thumb_down.png │ └── ic_thumb_up.png │ ├── drawable-night │ ├── ic_github.xml │ └── ic_mail_outline.xml │ ├── drawable-v21 │ ├── ic_add.xml │ ├── ic_check.xml │ ├── ic_music.xml │ ├── ic_pause.xml │ ├── ic_play.xml │ ├── ic_skip_next.xml │ ├── ic_skip_previous.xml │ ├── ic_stop.xml │ ├── ic_thumb_down.xml │ └── ic_thumb_up.xml │ ├── drawable-xhdpi │ ├── ic_add.png │ ├── ic_check.png │ ├── ic_music.png │ ├── ic_pause.png │ ├── ic_play.png │ ├── ic_skip_next.png │ ├── ic_skip_previous.png │ ├── ic_stop.png │ ├── ic_thumb_down.png │ └── ic_thumb_up.png │ ├── drawable-xxhdpi │ ├── ic_add.png │ ├── ic_check.png │ ├── ic_music.png │ ├── ic_pause.png │ ├── ic_play.png │ ├── ic_skip_next.png │ ├── ic_skip_previous.png │ ├── ic_stop.png │ ├── ic_thumb_down.png │ └── ic_thumb_up.png │ ├── drawable │ ├── background_image.xml │ ├── color_drawable.xml │ ├── edxp.webp │ ├── edxp_icon.png │ ├── ic_cancel.xml │ ├── ic_check_circle.xml │ ├── ic_delete_black_24dp.xml │ ├── ic_github.xml │ ├── ic_mail_outline.xml │ ├── ic_music.png │ ├── ic_refresh_black_24dp.xml │ ├── ic_settings_black_24dp.xml │ ├── ic_telegram_logo.xml │ ├── icon.webp │ ├── miui.webp │ ├── singleneuron.webp │ └── taichi.webp │ ├── layout-v24 │ ├── layout_notification_collapsed.xml │ ├── layout_notification_collapsed_stlye2.xml │ ├── layout_notification_expanded.xml │ └── layout_notification_expanded_stlye2.xml │ ├── layout │ ├── layout_notification_collapsed.xml │ ├── layout_notification_collapsed_stlye2.xml │ ├── layout_notification_expanded.xml │ ├── layout_notification_expanded_stlye2.xml │ ├── log_fragment.xml │ ├── main_activity.xml │ ├── notifition_layout.xml │ ├── setting_fragment.xml │ ├── simple_alcatraz_interactive_cardview.xml │ └── third_party_source.xml │ ├── values-night │ └── colors.xml │ ├── values │ ├── colors.xml │ ├── integers.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ ├── apps.xml │ ├── detail.xml │ ├── experimental.xml │ ├── file_paths.xml │ ├── json_detail.xml │ ├── media_notification.xml │ ├── music_notification.xml │ ├── settings.xml │ └── third_party_source.xml ├── build.gradle ├── debugTool ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── me │ │ └── singleneuron │ │ └── originalmusicnotification_debugtool │ │ └── MainActivity.java │ └── res │ └── layout │ └── activity_main.xml ├── google-play-badge.png ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── icon_原生音乐通知_new.png ├── icon_原生音乐通知_new_512.png ├── nexus6pcn.jks ├── settings.gradle ├── singleneuron.png ├── singleneuron_me.jks ├── 未标题-1.psd └── 演示文稿1.ppt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/dictionaries 41 | .idea/libraries 42 | 43 | # Keystore files 44 | 45 | # External native build folder generated in Android Studio 2.2 and later 46 | .externalNativeBuild 47 | 48 | # Google Services (e.g. APIs or Firebase) 49 | google-services.json 50 | 51 | # Freeline 52 | freeline.py 53 | freeline/ 54 | freeline_project_description.json 55 | 56 | 捕获.PNG 57 | 58 | .idea/ 59 | 60 | app/debug/output.json 61 | .vscode/ 62 | keystore.properties 63 | .settings 64 | .classpath 65 | .settings/ 66 | .settings/org.eclipse.buildship.core.prefs 67 | .projeck -------------------------------------------------------------------------------- /1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/1.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 原生音乐通知 2 | 3 | [![license](https://img.shields.io/badge/license-LGPL-blue.svg)](https://github.com/hefuyicoder/ListenerMusicPlayer#license) 4 | [![platform](https://img.shields.io/badge/platform-Android-yellow.svg)](https://www.android.com) 5 | [![API](https://img.shields.io/badge/API-29-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=29) 6 | [![google play](./google-play-badge.png)](https://play.google.com/store/apps/details?id=cn.nexus6p.QQMusicNotify) 7 | ![build](https://build.appcenter.ms/v0.1/apps/732e2543-af12-4359-b442-c42f10134490/branches/master/badge) 8 | 9 | ![](1.png) 10 | An xposed moudle trying to make music player using standard notification 11 | 12 | Supported App: 轻听、全民K歌、酷我音乐、5Sing 13 | Supported System: AOSP Based、MIUI、Flyme…… 14 | 15 | ![](https://user-images.githubusercontent.com/23723294/55279278-d1deb280-5351-11e9-934a-e427462176b8.PNG) 16 | 17 | 欢迎加入某些不靠谱插件交流群:951343825 18 | 19 | Telegram Channel/Group: https://t.me/NeuronDevelopChannel 20 | 21 | Canary版CI自动编译下载地址,任何使用风险自负:https://install.appcenter.ms/users/liziyuan123456-yeah.net/apps/xposedmusicnotify/distribution_groups/canary 22 | 23 | ### [隐私权政策](./PrivacyPolicy) 24 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /release -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | compileSdkVersion 29 7 | buildToolsVersion '29.0.3' 8 | 9 | defaultConfig { 10 | applicationId "cn.nexus6p.QQMusicNotify" 11 | minSdkVersion 23 12 | //noinspection OldTargetApi,ExpiredTargetSdkVersion 13 | targetSdkVersion 29 14 | vectorDrawables.useSupportLibrary = true 15 | } 16 | 17 | repositories { 18 | maven { url 'https://jitpack.io' } 19 | } 20 | 21 | buildTypes { 22 | release { 23 | minifyEnabled true 24 | shrinkResources true 25 | zipAlignEnabled true 26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 27 | } 28 | } 29 | 30 | signingConfigs { 31 | release { 32 | if (rootProject.file("keystore.properties").exists()) { 33 | def keystorePropertiesFile = rootProject.file("keystore.properties") 34 | def keystoreProperties = new Properties() 35 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 36 | storeFile file('nexus6pcn.jks') 37 | keyAlias keystoreProperties['keyAlias'] 38 | keyPassword keystoreProperties['keyPassword'] 39 | storePassword keystoreProperties['storePassword'] 40 | } 41 | } 42 | } 43 | 44 | flavorDimensions "type" 45 | productFlavors { 46 | play { 47 | dimension "type" 48 | } 49 | apk { 50 | dimension "type" 51 | } 52 | } 53 | 54 | compileOptions { 55 | sourceCompatibility JavaVersion.VERSION_1_8 56 | targetCompatibility JavaVersion.VERSION_1_8 57 | } 58 | kotlinOptions { 59 | jvmTarget = "1.8" 60 | } 61 | 62 | buildFeatures { 63 | viewBinding = true 64 | } 65 | 66 | applicationVariants.all { variant -> 67 | def buildType = variant.buildType.name 68 | def variantName = variant.productFlavors[0].name 69 | if (buildType == "release" && variantName == "apk") { 70 | //variant.packageApplicationProvider.get().outputDirectory = new File(project.rootDir.absolutePath + "/app/release") 71 | variant.outputs.all { output -> 72 | output.outputFileName = "XposedMusicNotify-" + variant.versionName + "-release.apk" 73 | } 74 | } 75 | } 76 | 77 | } 78 | 79 | task buildAllRelease { 80 | group = 'build' 81 | dependsOn 'bundlePlayRelease' 82 | dependsOn 'assembleApkRelease' 83 | } 84 | 85 | dependencies { 86 | implementation fileTree(dir: 'libs', include: ['*.aar']) 87 | compileOnly 'de.robv.android.xposed:api:82' 88 | implementation 'androidx.preference:preference-ktx:1.1.1' 89 | implementation 'androidx.appcompat:appcompat:1.2.0' 90 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 91 | implementation 'androidx.palette:palette-ktx:1.0.0' 92 | implementation 'com.github.topjohnwu.libsu:core:2.5.1' 93 | implementation 'de.psdev.licensesdialog:licensesdialog:2.1.0' 94 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" 95 | implementation 'com.google.android.material:material:1.3.0-alpha03' 96 | implementation 'io.alcatraz.alcatrazui:libalcatrazui:1.0.0' 97 | implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0" 98 | } 99 | repositories { 100 | mavenCentral() 101 | } 102 | -------------------------------------------------------------------------------- /app/libs/suspension-fab-1.1.0.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/libs/suspension-fab-1.1.0.aar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class cn.nexus6p.QQMusicNotify.*{*;} -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 40 | 41 | 46 | 49 | 50 | 58 | 59 | 62 | 65 | 68 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /app/src/main/assets/config/cn.kuwo.player.json: -------------------------------------------------------------------------------- 1 | { 2 | "versionName": "9.3.1.0", 3 | "versionCode": "9310", 4 | "class": "cn.kuwo.mod.notification.manager.KwNotificationManager", 5 | "method": "getPlayNotification", 6 | "iconID": "7f020c9b", 7 | "drawableClass": "cn.kuwo.player.R$drawable", 8 | "iconField": "notification_icon_white", 9 | "contextField": "mContext", 10 | "preSongIntent": "kuwo.play.pre", 11 | "playSongIntent": "kuwo.play.playing", 12 | "nextSongIntent": "kuwo.play.next", 13 | "IntentHandleActivity": "cn.kuwo.player.activities.EntryActivity", 14 | "getStatusClass": "cn.kuwo.a.b.b", 15 | "getStatusMethod": "r", 16 | "getStatusMethod2": "getStatus", 17 | "playProxyStatusClass": "cn.kuwo.service.PlayProxy$Status", 18 | "playProxyStatusField": "PLAYING", 19 | "extraActionIcon": "7f02058c", 20 | "extraActionIconField": "ic_notification_lrc_on", 21 | "extraActionIntent": "kuwo.desklrc.enable" 22 | } -------------------------------------------------------------------------------- /app/src/main/assets/config/com.kugou.android.json: -------------------------------------------------------------------------------- 1 | { 2 | "versionName": "10.1.0", 3 | "versionCode": "10101", 4 | "class": "com.kugou.common.q.c", 5 | "method1": "bX", 6 | "method2": "aj" 7 | } -------------------------------------------------------------------------------- /app/src/main/assets/config/com.tencent.karaoke.json: -------------------------------------------------------------------------------- 1 | { 2 | "versionName": "6.20.28.278", 3 | "versionCode": "493", 4 | "class": "com.tencent.karaoke.common.media.n", 5 | "method": "a", 6 | "titleID": "7f091d55", 7 | "textID": "7f091d53", 8 | "bitmapID": "7f091d50", 9 | "iconID": "7f0800dd", 10 | "intentClass": "com.tencent.karaoke.common.h$a", 11 | "preSongField": "d", 12 | "playSongField": "a", 13 | "nextSongField": "e", 14 | "deleteField": "b", 15 | "IntentHandleActivity": "com.tencent.karaoke.widget.intent.IntentHandleActivity", 16 | "params": [ 17 | "android.content.Context", 18 | "com.tencent.karaoke.common.media.player.db.PlaySongInfo", 19 | "int", 20 | "java.lang.String", 21 | "android.graphics.drawable.Drawable" 22 | ], 23 | "idClass": "com.tencent.karaoke.R$a", 24 | "titleField": "play_notification_song_name", 25 | "textField": "play_notification_nickname", 26 | "bitmapField": "play_notification_cover" 27 | } -------------------------------------------------------------------------------- /app/src/main/assets/config/com.tencent.qqmusiclocalplayer.json: -------------------------------------------------------------------------------- 1 | { 2 | "versionName": "1.2.2.3", 3 | "versionCode": "27" 4 | } -------------------------------------------------------------------------------- /app/src/main/assets/config/me.singleneuron.originalmusicnotification_debugtool.json: -------------------------------------------------------------------------------- 1 | { 2 | "versionName": "1.0", 3 | "versionCode": "1" 4 | } -------------------------------------------------------------------------------- /app/src/main/assets/config/packages.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "app": "com.tencent.karaoke", 4 | "name": "全民K歌", 5 | "supportedVersion": [ 6 | { 7 | "versionName": "6.7.8.278", 8 | "versionCode": "356" 9 | }, 10 | { 11 | "versionName": "6.9.8.278", 12 | "versionCode": "371" 13 | },{ 14 | "versionName": "6.10.1.273", 15 | "versionCode": "376" 16 | },{ 17 | "versionName": "6.15.28.278", 18 | "versionCode": "438" 19 | },{ 20 | "versionName": "6.19.28.278", 21 | "versionCode": "482" 22 | }, 23 | { 24 | "versionName": "6.20.28.278", 25 | "versionCode": "493" 26 | } 27 | ] 28 | }, 29 | { 30 | "app": "com.tencent.qqmusiclocalplayer", 31 | "name": "轻听", 32 | "supportedVersion": [ 33 | { 34 | "versionName": "1.2.2.3", 35 | "versionCode": "27" 36 | } 37 | ] 38 | }, 39 | { 40 | "app": "com.sing.client", 41 | "name": "5Sing" 42 | }, 43 | { 44 | "app": "cn.kuwo.player", 45 | "name": "酷我音乐", 46 | "supportedVersion": [ 47 | { 48 | "versionName": "9.2.4.0", 49 | "versionCode": "9240" 50 | }, 51 | { 52 | "versionName": "9.2.4.1", 53 | "versionCode": "9241" 54 | }, 55 | { 56 | "versionName": "9.3.0.1", 57 | "versionCode": "9301" 58 | }, 59 | { 60 | "versionName": "9.3.1.0", 61 | "versionCode": "9310" 62 | } 63 | ] 64 | }, 65 | { 66 | "app": "me.singleneuron.originalmusicnotification_debugtool", 67 | "name": "原生音乐通知调试器", 68 | "supportedVersion": [ 69 | { 70 | "versionName": "1.0", 71 | "versionCode": "1" 72 | }, 73 | { 74 | "versionName": "1.1", 75 | "versionCode": "2" 76 | } 77 | ] 78 | }, 79 | { 80 | "app": "com.kugou.android", 81 | "name": "酷狗音乐", 82 | "supportedVersion": [ 83 | { 84 | "versionName": "10.1.0", 85 | "versionCode": "10101" 86 | } 87 | ] 88 | } 89 | ] 90 | -------------------------------------------------------------------------------- /app/src/main/assets/config/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "2.9.2", 3 | "code": 29 4 | } -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | cn.nexus6p.QQMusicNotify.initHook -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/BackgroundActivity.kt: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify 2 | 3 | import android.os.Bundle 4 | import android.util.Log 5 | import android.view.MotionEvent 6 | import androidx.annotation.Keep 7 | import androidx.appcompat.app.AppCompatActivity 8 | 9 | @Keep 10 | class BackgroundActivity : AppCompatActivity() { 11 | 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | Log.d("XposedMusicNotify", "BackgroundActivity已启动") 15 | moveTaskToBack(true) 16 | } 17 | 18 | override fun onBackPressed() { 19 | super.onBackPressed() 20 | this.finish() 21 | } 22 | 23 | override fun dispatchTouchEvent(ev: MotionEvent?): Boolean { 24 | this.finish() 25 | return super.dispatchTouchEvent(ev) 26 | } 27 | 28 | override fun onStart() { 29 | super.onStart() 30 | setVisible(true) 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Base/BasicInit.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Base; 2 | 3 | import android.content.Context; 4 | 5 | public abstract class BasicInit implements HookInterface { 6 | 7 | public BasicParam basicParam = new BasicParam(); 8 | public ClassLoader classLoader; 9 | 10 | @Override 11 | public abstract void init(); 12 | 13 | @Override 14 | public void initBefore() { 15 | init(); 16 | } 17 | 18 | @Override 19 | public final BasicInit setClassLoader(ClassLoader mClassLoader) { 20 | classLoader = mClassLoader; 21 | return this; 22 | } 23 | 24 | @Override 25 | public final BasicInit setContext(Context mContext) { 26 | basicParam.setContext(mContext); 27 | return this; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Base/BasicParam.kt: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Base 2 | 3 | import android.app.PendingIntent 4 | import android.content.Context 5 | import android.graphics.Bitmap 6 | import android.media.session.MediaSession 7 | 8 | class BasicParam { 9 | 10 | constructor() 11 | constructor(mContext: Context, mIcon: Int, mTitle: CharSequence, mText: CharSequence, mBitmap: Bitmap?, mStatue: Boolean, mToken: MediaSession.Token? = null, mIntent: PendingIntent) { 12 | context = mContext 13 | iconID = mIcon 14 | titleString = mTitle 15 | textString = mText 16 | bitmap = mBitmap 17 | statue = mStatue 18 | token = mToken 19 | contentIntent = mIntent 20 | } 21 | 22 | constructor(mContext: Context, mIcon: Int, mTitle: CharSequence, mText: CharSequence, mBitmap: Bitmap?, mStatue: Boolean, mToken: MediaSession.Token? = null) { 23 | context = mContext 24 | iconID = mIcon 25 | titleString = mTitle 26 | textString = mText 27 | bitmap = mBitmap 28 | statue = mStatue 29 | token = mToken 30 | } 31 | 32 | lateinit var titleString: CharSequence 33 | lateinit var textString: CharSequence 34 | var iconID: Int = -1 35 | var statue: Boolean = true 36 | var token: MediaSession.Token? = null 37 | var bitmap: Bitmap? = null 38 | var context: Context? = null 39 | var contentIntent: PendingIntent? = null 40 | var deleteIntent: PendingIntent? = null 41 | 42 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Base/BasicViewNotification.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Base; 2 | 3 | import android.app.Notification; 4 | import android.graphics.drawable.BitmapDrawable; 5 | import android.os.Build; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.widget.ImageView; 9 | import android.widget.RemoteViews; 10 | import android.widget.TextView; 11 | 12 | import de.robv.android.xposed.XposedBridge; 13 | import de.robv.android.xposed.XposedHelpers; 14 | 15 | public abstract class BasicViewNotification extends BasicNotification { 16 | 17 | public Notification oldNotification; 18 | public int titleID; 19 | public int textID; 20 | public int bitmapID; 21 | public String className = ""; 22 | public String methodName = ""; 23 | 24 | protected BasicViewNotification() { 25 | } 26 | 27 | public final Notification viewBuild() { 28 | if (oldNotification == null) { 29 | Log.e("QQMusicNotify", "oldNotification should not be null!"); 30 | return null; 31 | } 32 | RemoteViews remoteViews = (RemoteViews) XposedHelpers.getObjectField(oldNotification,"bigContentView"); 33 | View view = remoteViews.apply(basicParam.getContext(), null); 34 | /*if (view==null) { 35 | Log.e("XposedMusicNotify", "RemoteView shoud not be bull"); 36 | return null; 37 | }*/ 38 | TextView titleTextView = view.findViewById(titleID); 39 | TextView textTextView = view.findViewById(textID); 40 | ImageView imageView = view.findViewById(bitmapID); 41 | basicParam.setTitleString(titleTextView.getText()); 42 | basicParam.setTextString(textTextView.getText()); 43 | basicParam.setBitmap(((BitmapDrawable) imageView.getDrawable()).getBitmap()); 44 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 45 | channelID = oldNotification.getChannelId(); 46 | } 47 | return this.build(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Base/HookInterface.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Base; 2 | 3 | import android.content.Context; 4 | 5 | public interface HookInterface { 6 | 7 | void init(); 8 | 9 | void initBefore(); 10 | 11 | HookInterface setClassLoader(ClassLoader classLoader); 12 | 13 | HookInterface setContext(Context context); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/ContentProvider.kt: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify 2 | 3 | import android.content.ContentProvider 4 | import android.content.ContentValues 5 | import android.content.Context 6 | import android.content.SharedPreferences 7 | import android.database.Cursor 8 | import android.media.session.MediaSession 9 | import android.net.Uri 10 | import android.os.Build 11 | import android.os.Bundle 12 | import android.os.Process 13 | import android.util.Log 14 | import androidx.annotation.Keep 15 | import androidx.annotation.StringDef 16 | import cn.nexus6p.QQMusicNotify.Utils.GeneralUtils 17 | import cn.nexus6p.QQMusicNotify.Utils.LogUtils 18 | import cn.nexus6p.QQMusicNotify.Utils.MediaSessionTokenHashMap.mediaSessionTokenMap 19 | import org.json.JSONObject 20 | 21 | @Keep 22 | class ContentProvider : ContentProvider() { 23 | 24 | companion object { 25 | const val CONTENT_PROVIDER_JSON: String = "content_provider_json" 26 | const val CONTENT_PROVIDER_PREFERENCE: String = "content_provider_preference" 27 | const val CONTENT_PROVIDER_DEVICE_PROTECTED_PREFERENCE: String = "content_provider_device_protected_preference" 28 | const val CONTENT_PROVIDER_COMMIT: String = "content_provider_commit" 29 | const val PUSH_MEDIA_SESSION_TOKEN: String = "push_mediasession_token" 30 | const val PULL_MEDIA_SESSION_TOKEN: String = "pull_mediasession_token" 31 | const val GET_ALL_SESSION_TOKEN: String = "get_all_session_token" 32 | 33 | const val BUNDLE_KEY_JSON_STRING: String = "bundle_key_json_string" 34 | const val BUNDLE_KEY_MEDIA_SESSION_TOKEN: String = "bundle_key_mediasession_token" 35 | 36 | /*@JvmStatic 37 | val mediaSessionTokenMap: HashMap = HashMap()*/ 38 | } 39 | 40 | override fun call(@ContentProviderParams method: String, arg: String?, extras: Bundle?): Bundle? { 41 | //Log.d("XposedMusicNotify", "ContentProvider is called") 42 | val bundle = Bundle() 43 | if (method == CONTENT_PROVIDER_COMMIT) { 44 | LogUtils.addLog(arg!!, context!!) 45 | return Bundle().apply { 46 | putBoolean("success", true) 47 | } 48 | } 49 | if (method == PUSH_MEDIA_SESSION_TOKEN) { 50 | if (extras==null) return Bundle().apply { 51 | putBoolean("success", false) 52 | } 53 | val token = extras.get(BUNDLE_KEY_MEDIA_SESSION_TOKEN) as MediaSession.Token 54 | Log.d("XposedMusicNotify","get $arg's token:$token") 55 | Log.d("XposedMusicNotify","process: "+Process.myPid()) 56 | mediaSessionTokenMap[arg!!] = token 57 | Log.d("XposedMusicNotify", mediaSessionTokenMap.toString()) 58 | return Bundle().apply { 59 | putBoolean("success", true) 60 | } 61 | } 62 | if (method == PULL_MEDIA_SESSION_TOKEN) { 63 | val token = mediaSessionTokenMap[arg] 64 | return Bundle().apply { 65 | putParcelable(BUNDLE_KEY_MEDIA_SESSION_TOKEN,token) 66 | } 67 | } 68 | if (method == GET_ALL_SESSION_TOKEN) { 69 | return Bundle().apply { 70 | Log.d("XposedMusicNotify", "send hashMap $mediaSessionTokenMap") 71 | Log.d("XposedMusicNotify","process: "+Process.myPid()) 72 | putSerializable(BUNDLE_KEY_MEDIA_SESSION_TOKEN, mediaSessionTokenMap) 73 | } 74 | } 75 | if (method == CONTENT_PROVIDER_JSON) { 76 | //Log.d("XposedMusicNotify","getJsonFile: "+GeneralUtils.getAssetsString("$arg.json",context)) 77 | bundle.putString(BUNDLE_KEY_JSON_STRING, GeneralUtils.getAssetsString("$arg.json", context)) 78 | } else { 79 | val mSharedPreferences: SharedPreferences = when (method) { 80 | CONTENT_PROVIDER_PREFERENCE -> GeneralUtils.getSharedPreferenceOnUI(context) 81 | CONTENT_PROVIDER_DEVICE_PROTECTED_PREFERENCE -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 82 | context!!.createDeviceProtectedStorageContext().getSharedPreferences("deviceProtected", Context.MODE_PRIVATE) 83 | } else { 84 | context!!.getSharedPreferences("deviceProtected", Context.MODE_PRIVATE) 85 | } 86 | else -> throw IllegalArgumentException() 87 | } 88 | 89 | bundle.putString(BUNDLE_KEY_JSON_STRING, JSONObject(mSharedPreferences.all).toString()) 90 | 91 | } 92 | return bundle 93 | } 94 | 95 | override fun onCreate(): Boolean { 96 | return true 97 | } 98 | 99 | @Retention(AnnotationRetention.SOURCE) 100 | @StringDef(CONTENT_PROVIDER_DEVICE_PROTECTED_PREFERENCE, CONTENT_PROVIDER_JSON, CONTENT_PROVIDER_PREFERENCE, CONTENT_PROVIDER_COMMIT, PULL_MEDIA_SESSION_TOKEN, PUSH_MEDIA_SESSION_TOKEN) 101 | @Target(AnnotationTarget.VALUE_PARAMETER) 102 | annotation class ContentProviderParams 103 | 104 | override fun query(uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, sortOrder: String?): Cursor? { 105 | throw NoSuchMethodException() 106 | } 107 | 108 | override fun getType(uri: Uri): String? { 109 | throw NoSuchMethodException() 110 | } 111 | 112 | override fun insert(uri: Uri, values: ContentValues?): Uri? { 113 | throw NoSuchMethodException() 114 | } 115 | 116 | override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?): Int { 117 | throw NoSuchMethodException() 118 | } 119 | 120 | override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int { 121 | throw NoSuchMethodException() 122 | } 123 | 124 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Fragment/AppsFragment.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Fragment; 2 | 3 | 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.os.Build; 7 | import android.os.Bundle; 8 | 9 | import androidx.annotation.Keep; 10 | import androidx.preference.Preference; 11 | import androidx.preference.PreferenceCategory; 12 | import androidx.preference.PreferenceFragmentCompat; 13 | 14 | import org.json.JSONArray; 15 | 16 | import cn.nexus6p.QQMusicNotify.BuildConfig; 17 | import cn.nexus6p.QQMusicNotify.R; 18 | import cn.nexus6p.QQMusicNotify.Utils.GeneralUtils; 19 | 20 | @Keep 21 | public class AppsFragment extends PreferenceFragmentCompat { 22 | 23 | @Override 24 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 25 | addPreferencesFromResource(R.xml.apps); 26 | //boolean PMEnabled = getSharedPreferenceOnUI(getActivity()).getBoolean("pm", true); 27 | try { 28 | JSONArray jsonArray = GeneralUtils.getSupportPackages(this.getContext()); 29 | for (int i = 0; i < jsonArray.length(); i++) { 30 | String packageName = jsonArray.getJSONObject(i).getString("app"); 31 | if (!(BuildConfig.DEBUG) && packageName.contains("com.kugou.android") && Build.VERSION.SDK_INT > 28) 32 | continue; 33 | Preference preference = new Preference(getActivity(), null); 34 | //if (PMEnabled) { 35 | PackageInfo packageInfo; 36 | try { 37 | packageInfo = getActivity().getPackageManager().getPackageInfo(packageName, 0); 38 | } catch (PackageManager.NameNotFoundException e) { 39 | packageInfo = null; 40 | } 41 | if (packageInfo == null) continue; 42 | else 43 | preference.setIcon(getActivity().getPackageManager().getApplicationIcon(packageName)); 44 | //} 45 | preference.setTitle(jsonArray.getJSONObject(i).getString("name")); 46 | preference.setSummary(packageName); 47 | preference.setOnPreferenceClickListener(preference1 -> { 48 | getActivity().getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.slide_right_in, R.anim.slide_left_out, R.anim.slide_left_in, R.anim.slide_right_out).replace(R.id.content_frame, DetailFragment.Companion.newInstance(packageName)).addToBackStack(DetailFragment.class.getSimpleName()).commit(); 49 | return true; 50 | }); 51 | ((PreferenceCategory) findPreference("app")).addPreference(preference); 52 | } 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | } 56 | 57 | findPreference("thirdPartySource").setOnPreferenceClickListener(preference -> { 58 | getActivity().getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.slide_right_in, R.anim.slide_left_out, R.anim.slide_left_in, R.anim.slide_right_out).replace(R.id.content_frame, new ThirdPartySourceFragment()).addToBackStack(ThirdPartySourceFragment.class.getSimpleName()).commit(); 59 | return true; 60 | }); 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Fragment/ExperimentalFragment.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Fragment; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.annotation.Keep; 6 | import androidx.preference.PreferenceFragmentCompat; 7 | 8 | import cn.nexus6p.QQMusicNotify.MainActivity; 9 | import cn.nexus6p.QQMusicNotify.R; 10 | 11 | @Keep 12 | public class ExperimentalFragment extends PreferenceFragmentCompat { 13 | @Override 14 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 15 | addPreferencesFromResource(R.xml.experimental); 16 | findPreference("fakeTaichi").setOnPreferenceChangeListener((preference, newValue) -> { 17 | ((MainActivity) getActivity()).reload(); 18 | return true; 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Fragment/JsonDetailFragment.kt: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Fragment 2 | 3 | import android.os.Bundle 4 | import androidx.annotation.Keep 5 | import androidx.preference.Preference 6 | import androidx.preference.PreferenceCategory 7 | import androidx.preference.PreferenceFragmentCompat 8 | import cn.nexus6p.QQMusicNotify.R 9 | import org.json.JSONObject 10 | 11 | @Keep 12 | class JsonDetailFragment private constructor() : PreferenceFragmentCompat() { 13 | 14 | companion object { 15 | fun newInstance(jsonString: String): JsonDetailFragment { 16 | val bundle = Bundle() 17 | bundle.putString("jsonString", jsonString) 18 | val jsonDetailFragment = JsonDetailFragment() 19 | jsonDetailFragment.arguments = bundle 20 | return jsonDetailFragment 21 | } 22 | } 23 | 24 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 25 | addPreferencesFromResource(R.xml.json_detail) 26 | if (arguments == null) throw IllegalAccessException("Arguments should not be null,please use newInstance to get a DetailFragment object and set the param as the packageName") 27 | try { 28 | val jsonString = requireArguments().getString("jsonString") 29 | val jsonObject = JSONObject(jsonString!!) 30 | val detailPreferenceCategory: PreferenceCategory = findPreference("JSONDetail")!! 31 | for (key in jsonObject.keys()) { 32 | val preference = Preference(requireContext()) 33 | preference.title = key 34 | preference.summary = jsonObject.optString(key) 35 | detailPreferenceCategory.addItemFromInflater(preference) 36 | } 37 | } catch (e: Exception) { 38 | e.printStackTrace() 39 | } 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Fragment/MediaNotificationFragment.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Fragment; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.graphics.drawable.GradientDrawable; 6 | import android.os.Bundle; 7 | import android.util.Log; 8 | import android.widget.Toast; 9 | 10 | import androidx.annotation.Keep; 11 | import androidx.preference.EditTextPreference; 12 | import androidx.preference.ListPreference; 13 | import androidx.preference.PreferenceFragmentCompat; 14 | 15 | import cn.nexus6p.QQMusicNotify.R; 16 | 17 | @Keep 18 | public class MediaNotificationFragment extends PreferenceFragmentCompat { 19 | @Override 20 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 21 | getPreferenceManager().setSharedPreferencesMode(Context.MODE_PRIVATE); 22 | addPreferencesFromResource(cn.nexus6p.QQMusicNotify.R.xml.media_notification); 23 | String[] strings = getContext().getResources().getStringArray(R.array.pickColorMode); 24 | ListPreference preference = findPreference("colorMethod"); 25 | preference.setSummary(preference.getEntry()); 26 | preference.setOnPreferenceChangeListener((preference1, newValue) -> { 27 | preference.setSummary(strings[Integer.parseInt(newValue.toString())]); 28 | //preferenceChangeListener(preference1,newValue); 29 | return true; 30 | }); 31 | 32 | /*findPreference("inverseTextColors").setOnPreferenceChangeListener((preference1, newValue) -> { 33 | preferenceChangeListener(preference1,newValue); 34 | return true; 35 | }); 36 | 37 | findPreference("highContrastText").setOnPreferenceChangeListener((preference1, newValue) -> { 38 | preferenceChangeListener(preference1,newValue); 39 | return true; 40 | });*/ 41 | 42 | EditTextPreference colorPreference = findPreference("customColor"); 43 | colorPreference.setSummary(colorPreference.getText()); 44 | colorPreference.setOnPreferenceChangeListener((preference1, newValue) -> { 45 | if (!newValue.toString().matches("\\#[0-9a-fA-F]{6}")) { 46 | Log.d("newValue", newValue.toString()); 47 | Toast.makeText(getActivity(), "请输入16进制RGB颜色", Toast.LENGTH_LONG).show(); 48 | return false; 49 | } 50 | colorPreference.setSummary((CharSequence) newValue); 51 | GradientDrawable drawable = (GradientDrawable) getContext().getDrawable(R.drawable.color_drawable); 52 | drawable.setColor(Color.parseColor((String) newValue)); 53 | colorPreference.setIcon(drawable); 54 | //preferenceChangeListener(preference1,newValue); 55 | return true; 56 | }); 57 | GradientDrawable drawable = (GradientDrawable) getContext().getDrawable(R.drawable.color_drawable); 58 | drawable.setColor(Color.parseColor(colorPreference.getText())); 59 | findPreference("customColor").setIcon(drawable); 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Fragment/MusicNotificationFragment.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Fragment; 2 | 3 | import android.os.Bundle; 4 | import android.widget.Button; 5 | 6 | import androidx.annotation.Keep; 7 | import androidx.appcompat.app.AlertDialog; 8 | import androidx.preference.PreferenceFragmentCompat; 9 | 10 | import com.google.android.material.dialog.MaterialAlertDialogBuilder; 11 | 12 | import cn.nexus6p.QQMusicNotify.MainActivity; 13 | import cn.nexus6p.QQMusicNotify.R; 14 | import cn.nexus6p.QQMusicNotify.Utils.HookStatue; 15 | 16 | import static cn.nexus6p.QQMusicNotify.Utils.GeneralUtils.deviceContextPreferenceChangeListener; 17 | 18 | @Keep 19 | public class MusicNotificationFragment extends PreferenceFragmentCompat { 20 | @Override 21 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 22 | addPreferencesFromResource(R.xml.music_notification); 23 | //GeneralUtils.bindPreference(this,"styleModify","always_show"); 24 | if (HookStatue.isExpModuleActive(getActivity()) > 0) { 25 | findPreference("miuiModify").setSummary("仅太极·阳有效,请将SystemUI加入太极"); 26 | } 27 | 28 | findPreference("styleModify").setOnPreferenceChangeListener((preference, newValue) -> { 29 | ((MainActivity) getActivity()).reload(); 30 | return true; 31 | }); 32 | /*findPreference("always_show").setOnPreferenceChangeListener((preference, newValue) -> { 33 | preferenceChangeListener(preference,newValue); 34 | return true; 35 | });*/ 36 | findPreference("miuiModify").setOnPreferenceChangeListener((preference, newValue) -> { 37 | deviceContextPreferenceChangeListener(preference, newValue, getActivity()); 38 | return true; 39 | }); 40 | findPreference("miuiForceExpand").setOnPreferenceChangeListener((preference, newValue) -> { 41 | deviceContextPreferenceChangeListener(preference, newValue, getActivity()); 42 | return true; 43 | }); 44 | 45 | } 46 | 47 | @Override 48 | public void onStart() { 49 | super.onStart(); 50 | AlertDialog dialog = new MaterialAlertDialogBuilder(getActivity()) 51 | .setTitle("关于去白边及强制展开") 52 | .setMessage("此功能是否生效取决于您的手机系统及框架,且不属于本模块的常规功能范畴,本人不为其效果提供任何保证及咨询服务,本功能在您的手机上失效亦不会属于未来任何一个版本的修复内容。关于部分ROM上的通知如何去除白边或强制展开,请自行去相关论坛或手机系统交流群咨询。\n\n下面列出一个可能会有用但没用也不关我事的网址:\nhttps://github.com/singleNeuron/XposedRemoveNotificationWhiteFrame/releases") 53 | .setCancelable(false) 54 | .setPositiveButton("我已阅读并知悉 (5)", null) 55 | .create(); 56 | dialog.show(); 57 | Button button = dialog.getButton(AlertDialog.BUTTON_POSITIVE); 58 | button.setEnabled(false); 59 | new Thread(() -> { 60 | for (int i = 5; i > 0; i--) { 61 | int finalI = i; 62 | getActivity().runOnUiThread(() -> { 63 | button.setText("我已阅读并知悉 (" + finalI + ")"); 64 | }); 65 | try { 66 | Thread.sleep(1000); 67 | } catch (InterruptedException e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | getActivity().runOnUiThread(() -> { 72 | button.setText("我已阅读并知悉"); 73 | }); 74 | getActivity().runOnUiThread(() -> { 75 | button.setEnabled(true); 76 | }); 77 | }).start(); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Fragment/PlayingFragment.kt: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Fragment 2 | 3 | import android.graphics.drawable.BitmapDrawable 4 | import android.media.MediaMetadata 5 | import android.media.session.MediaController 6 | import android.media.session.MediaSession 7 | import android.os.Bundle 8 | import android.util.Log 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import android.widget.LinearLayout 13 | import android.widget.Toast 14 | import androidx.fragment.app.Fragment 15 | import cn.nexus6p.QQMusicNotify.ContentProvider 16 | import cn.nexus6p.QQMusicNotify.SharedPreferences.ContentProviderPreference 17 | import cn.nexus6p.QQMusicNotify.SimpleAlcatrazInteractiveCardView 18 | import soptqs.medianotification.utils.PaletteUtils 19 | 20 | private lateinit var linearLayout: LinearLayout 21 | 22 | class PlayingFragment : Fragment() { 23 | 24 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 25 | linearLayout = LinearLayout(context) 26 | linearLayout.orientation = LinearLayout.VERTICAL 27 | return linearLayout 28 | } 29 | 30 | override fun onResume() { 31 | super.onResume() 32 | linearLayout.removeAllViews() 33 | val packageManager = requireContext().packageManager 34 | val hashMap: HashMap? = ContentProviderPreference.getBundle(ContentProvider.GET_ALL_SESSION_TOKEN,null,requireContext())?.getSerializable(ContentProvider.BUNDLE_KEY_MEDIA_SESSION_TOKEN) as HashMap? 35 | if (hashMap==null) { 36 | Toast.makeText(requireContext(), "获取失败", Toast.LENGTH_SHORT).show() 37 | return 38 | } 39 | Log.d("XposedMusicNotify","get hashMap $hashMap") 40 | for (entry in hashMap) { 41 | val cardView = SimpleAlcatrazInteractiveCardView(requireContext()) 42 | cardView.titleLine = try { 43 | packageManager.getApplicationLabel(packageManager.getApplicationInfo(entry.key,0)).toString() 44 | } catch (e:Exception) { 45 | entry.key 46 | } 47 | try{ 48 | val metaData = MediaController(requireContext(),entry.value).metadata ?: continue 49 | Log.d("XposedMusicNotify",metaData.keySet().toTypedArray().joinToString()) 50 | var title = metaData.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE) 51 | if (title.isNullOrBlank()) title = metaData.getString(MediaMetadata.METADATA_KEY_TITLE) 52 | cardView.firstLine = title 53 | cardView.secondLine = metaData.getString(MediaMetadata.METADATA_KEY_ARTIST) 54 | var bitmap = metaData.getBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON) 55 | if (bitmap==null) bitmap = metaData.getBitmap(MediaMetadata.METADATA_KEY_ART) 56 | if (bitmap==null) bitmap = metaData.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART) 57 | var icon = packageManager.getApplicationIcon(entry.key) 58 | if (bitmap!=null) { 59 | icon = BitmapDrawable(resources,bitmap) 60 | } else if (icon is BitmapDrawable) { 61 | bitmap = icon.bitmap 62 | } 63 | cardView.iconDrawable = icon 64 | if (bitmap!=null) { 65 | cardView.color = PaletteUtils.getSwatch(PaletteUtils.getPalette(bitmap),requireContext()).rgb 66 | } 67 | linearLayout.addView(cardView) 68 | }catch (e:Exception) { 69 | e.printStackTrace() 70 | } 71 | } 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Fragment/SettingFragment.kt: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Fragment 2 | 3 | import android.content.ActivityNotFoundException 4 | import android.content.Intent 5 | import android.net.Uri 6 | import android.os.Bundle 7 | import android.view.LayoutInflater 8 | import android.view.View 9 | import android.view.ViewGroup 10 | import android.widget.ImageView 11 | import android.widget.LinearLayout 12 | import android.widget.TextView 13 | import androidx.cardview.widget.CardView 14 | import androidx.core.content.ContextCompat 15 | import androidx.fragment.app.Fragment 16 | import cn.nexus6p.QQMusicNotify.R 17 | import cn.nexus6p.QQMusicNotify.Utils.GeneralUtils 18 | import cn.nexus6p.QQMusicNotify.Utils.HookStatue 19 | import cn.nexus6p.QQMusicNotify.Utils.LogUtils 20 | 21 | class SettingFragment : Fragment() { 22 | 23 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 24 | super.onCreateView(inflater, container, savedInstanceState) 25 | val view = inflater.inflate(R.layout.setting_fragment, container, false) 26 | childFragmentManager.beginTransaction().setCustomAnimations(R.anim.slide_right_in, R.anim.slide_left_out, R.anim.slide_left_in, R.anim.slide_right_out).replace(R.id.content_frame3, SettingsFragment()).addToBackStack(SettingsFragment::class.java.simpleName).commit() 27 | 28 | val shardPreferences = GeneralUtils.getSharedPreferenceOnUI(context) 29 | 30 | val cardView = view.findViewById(R.id.cardview) 31 | val cardViewLinearLayout = view.findViewById(R.id.setting_linearLayout) 32 | val cardViewTitle = view.findViewById(R.id.cardView_Title) 33 | val cardViewImage = view.findViewById(R.id.cardView_image) 34 | val statue = HookStatue.getStatue(activity) 35 | cardViewTitle.text = HookStatue.getStatueName(statue) 36 | if (HookStatue.isActive(statue)) { 37 | cardViewImage.setImageResource(R.drawable.ic_check_circle) 38 | if (shardPreferences.getBoolean("colorCardView", true)) cardViewLinearLayout.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.green)) 39 | } else { 40 | cardViewImage.setImageResource(R.drawable.ic_cancel) 41 | if (shardPreferences.getBoolean("colorCardView", true)) cardViewLinearLayout.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.colorError)) 42 | } 43 | 44 | if (statue.name.contains("taichi", true)) { 45 | if (HookStatue.isActive(statue)) { 46 | cardView.setOnClickListener { 47 | requireActivity().supportFragmentManager.beginTransaction().setCustomAnimations(R.anim.slide_right_in, R.anim.slide_left_out, R.anim.slide_left_in, R.anim.slide_right_out).replace(R.id.content_frame, LogFragment(), "logFragment").addToBackStack(LogFragment::class.java.simpleName).commit() 48 | } 49 | cardViewImage.apply { 50 | setOnClickListener { 51 | //activity!!.toast("跳转到太极") 52 | val t = Intent("me.weishu.exp.ACTION_MODULE_MANAGE"); 53 | t.data = Uri.parse("package:" + "cn.nexus6p.QQMusicNotify"); 54 | t.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 55 | try { 56 | startActivity(t); 57 | } catch (e: ActivityNotFoundException) { 58 | //ignore 59 | } 60 | } 61 | isClickable = true 62 | } 63 | } else { 64 | cardView.apply { 65 | setOnClickListener { 66 | //activity!!.toast("跳转到太极") 67 | val t = Intent("me.weishu.exp.ACTION_MODULE_MANAGE"); 68 | t.data = Uri.parse("package:" + "cn.nexus6p.QQMusicNotify"); 69 | t.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 70 | try { 71 | startActivity(t); 72 | } catch (e: ActivityNotFoundException) { 73 | //ignore 74 | } 75 | } 76 | isClickable = true 77 | } 78 | } 79 | } else { 80 | cardView.setOnClickListener { 81 | requireActivity().supportFragmentManager.beginTransaction().setCustomAnimations(R.anim.slide_right_in, R.anim.slide_left_out, R.anim.slide_left_in, R.anim.slide_right_out).replace(R.id.content_frame, LogFragment(), "logFragment").addToBackStack(LogFragment::class.java.simpleName).commit() 82 | } 83 | } 84 | 85 | return view 86 | } 87 | 88 | override fun onResume() { 89 | super.onResume() 90 | LogUtils.cleanLog(GeneralUtils.getSharedPreferenceOnUI(context).getInt("logMaxLine", 1000), requireContext()) 91 | val cardViewSummary = requireView().findViewById(R.id.cardView_summary) 92 | cardViewSummary.text = "已应用" + LogUtils.getLineCount(requireContext()) + "次" 93 | } 94 | 95 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Fragment/ThirdPartySourceFragment.kt: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Fragment 2 | 3 | import android.content.DialogInterface 4 | import android.graphics.Color 5 | import android.os.Bundle 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import android.widget.EditText 10 | import android.widget.ProgressBar 11 | import android.widget.Toast 12 | import androidx.annotation.Keep 13 | import androidx.core.content.ContextCompat 14 | import androidx.fragment.app.Fragment 15 | import cn.nexus6p.QQMusicNotify.R 16 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 17 | import com.google.android.material.floatingactionbutton.FloatingActionButton 18 | import org.json.JSONObject 19 | import java.io.File 20 | import java.net.URL 21 | 22 | @Keep 23 | class ThirdPartySourceFragment : Fragment() { 24 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 25 | super.onCreateView(inflater, container, savedInstanceState) 26 | val view = inflater.inflate(R.layout.third_party_source, container, false) 27 | childFragmentManager.beginTransaction().replace(R.id.content_frame2, ThirdPartySourceListFragment()).addToBackStack(ThirdPartySourceListFragment::class.java.simpleName).commit() 28 | val floatingActionButton = view.findViewById(R.id.floating_action_button) 29 | floatingActionButton.setColorFilter(Color.WHITE) 30 | floatingActionButton.rippleColor = ContextCompat.getColor(requireContext(), R.color.colorPrimaryVariant) 31 | floatingActionButton.setOnClickListener { 32 | val editText = EditText(activity) 33 | MaterialAlertDialogBuilder(requireContext()) 34 | .setTitle("请输入源地址") 35 | .setView(editText) 36 | .setNegativeButton("取消", null) 37 | .setPositiveButton("确定", DialogInterface.OnClickListener { _, _ -> 38 | val builder = MaterialAlertDialogBuilder(requireContext()) 39 | builder.setTitle("下载中...description.json") 40 | builder.setCancelable(false) 41 | val progressBar = ProgressBar(context) 42 | builder.setView(progressBar) 43 | val alertDialog = builder.create() 44 | alertDialog.show() 45 | Thread(Runnable { 46 | try { 47 | val jsonString: String = URL(editText.text.toString() + (if (editText.text.toString().endsWith("/")) "" else "/") + "description.json").readText() 48 | val jsonObject = JSONObject(jsonString) 49 | val id = jsonObject.optString("id") 50 | val files = File(requireContext().getExternalFilesDir("ThirdPartySource").toString() + File.separator + id) 51 | if (!files.exists()) files.mkdir() 52 | File(files.toString() + File.separator + "description.json").writeText(jsonString) 53 | File(files.toString() + File.separator + "packages.json").writeBytes(URL(editText.text.toString() + (if (editText.text.toString().endsWith("/")) "" else "/") + "packages.json").readBytes()) 54 | requireActivity().runOnUiThread { 55 | childFragmentManager.beginTransaction().replace(R.id.content_frame2, ThirdPartySourceListFragment()).commit() 56 | } 57 | } catch (e: Exception) { 58 | requireActivity().runOnUiThread { Toast.makeText(requireActivity(), e.toString(), Toast.LENGTH_SHORT).show() } 59 | e.printStackTrace() 60 | } finally { 61 | requireActivity().runOnUiThread(alertDialog::dismiss) 62 | } 63 | }).start() 64 | }).show() 65 | } 66 | return view 67 | } 68 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Hook/cnkuwoplayer.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Hook; 2 | 3 | import android.app.Notification; 4 | import android.app.NotificationChannel; 5 | import android.app.NotificationManager; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.SharedPreferences; 9 | import android.graphics.Bitmap; 10 | import android.media.session.MediaSession; 11 | 12 | import androidx.annotation.Keep; 13 | 14 | import cn.nexus6p.QQMusicNotify.Base.BasicNotification; 15 | import cn.nexus6p.QQMusicNotify.Utils.GeneralUtils; 16 | import cn.nexus6p.QQMusicNotify.Utils.PreferenceUtil; 17 | import de.robv.android.xposed.XC_MethodReplacement; 18 | import de.robv.android.xposed.XposedHelpers; 19 | 20 | import static android.content.Context.NOTIFICATION_SERVICE; 21 | import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; 22 | import static de.robv.android.xposed.XposedHelpers.getObjectField; 23 | 24 | @Keep 25 | public class cnkuwoplayer extends BasicNotification { 26 | 27 | private static MediaSession.Token mTOKEN; 28 | 29 | @Override 30 | public void init() { 31 | SharedPreferences preference = PreferenceUtil.getJSONPreference("cn.kuwo.player", basicParam.getContext()); 32 | String className = preference.getString("class", ""); 33 | String methodName = preference.getString("method", ""); 34 | //int iconID = preference.getInt("iconID", -1); 35 | String contextField = preference.getString("contextField", ""); 36 | String preSongIntentName = preference.getString("preSongIntent", ""); 37 | String playSongIntentName = preference.getString("playSongIntent", ""); 38 | String nextSongIntentName = preference.getString("nextSongIntent", ""); 39 | String IntentHandleActivity = preference.getString("IntentHandleActivity", ""); 40 | String getStatusClass = preference.getString("getStatusClass", ""); 41 | String getStatusMethod = preference.getString("getStatusMethod", ""); 42 | String getStatusMethod2 = preference.getString("getStatusMethod2", ""); 43 | String playProxyStatusClass = preference.getString("playProxyStatusClass", ""); 44 | String playProxyStatusField = preference.getString("playProxyStatusField", ""); 45 | //extraActionIcon = preference.getInt("extraActionIcon", -1); 46 | String extraActionIntentName = preference.getString("extraActionIntent", ""); 47 | 48 | Class drawableClass = XposedHelpers.findClass(preference.getString("drawableClass",""),classLoader); 49 | int iconID = XposedHelpers.getStaticIntField(drawableClass,preference.getString("iconField","")); 50 | extraActionIcon = XposedHelpers.getStaticIntField(drawableClass,preference.getString("extraActionIconField","")); 51 | 52 | final Class notifyClazz = XposedHelpers.findClass(className, classLoader); 53 | findAndHookMethod(notifyClazz, methodName, Bitmap.class, String.class, String.class, String.class, new XC_MethodReplacement() { 54 | @Override 55 | protected Notification replaceHookedMethod(MethodHookParam param) throws Throwable { 56 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { 57 | channelID = "music1"; 58 | NotificationChannel channel = new NotificationChannel(channelID, "音乐通知", NotificationManager.IMPORTANCE_LOW); 59 | channel.setSound(null, null); 60 | channel.enableVibration(false); 61 | ((NotificationManager) GeneralUtils.getContext().getSystemService(NOTIFICATION_SERVICE)).deleteNotificationChannel("music"); 62 | ((NotificationManager) GeneralUtils.getContext().getSystemService(NOTIFICATION_SERVICE)).createNotificationChannel(channel); 63 | } 64 | basicParam.setIconID(iconID); 65 | basicParam.setContext((Context) getObjectField(param.thisObject, contextField)); 66 | basicParam.setBitmap((Bitmap) param.args[0]); 67 | if (mTOKEN == null) 68 | mTOKEN = new MediaSession(basicParam.getContext(), "MediaSessionHelper").getSessionToken(); 69 | basicParam.setToken(mTOKEN); 70 | basicParam.setTitleString((CharSequence) param.args[1]); 71 | basicParam.setTextString((CharSequence) param.args[2]); 72 | preSongIntent = new Intent(preSongIntentName); 73 | playIntent = new Intent(playSongIntentName); 74 | nextSongIntent = new Intent(nextSongIntentName); 75 | contentIntent = new Intent(basicParam.getContext(), XposedHelpers.findClass(IntentHandleActivity, classLoader)); 76 | contentIntent.setAction("android.intent.action.MAIN") 77 | .addCategory("android.intent.category.LAUNCHER"); 78 | intentRequestID = 1; 79 | hasExtraAction = true; 80 | extraActionIntent = new Intent(extraActionIntentName); 81 | Object object = XposedHelpers.callStaticMethod(XposedHelpers.findClass(getStatusClass, classLoader), getStatusMethod); 82 | Object object2 = XposedHelpers.callMethod(object, getStatusMethod2); 83 | Object object3 = XposedHelpers.getStaticObjectField(XposedHelpers.findClass(playProxyStatusClass, classLoader), playProxyStatusField); 84 | basicParam.setStatue(object2.equals(object3)); 85 | return build(); 86 | } 87 | }); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Hook/comkugouandroid.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Hook; 2 | 3 | import android.content.SharedPreferences; 4 | import android.os.Build; 5 | import android.widget.Toast; 6 | 7 | import androidx.annotation.Keep; 8 | 9 | import cn.nexus6p.QQMusicNotify.Base.BasicInit; 10 | import cn.nexus6p.QQMusicNotify.BuildConfig; 11 | import cn.nexus6p.QQMusicNotify.Utils.PreferenceUtil; 12 | import de.robv.android.xposed.XC_MethodHook; 13 | import de.robv.android.xposed.XC_MethodReplacement; 14 | import de.robv.android.xposed.XposedBridge; 15 | import de.robv.android.xposed.XposedHelpers; 16 | 17 | @Keep 18 | public class comkugouandroid extends BasicInit { 19 | 20 | @Override 21 | public void init() { 22 | if ((!BuildConfig.DEBUG) && Build.VERSION.SDK_INT > 28) return; 23 | try { 24 | Class preferenceClass = XposedHelpers.findClass("com.kugou.framework.setting.preference.Preference", classLoader); 25 | XposedHelpers.findAndHookMethod("com.kugou.framework.setting.preference.PreferenceGroup", classLoader, "removePreference", preferenceClass, new XC_MethodHook() { 26 | @Override 27 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 28 | Object preference = param.args[0]; 29 | String key = (String) XposedHelpers.callMethod(preference, "getKey"); 30 | XposedBridge.log("XposedMusicNotify: get key " + key); 31 | if (key.contains("USE_KG_NOTIFICATION")) { 32 | Toast.makeText(basicParam.getContext(), "stop kugou removing " + key, Toast.LENGTH_SHORT).show(); 33 | param.setResult(true); 34 | } 35 | } 36 | }); 37 | } catch (Exception e) { 38 | e.printStackTrace(); 39 | } 40 | SharedPreferences preference = PreferenceUtil.getJSONPreference("com.kugou.android", basicParam.getContext()); 41 | String className = preference.getString("class", ""); 42 | try { 43 | String method1 = preference.getString("method1", ""); 44 | XposedHelpers.findAndHookMethod(className, classLoader, method1, new XC_MethodReplacement() { 45 | @Override 46 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 47 | return false; 48 | } 49 | }); 50 | } catch (Exception e) { 51 | e.printStackTrace(); 52 | } 53 | try { 54 | String method2 = preference.getString("method2", ""); 55 | XposedHelpers.findAndHookMethod(className, classLoader, method2, boolean.class, new XC_MethodReplacement() { 56 | @Override 57 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 58 | return false; 59 | } 60 | }); 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Hook/comneteasecloudmusic.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Hook; 2 | 3 | import android.content.SharedPreferences; 4 | 5 | import androidx.annotation.Keep; 6 | 7 | import cn.nexus6p.QQMusicNotify.Base.BasicInit; 8 | import de.robv.android.xposed.XC_MethodHook; 9 | import de.robv.android.xposed.XposedHelpers; 10 | 11 | @Keep 12 | public class comneteasecloudmusic extends BasicInit { 13 | 14 | @Override 15 | public void init() { 16 | XposedHelpers.findAndHookMethod(SharedPreferences.class, "getInt", String.class, int.class, new XC_MethodHook() { 17 | @Override 18 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 19 | if (param.args[0].equals("notificationBackground")) { 20 | param.setResult(2); 21 | } 22 | } 23 | }); 24 | XposedHelpers.findAndHookMethod(SharedPreferences.Editor.class, "putInt", String.class, int.class, new XC_MethodHook() { 25 | @Override 26 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 27 | if (param.args[0].equals("notificationBackground")) { 28 | param.args[1] = 2; 29 | } 30 | } 31 | }); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Hook/comsingclient.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Hook; 2 | 3 | import android.app.Notification; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.graphics.drawable.BitmapDrawable; 7 | import android.media.session.MediaSession; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.RemoteViews; 11 | import android.widget.TextView; 12 | 13 | import androidx.annotation.Keep; 14 | 15 | import cn.nexus6p.QQMusicNotify.Base.BasicViewNotification; 16 | import de.robv.android.xposed.XC_MethodHook; 17 | import de.robv.android.xposed.XposedHelpers; 18 | 19 | @Keep 20 | public class comsingclient extends BasicViewNotification { 21 | 22 | private static MediaSession.Token mTOKEN; 23 | 24 | @Override 25 | public void init() { 26 | 27 | Class songClazz = XposedHelpers.findClass("com.sing.client.model.Song", classLoader); 28 | XposedHelpers.findAndHookMethod("com.kugou.common.player.manager.b", classLoader, "h", songClazz, new XC_MethodHook() { 29 | @Override 30 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 31 | oldNotification = (Notification) XposedHelpers.getObjectField(param.thisObject, "b"); 32 | basicParam.setContext((Context) XposedHelpers.getObjectField(param.thisObject, "a")); 33 | basicParam.setIconID(0x7f0207f1); 34 | titleID = 0x7f100bf8; 35 | textID = 0x7f100bf9; 36 | bitmapID = 0x7f100bf7; 37 | RemoteViews remoteViews = (RemoteViews) XposedHelpers.getObjectField(oldNotification,"bigContentView"); 38 | View view = remoteViews.apply(basicParam.getContext(), null); 39 | try { 40 | basicParam.setBitmap(((BitmapDrawable) ((ImageView) view.findViewById(bitmapID)).getDrawable()).getBitmap()); 41 | basicParam.setTextString(((TextView) view.findViewById(titleID)).getText()); 42 | basicParam.setTextString(((TextView) view.findViewById(textID)).getText()); 43 | } catch (Exception e) { 44 | e.printStackTrace(); 45 | } 46 | if (mTOKEN == null) 47 | mTOKEN = new MediaSession(basicParam.getContext(), "MediaSessionHelper").getSessionToken(); 48 | basicParam.setToken(mTOKEN); 49 | playIntent = new Intent("com.sing.client.click_action_pause"); 50 | preSongIntent = new Intent("com.sing.client.click_action_pre"); 51 | nextSongIntent = new Intent("com.sing.client.click_action"); 52 | hasExtraAction = false; 53 | extraActionIcon = 0x7f020207; 54 | extraActionIntent = new Intent("com.sing.client.click_action_lyric"); 55 | contentIntent = new Intent().putExtra("isFrom", "isFromPlay").setClass(basicParam.getContext(), XposedHelpers.findClass("com.sing.client.play.ui.PlayerActivity", classLoader)); 56 | intentRequestID = 5; 57 | XposedHelpers.setObjectField(param.thisObject, "b", build()); 58 | } 59 | }); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Hook/comtencentkaraoke.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Hook; 2 | 3 | import android.app.Notification; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.SharedPreferences; 7 | import android.media.session.MediaSession; 8 | import android.net.Uri; 9 | import android.os.Parcelable; 10 | 11 | import androidx.annotation.Keep; 12 | 13 | import org.json.JSONArray; 14 | 15 | import cn.nexus6p.QQMusicNotify.Base.BasicViewNotification; 16 | import cn.nexus6p.QQMusicNotify.SharedPreferences.ContentProviderPreference; 17 | import cn.nexus6p.QQMusicNotify.Utils.PreferenceUtil; 18 | import de.robv.android.xposed.XC_MethodHook; 19 | import de.robv.android.xposed.XposedBridge; 20 | import de.robv.android.xposed.XposedHelpers; 21 | 22 | @Keep 23 | public class comtencentkaraoke extends BasicViewNotification { 24 | 25 | private static MediaSession.Token mTOKEN; 26 | 27 | @Override 28 | public void init() { 29 | SharedPreferences preference = PreferenceUtil.getJSONPreference("com.tencent.karaoke", basicParam.getContext()); 30 | className = preference.getString("class", ""); 31 | methodName = preference.getString("method", ""); 32 | //titleID = preference.getInt("titleID", -1); 33 | //textID = preference.getInt("textID", -1); 34 | //bitmapID = preference.getInt("bitmapID", -1); 35 | basicParam.setIconID(preference.getInt("iconID", -1)); 36 | String intentClass = preference.getString("intentClass", ""); 37 | String preSongField = preference.getString("preSongField", ""); 38 | String playSongField = preference.getString("playSongField", ""); 39 | String nextSongField = preference.getString("nextSongField", ""); 40 | String deleteField = preference.getString("deleteField", ""); 41 | String IntentHandleActivity = preference.getString("IntentHandleActivity", ""); 42 | 43 | Class idClass = XposedHelpers.findClass(preference.getString("idClass",""),classLoader); 44 | titleID = XposedHelpers.getStaticIntField(idClass,preference.getString("titleField","")); 45 | textID = XposedHelpers.getStaticIntField(idClass,preference.getString("textField","")); 46 | bitmapID = XposedHelpers.getStaticIntField(idClass,preference.getString("bitmapField","")); 47 | 48 | JSONArray params = ((ContentProviderPreference) preference).jsonObject.optJSONArray("params"); 49 | Object[] objects = new Object[params.length() + 1]; 50 | try { 51 | for (int i = 0; i < params.length(); i++) { 52 | objects[i] = (params.get(i).toString().equals("int")) ? int.class : XposedHelpers.findClass(params.get(i).toString(), classLoader); 53 | } 54 | } catch (Exception e) { 55 | e.printStackTrace(); 56 | } 57 | objects[params.length()] = new XC_MethodHook() { 58 | @Override 59 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 60 | basicParam.setContext((Context) param.args[0]); 61 | Parcelable playSongInfo = (Parcelable) param.args[1]; 62 | oldNotification = (Notification) param.getResult(); 63 | basicParam.setStatue(((int) param.args[2]) == 8); 64 | if (mTOKEN == null) 65 | mTOKEN = new MediaSession(basicParam.getContext(), "Karaoke media button").getSessionToken(); 66 | basicParam.setToken(mTOKEN); 67 | preSongIntent = new Intent((String) XposedHelpers.getStaticObjectField(XposedHelpers.findClass(intentClass, classLoader), preSongField)).putExtra("play_current_song", playSongInfo); 68 | playIntent = new Intent((String) XposedHelpers.getStaticObjectField(XposedHelpers.findClass(intentClass, classLoader), playSongField)).putExtra("play_current_song", playSongInfo); 69 | nextSongIntent = new Intent((String) XposedHelpers.getStaticObjectField(XposedHelpers.findClass(intentClass, classLoader), nextSongField)).putExtra("play_current_song", playSongInfo); 70 | contentIntent = new Intent("com.tencent.karaoke.action.PLAYER"); 71 | contentIntent.setData(Uri.parse("qmkege://")) 72 | .putExtra("action", "notification_player") 73 | .putExtra("from", "from_notification") 74 | .setClassName(basicParam.getContext(), XposedHelpers.findClass(IntentHandleActivity, classLoader).getCanonicalName()) 75 | .addCategory("android.intent.category.DEFAULT"); 76 | XposedBridge.log("加载方法完毕"); 77 | param.setResult(viewBuild()); 78 | } 79 | }; 80 | 81 | XposedHelpers.findAndHookMethod(className, classLoader, methodName, objects); 82 | 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Hook/comtencentqqmusic.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Hook; 2 | 3 | import androidx.annotation.Keep; 4 | 5 | import cn.nexus6p.QQMusicNotify.Base.BasicInit; 6 | import de.robv.android.xposed.XC_MethodReplacement; 7 | import de.robv.android.xposed.XposedHelpers; 8 | 9 | @Keep 10 | public class comtencentqqmusic extends BasicInit { 11 | 12 | private ClassLoader mClassloader; 13 | 14 | @Override 15 | public void init() { 16 | XposedHelpers.findAndHookMethod("com.tencent.qqmusic.fragment.morefeatures.settings.providers.NotificationStyleSettingProvider", mClassloader, "shouldUseAndroidMediaNotificationStyle", new XC_MethodReplacement() { 17 | @Override 18 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 19 | return true; 20 | } 21 | }); 22 | XposedHelpers.findAndHookMethod("com.tencent.qqmusic.fragment.morefeatures.settings.providers.NotificationStyleSettingProvider", mClassloader, "shouldUseQQMusicNotificationStyle", new XC_MethodReplacement() { 23 | @Override 24 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 25 | return false; 26 | } 27 | }); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Hook/comtencentqqmusiclocalplayer.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Hook; 2 | 3 | import android.app.Notification; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.graphics.Bitmap; 7 | import android.media.session.MediaSession; 8 | 9 | import androidx.annotation.Keep; 10 | 11 | import cn.nexus6p.QQMusicNotify.Base.BasicNotification; 12 | import de.robv.android.xposed.XC_MethodReplacement; 13 | import de.robv.android.xposed.XposedHelpers; 14 | 15 | import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; 16 | 17 | @Keep 18 | public class comtencentqqmusiclocalplayer extends BasicNotification { 19 | 20 | private static MediaSession.Token mTOKEN; 21 | 22 | @Override 23 | public void init() { 24 | final Class notifyClazz = XposedHelpers.findClass("com.tencent.qqmusiclocalplayer.business.k.s", classLoader); 25 | final Class infoClazz = XposedHelpers.findClass("com.tencent.qqmusiclocalplayer.c.e", classLoader); 26 | final Class clazz3 = XposedHelpers.findClass("com.tencent.a.d.t", classLoader); 27 | final Class clazzO = XposedHelpers.findClass("com.tencent.qqmusicsdk.a.o", classLoader); 28 | findAndHookMethod(notifyClazz, "b", Context.class, infoClazz, Bitmap.class, new XC_MethodReplacement() { 29 | @Override 30 | protected Notification replaceHookedMethod(MethodHookParam param) throws Throwable { 31 | basicParam.setIconID(0x7f020099); 32 | basicParam.setContext((Context) param.args[0]); 33 | basicParam.setBitmap((Bitmap) param.args[2]); 34 | basicParam.setStatue((!(Boolean) XposedHelpers.callStaticMethod(clazzO, "a") && ( (boolean) XposedHelpers.callStaticMethod(clazzO, "e") || (boolean) XposedHelpers.callStaticMethod(clazzO, "b")))); 35 | if (mTOKEN == null) 36 | mTOKEN = new MediaSession(basicParam.getContext(), "mbr").getSessionToken(); 37 | basicParam.setToken(mTOKEN); 38 | basicParam.setTitleString((CharSequence) XposedHelpers.callMethod(param.args[1], "getName")); 39 | basicParam.setTextString((CharSequence) XposedHelpers.callMethod(param.args[1], "getSinger")); 40 | preSongIntent = new Intent("com.tencent.qqmusicsdk.ACTION_SERVICE_PREVIOUS_TASKBAR"); 41 | playIntent = new Intent("com.tencent.qqmusicsdk.ACTION_SERVICE_TOGGLEPAUSE_TASKBAR"); 42 | nextSongIntent = new Intent("com.tencent.qqmusicsdk.ACTION_SERVICE_NEXT_TASKBAR"); 43 | contentIntent = new Intent("android.intent.action.MAIN"); 44 | contentIntent.addCategory("android.intent.category.LAUNCHER").setClassName(basicParam.getContext(), (String) XposedHelpers.callStaticMethod(clazz3, "d", basicParam.getContext())); 45 | return build(); 46 | } 47 | }); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/SharedPreferences/BasePreference.kt: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.SharedPreferences 2 | 3 | import android.content.SharedPreferences 4 | 5 | abstract class BasePreference : SharedPreferences { 6 | 7 | override fun contains(p0: String?): Boolean { 8 | throw NoSuchMethodException() 9 | } 10 | 11 | override fun unregisterOnSharedPreferenceChangeListener(p0: SharedPreferences.OnSharedPreferenceChangeListener?) { 12 | throw NoSuchMethodException() 13 | } 14 | 15 | override fun getAll(): MutableMap? { 16 | throw NoSuchMethodException() 17 | } 18 | 19 | override fun edit(): SharedPreferences.Editor { 20 | throw NoSuchMethodException() 21 | } 22 | 23 | override fun getLong(p0: String?, p1: Long): Long { 24 | throw NoSuchMethodException() 25 | } 26 | 27 | override fun getFloat(p0: String?, p1: Float): Float { 28 | throw NoSuchMethodException() 29 | } 30 | 31 | override fun getStringSet(p0: String?, p1: MutableSet?): MutableSet { 32 | throw NoSuchMethodException() 33 | } 34 | 35 | override fun registerOnSharedPreferenceChangeListener(p0: SharedPreferences.OnSharedPreferenceChangeListener?) { 36 | throw NoSuchMethodException() 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/SharedPreferences/ContentProviderPreference.kt: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.SharedPreferences 2 | 3 | import android.content.ContentResolver 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.net.Uri 7 | import android.os.Bundle 8 | import cn.nexus6p.QQMusicNotify.BackgroundActivity 9 | import cn.nexus6p.QQMusicNotify.BuildConfig 10 | import cn.nexus6p.QQMusicNotify.ContentProvider 11 | import org.json.JSONObject 12 | 13 | class ContentProviderPreference private constructor() : BasePreference() { 14 | 15 | constructor(@ContentProvider.ContentProviderParams position: String, key: String?, context: Context) : this() { 16 | var bundle: Bundle? = null 17 | if (position == ContentProvider.CONTENT_PROVIDER_COMMIT) { 18 | getBundle(position, key, context) 19 | return 20 | } 21 | if (position == ContentProvider.CONTENT_PROVIDER_JSON) { 22 | bundle = getBundle(position, key, context) 23 | } else if (position == ContentProvider.CONTENT_PROVIDER_PREFERENCE || position == ContentProvider.CONTENT_PROVIDER_DEVICE_PROTECTED_PREFERENCE) { 24 | bundle = getBundle(position, null, context) 25 | } 26 | if (bundle == null) { 27 | this.jsonObject = JSONObject() 28 | } else { 29 | //Log.d("XposedMusicNotify", "getBundle: $bundle") 30 | originalJsonString = bundle.getString(ContentProvider.BUNDLE_KEY_JSON_STRING) 31 | try { 32 | if (!originalJsonString!!.startsWith('[')) 33 | this.jsonObject = JSONObject(originalJsonString!!) 34 | } catch (e: Exception) { 35 | e.printStackTrace() 36 | jsonObject = JSONObject() 37 | } 38 | } 39 | } 40 | 41 | lateinit var jsonObject: JSONObject 42 | var originalJsonString: String? = null 43 | 44 | override fun getBoolean(key: String?, defValue: Boolean): Boolean { 45 | return jsonObject.optBoolean(key, defValue) 46 | } 47 | 48 | override fun getInt(key: String?, defValue: Int): Int { 49 | return jsonObject.optString(key, defValue.toString()).toInt(16) 50 | } 51 | 52 | override fun getString(key: String?, defValue: String?): String? { 53 | return jsonObject.optString(key, defValue ?: "") 54 | } 55 | 56 | fun getJSONString(): String { 57 | return jsonObject.toString(4) 58 | } 59 | 60 | companion object { 61 | 62 | fun getBundle(@ContentProvider.ContentProviderParams position: String, key: String?, context: Context): Bundle? { 63 | return getBundle(position,key,context,null) 64 | } 65 | 66 | fun getBundle(@ContentProvider.ContentProviderParams position: String, key: String?, context: Context, extras: Bundle?): Bundle? { 67 | try { 68 | val contentResolver: ContentResolver = context.contentResolver 69 | val uri = Uri.parse("content://cn.nexus6p.QQMusicNotify.provider/") 70 | var result: Bundle? = null 71 | try { 72 | result = contentResolver.call(uri, position, key, extras) 73 | } catch (e: RuntimeException) { 74 | try { 75 | val intent = Intent() 76 | intent.setClassName(BuildConfig.APPLICATION_ID, BackgroundActivity::class.java.name) 77 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 78 | context.startActivity(intent) 79 | } catch (e1: Throwable) { 80 | return null 81 | } 82 | } 83 | if (result == null) { 84 | result = contentResolver.call(uri, position, key, extras) 85 | } 86 | if (result == null) { 87 | return null 88 | } 89 | return result 90 | } catch (ignored: Throwable) { 91 | return null 92 | } 93 | } 94 | } 95 | 96 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/SimpleAlcatrazInteractiveCardView.kt: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify 2 | 3 | import android.content.Context 4 | import android.graphics.Color 5 | import android.graphics.drawable.Drawable 6 | import android.util.AttributeSet 7 | import android.view.LayoutInflater 8 | import android.view.View 9 | import android.widget.LinearLayout 10 | import androidx.annotation.ColorInt 11 | import androidx.annotation.DrawableRes 12 | import androidx.core.content.ContextCompat 13 | import cn.nexus6p.QQMusicNotify.databinding.SimpleAlcatrazInteractiveCardviewBinding 14 | 15 | open class SimpleAlcatrazInteractiveCardView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.style.googleBlue) : LinearLayout(context, attrs, defStyleAttr) { 16 | 17 | protected val binding: SimpleAlcatrazInteractiveCardviewBinding = SimpleAlcatrazInteractiveCardviewBinding.inflate(LayoutInflater.from(context), this, true) 18 | 19 | var active: Boolean = false 20 | set(value) { 21 | val color = if (value) ContextCompat.getColor(context, R.color.green) 22 | else ContextCompat.getColor(context, R.color.colorError) 23 | this.color = color 24 | val drawable = if (value) R.drawable.ic_check_circle else R.drawable.ic_cancel 25 | this.iconDrawable = context.getDrawable(drawable) 26 | this.iconTint = Color.WHITE 27 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlayIndicatorImage.visibility = View.VISIBLE 28 | field = value 29 | } 30 | 31 | @ColorInt 32 | var color: Int = ContextCompat.getColor(context, R.color.colorPrimary) 33 | set(value) { 34 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlayLayer.setBackgroundColor(value) 35 | field = value 36 | } 37 | 38 | @DrawableRes 39 | var iconRes: Int = -1 40 | set(value) { 41 | if (value==-1) return 42 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlayIndicatorImage.setImageResource(value) 43 | field = value 44 | } 45 | 46 | var iconDrawable: Drawable? = null 47 | set(value) { 48 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlayIndicatorImage.setImageDrawable(value) 49 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlayIndicatorImage.visibility = if (value!=null) View.VISIBLE else View.GONE 50 | field = value 51 | } 52 | 53 | @ColorInt 54 | var iconTint: Int = Color.WHITE 55 | set(value) { 56 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlayIndicatorImage.setColorFilter(value) 57 | field = value 58 | } 59 | 60 | var firstLine: String? 61 | get() { 62 | return binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlayInfo.text.toString() 63 | } 64 | set(value) { 65 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlayInfo.text = value 66 | } 67 | 68 | var secondLine: String? 69 | get() { 70 | return binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlaySubinfo.text.toString() 71 | } 72 | set(value) { 73 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlaySubinfo.text = value 74 | } 75 | 76 | var titleLine: String? 77 | get() { 78 | return binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlaySubinfo.toString() 79 | } 80 | set(value) { 81 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlayTitle.text = value 82 | } 83 | 84 | init { 85 | binding.alcatrazInteractiveCard.setShowOverlay(true) 86 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlayIndicatorImage.visibility = View.VISIBLE 87 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlayTitle.visibility = View.VISIBLE 88 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlayInfo.visibility = View.VISIBLE 89 | binding.alcatrazInteractiveCard.cardBinding.alcInteractiveCardOverlaySubinfo.visibility = View.VISIBLE 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Utils/LogUtils.kt: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Utils 2 | 3 | import android.content.Context 4 | import android.util.Log 5 | import cn.nexus6p.QQMusicNotify.ContentProvider 6 | import cn.nexus6p.QQMusicNotify.SharedPreferences.ContentProviderPreference 7 | import com.topjohnwu.superuser.Shell 8 | import java.io.File 9 | import java.text.SimpleDateFormat 10 | import java.util.* 11 | 12 | class LogUtils { 13 | 14 | companion object { 15 | fun cleanLog(max: Int, context: Context) { 16 | val logFile = File(context.filesDir.absolutePath + File.separator + "log.txt") 17 | if (!logFile.exists()) return 18 | val fileLineCount: Int = getLineCount(context) 19 | if (fileLineCount <= max) return 20 | val tmpFile = File(context.filesDir.absolutePath + File.separator + "log.tmp") 21 | if (tmpFile.exists()) tmpFile.writeText("") 22 | tmpFile.writeBytes(logFile.readBytes()) 23 | val command = "head -" + max + " " + tmpFile.absolutePath + " > " + logFile.absolutePath 24 | Log.d("log clean", command) 25 | val result = Shell.sh(command).exec() 26 | if (!result.isSuccess) Log.w("clean log", result.err.toString()) 27 | tmpFile.delete() 28 | } 29 | 30 | fun addLogByContentProvider(packageName: String, className: String, context: Context) { 31 | val string: String = SimpleDateFormat("[yyyy-MM-dd HH:mm:ss] ", Locale.getDefault()).format(Date()) + className + " hooked " + packageName + " \n" 32 | ContentProviderPreference(ContentProvider.CONTENT_PROVIDER_COMMIT, string, context) 33 | } 34 | 35 | fun addLog(string: String, context: Context) { 36 | val logFile = File(context.filesDir.absolutePath + File.separator + "log.txt") 37 | if (!logFile.exists()) logFile.createNewFile() 38 | val tmpFile = File(context.filesDir.absolutePath + File.separator + "log.tmp") 39 | if (tmpFile.exists()) tmpFile.writeText("") 40 | tmpFile.writeBytes(logFile.readBytes()) 41 | logFile.writeText(string) 42 | logFile.appendText(tmpFile.readText()) 43 | tmpFile.delete() 44 | } 45 | 46 | fun getLineCount(context: Context): Int { 47 | val logFile = File(context.filesDir.absolutePath + File.separator + "log.txt") 48 | if (!logFile.exists()) return 0 49 | if (logFile.length() < 1) return 0 50 | val lineResult = Shell.sh("wc -l " + logFile.absolutePath).exec() 51 | if (!lineResult.isSuccess) { 52 | Log.w("clean log", lineResult.err.toString()) 53 | return 0 54 | } 55 | Log.d("log clean", lineResult.out.toString()) 56 | return Integer.parseInt(lineResult.out[0].replace(logFile.absolutePath, "").replace(" ", "")) 57 | } 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Utils/MediaSessionTokenHashMap.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Utils; 2 | 3 | import android.media.session.MediaSession; 4 | 5 | import java.util.HashMap; 6 | 7 | public class MediaSessionTokenHashMap { 8 | 9 | final public static HashMap mediaSessionTokenMap = new HashMap<>(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/QQMusicNotify/Utils/PreferenceUtil.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.QQMusicNotify.Utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | import org.json.JSONArray; 7 | 8 | import cn.nexus6p.QQMusicNotify.BuildConfig; 9 | import cn.nexus6p.QQMusicNotify.ContentProvider; 10 | import cn.nexus6p.QQMusicNotify.SharedPreferences.ContentProviderPreference; 11 | 12 | final public class PreferenceUtil { 13 | 14 | @SuppressWarnings("ConstantConditions") 15 | public static boolean isGooglePlay = BuildConfig.FLAVOR.equals("play"); 16 | 17 | public static SharedPreferences getPreference(Context context) { 18 | return new ContentProviderPreference(ContentProvider.CONTENT_PROVIDER_PREFERENCE, null, context); 19 | } 20 | 21 | public static SharedPreferences getJSONPreference(String packageName, Context context) { 22 | return new ContentProviderPreference(ContentProvider.CONTENT_PROVIDER_JSON, packageName, context); 23 | } 24 | 25 | public static JSONArray getSupportPackages(Context context) { 26 | JSONArray jsonArray = null; 27 | try { 28 | jsonArray = new JSONArray(((ContentProviderPreference) PreferenceUtil.getJSONPreference("packages", context)).getOriginalJsonString()); 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | } 32 | return jsonArray; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/cn/nexus6p/removewhitenotificationforbugme/main.java: -------------------------------------------------------------------------------- 1 | package cn.nexus6p.removewhitenotificationforbugme; 2 | 3 | import android.content.res.Resources; 4 | 5 | import java.util.ArrayList; 6 | 7 | import de.robv.android.xposed.IXposedHookInitPackageResources; 8 | import de.robv.android.xposed.IXposedHookLoadPackage; 9 | import de.robv.android.xposed.XC_MethodHook; 10 | import de.robv.android.xposed.XposedHelpers; 11 | import de.robv.android.xposed.callbacks.XC_InitPackageResources; 12 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 13 | 14 | public class main implements IXposedHookInitPackageResources, IXposedHookLoadPackage { 15 | 16 | private static ArrayList nameStrings = new ArrayList<>(); 17 | static { 18 | nameStrings.add("notification_background_custom_padding_left"); 19 | nameStrings.add("notification_background_custom_padding_top"); 20 | nameStrings.add("notification_background_custom_padding_right"); 21 | nameStrings.add("notification_background_custom_padding_bottom"); 22 | nameStrings.add("notification_custom_view_margin_end"); 23 | nameStrings.add("notification_custom_view_margin_start"); 24 | nameStrings.add("notification_custom_view_corner_radius"); 25 | nameStrings.add("notification_row_extra_padding"); 26 | nameStrings.add("notification_custom_view_margin"); 27 | } 28 | 29 | @Override 30 | public void handleInitPackageResources(XC_InitPackageResources.InitPackageResourcesParam resparam) throws Throwable { 31 | for (String nameString : nameStrings) { 32 | try { 33 | final int ID = resparam.res.getIdentifier(nameString, "dimen", "com.android.systemui"); 34 | resparam.res.setReplacement(ID, 0); 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | } 40 | 41 | @Override 42 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { 43 | if (!lpparam.packageName.equals("com.android.systemui")) return; 44 | final ClassLoader classLoader = lpparam.classLoader; 45 | 46 | XposedHelpers.findAndHookMethod(Resources.class, "getDimensionPixelSize", int.class, new XC_MethodHook() { 47 | @Override 48 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 49 | final ArrayList IDs = new ArrayList<>(); 50 | for (String nameString : nameStrings) { 51 | try { 52 | IDs.add(((Resources)param.thisObject).getIdentifier(nameString, "dimen", "com.android.systemui")); 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | int resID = (int) param.args[0]; 58 | for (Integer ID : IDs) { 59 | if (resID == ID) { 60 | param.setResult(0); 61 | return; 62 | } 63 | } 64 | } 65 | }); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/me/qiwu/MusicNotification/ColorUtil.java: -------------------------------------------------------------------------------- 1 | package me.qiwu.MusicNotification; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Color; 5 | 6 | import androidx.annotation.ColorInt; 7 | import androidx.palette.graphics.Palette; 8 | 9 | /** 10 | * Created by Deng on 2019/2/20. 11 | */ 12 | 13 | public class ColorUtil { 14 | public static int[] getColor(Bitmap bitmap) { 15 | int backgroundColor = Color.BLACK; 16 | int textColor = Color.WHITE; 17 | if (bitmap != null) { 18 | Palette palette = Palette.from(bitmap).generate(); 19 | Palette.Swatch swatch = palette.getDominantSwatch(); 20 | if (swatch != null) { 21 | backgroundColor = swatch.getRgb(); 22 | textColor = getTextColor(palette, backgroundColor); 23 | } 24 | } 25 | return new int[]{backgroundColor, textColor}; 26 | } 27 | 28 | private static int getTextColor(Palette palette, int color) { 29 | boolean isLightColor = isColorLight(color); 30 | int textColor = isLightColor ? palette.getDarkMutedColor(Color.BLACK) : palette.getLightMutedColor(palette.getLightVibrantColor(Color.WHITE)); 31 | if (getDifference(color, textColor) < 100) { 32 | textColor = getReadableColor(color, textColor); 33 | } 34 | return textColor; 35 | } 36 | 37 | private static int getReadableColor(int backgroundColor, int textColor) { 38 | boolean isLight = isColorLight(backgroundColor); 39 | for (int i = 0; getDifference(textColor, backgroundColor) < 100 && i < 100; i++) { 40 | textColor = getMixedColor(textColor, isLight ? Color.BLACK : Color.WHITE); 41 | } 42 | if (getDifference(textColor, backgroundColor) < 100) { 43 | return isLight ? Color.BLACK : Color.WHITE; 44 | } 45 | return textColor; 46 | } 47 | 48 | //获取两种颜色的差异 49 | private static double getDifference(@ColorInt int color1, @ColorInt int color2) { 50 | double diff = Math.abs(0.299 * (Color.red(color1) - Color.red(color2))); 51 | diff += Math.abs(0.587 * (Color.green(color1) - Color.green(color2))); 52 | diff += Math.abs(0.114 * (Color.blue(color1) - Color.blue(color2))); 53 | return diff; 54 | } 55 | 56 | //获取两种颜色的混合颜色 57 | private static int getMixedColor(@ColorInt int color1, @ColorInt int color2) { 58 | return Color.rgb( 59 | (Color.red(color1) + Color.red(color2)) / 2, 60 | (Color.green(color1) + Color.green(color2)) / 2, 61 | (Color.blue(color1) + Color.blue(color2)) / 2 62 | ); 63 | } 64 | 65 | private static boolean isColorLight(@ColorInt int color) { 66 | return getColorDarkness(color) < 0.5; 67 | } 68 | 69 | private static double getColorDarkness(@ColorInt int color) { 70 | if (color == Color.BLACK) 71 | return 1.0; 72 | else if (color == Color.WHITE || color == Color.TRANSPARENT) 73 | return 0.0; 74 | else 75 | return (1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/name/mikanoshi/customiuizer/mods/System.java: -------------------------------------------------------------------------------- 1 | package name.mikanoshi.customiuizer.mods; 2 | 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | 6 | import de.robv.android.xposed.XC_MethodHook; 7 | import de.robv.android.xposed.XposedHelpers; 8 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 9 | 10 | public class System { 11 | public static void ExpandNotificationsHook(XC_LoadPackage.LoadPackageParam paramLoadPackageParam) { 12 | XposedHelpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", paramLoadPackageParam.classLoader, "updateRowStates", new XC_MethodHook() { 13 | protected void afterHookedMethod(MethodHookParam param1MethodHookParam) { 14 | ViewGroup viewGroup = (ViewGroup) XposedHelpers.getObjectField(param1MethodHookParam.thisObject, "mStackScroller"); 15 | for (int i = viewGroup.getChildCount() - 1; i >= 0; i--) { 16 | View view = viewGroup.getChildAt(i); 17 | if (view != null && view.getClass().getSimpleName().equalsIgnoreCase("ExpandableNotificationRow")) 18 | try { 19 | XposedHelpers.getObjectField(XposedHelpers.callMethod(view, "getEntry"), "notification"); 20 | XposedHelpers.callMethod(view, "setSystemExpanded", true); 21 | } finally { 22 | view = null; 23 | } 24 | } 25 | } 26 | }); 27 | } 28 | } 29 | 30 | 31 | /* Location: C:\Users\Neuron\Documents\Tencent Files\[数据删除]\FileRecv\MobileFile\classes.jar!\name\mikanoshi\customiuizer\mods\System.class 32 | * Java compiler version: 6 (50.0) 33 | * JD-Core Version: 1.1.2 34 | */ -------------------------------------------------------------------------------- /app/src/main/java/soptqs/medianotification/utils/ColorUtils.java: -------------------------------------------------------------------------------- 1 | package soptqs.medianotification.utils; 2 | 3 | import android.graphics.Color; 4 | 5 | import androidx.annotation.ColorInt; 6 | 7 | public class ColorUtils { 8 | 9 | public static boolean isColorLight(@ColorInt int color) { 10 | return getColorDarkness(color) < 0.5; 11 | } 12 | 13 | private static double getColorDarkness(@ColorInt int color) { 14 | if (color == Color.BLACK) 15 | return 1.0; 16 | else if (color == Color.WHITE || color == Color.TRANSPARENT) 17 | return 0.0; 18 | else 19 | return (1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255); 20 | } 21 | 22 | @ColorInt 23 | public static int getInverseColor(@ColorInt int color) { 24 | return (0xFFFFFF - color) | 0xFF000000; 25 | } 26 | 27 | public static boolean isColorSaturated(@ColorInt int color) { 28 | double max = Math.max(0.299 * Color.red(color), Math.max(0.587 * Color.green(color), 0.114 * Color.blue(color))); 29 | double min = Math.min(0.299 * Color.red(color), Math.min(0.587 * Color.green(color), 0.114 * Color.blue(color))); 30 | double diff = Math.abs(max - min); 31 | return diff > 20; 32 | } 33 | 34 | @ColorInt 35 | public static int getMixedColor(@ColorInt int color1, @ColorInt int color2) { 36 | return Color.rgb( 37 | (Color.red(color1) + Color.red(color2)) / 2, 38 | (Color.green(color1) + Color.green(color2)) / 2, 39 | (Color.blue(color1) + Color.blue(color2)) / 2 40 | ); 41 | } 42 | 43 | public static double getDifference(@ColorInt int color1, @ColorInt int color2) { 44 | double diff = Math.abs(0.299 * (Color.red(color1) - Color.red(color2))); 45 | diff += Math.abs(0.587 * (Color.green(color1) - Color.green(color2))); 46 | diff += Math.abs(0.114 * (Color.blue(color1) - Color.blue(color2))); 47 | return diff; 48 | } 49 | 50 | @ColorInt 51 | public static int getReadableText(@ColorInt int textColor, @ColorInt int backgroundColor) { 52 | return getReadableText(textColor, backgroundColor, 100); 53 | } 54 | 55 | @ColorInt 56 | public static int getReadableText(@ColorInt int textColor, @ColorInt int backgroundColor, int difference) { 57 | boolean isLight = isColorLight(backgroundColor); 58 | for (int i = 0; getDifference(textColor, backgroundColor) < difference && i < 100; i++) { 59 | textColor = getMixedColor(textColor, isLight ? Color.BLACK : Color.WHITE); 60 | } 61 | 62 | return textColor; 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /app/src/main/java/soptqs/medianotification/utils/PaletteUtils.java: -------------------------------------------------------------------------------- 1 | package soptqs.medianotification.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Color; 7 | 8 | import androidx.annotation.ColorInt; 9 | import androidx.palette.graphics.Palette; 10 | 11 | import java.util.Collections; 12 | import java.util.List; 13 | 14 | import cn.nexus6p.QQMusicNotify.Utils.PreferenceUtil; 15 | 16 | public class PaletteUtils { 17 | 18 | public static Palette getPalette(Bitmap bitmap) { 19 | if (bitmap != null) return Palette.from(bitmap).generate(); 20 | else return null; 21 | } 22 | 23 | public static Palette.Swatch getSwatch(Palette palette, Context context) { 24 | SharedPreferences prefs = PreferenceUtil.getPreference(context); 25 | 26 | if (palette == null) 27 | return new Palette.Swatch(Color.parseColor(prefs.getString(PreferenceUtils.PREF_CUSTOM_COLOR, "#FFFFFF")), 1); 28 | 29 | Palette.Swatch swatch = null; 30 | switch (Integer.parseInt(prefs.getString(PreferenceUtils.PREF_COLOR_METHOD, "0"))) { 31 | case PreferenceUtils.COLOR_METHOD_DOMINANT: 32 | swatch = palette.getDominantSwatch(); 33 | break; 34 | case PreferenceUtils.COLOR_METHOD_PRIMARY: 35 | swatch = getBestPaletteSwatchFrom(palette); 36 | break; 37 | case PreferenceUtils.COLOR_METHOD_VIBRANT: 38 | swatch = palette.getVibrantSwatch(); 39 | break; 40 | case PreferenceUtils.COLOR_METHOD_MUTED: 41 | swatch = palette.getMutedSwatch(); 42 | break; 43 | case PreferenceUtils.COLOR_METHOD_PHONOGRAPH: 44 | swatch = getHighestPopulationSwatch(palette.getSwatches()); 45 | break; 46 | } 47 | 48 | if (swatch == null) 49 | swatch = new Palette.Swatch(Color.parseColor(prefs.getString(PreferenceUtils.PREF_CUSTOM_COLOR, "#FFFFFF")), 1); 50 | 51 | return swatch; 52 | } 53 | 54 | 55 | @ColorInt 56 | public static int getTextColor(Palette palette, Palette.Swatch swatch, Context context) { 57 | SharedPreferences prefs = PreferenceUtil.getPreference(context); 58 | if (prefs.getBoolean(PreferenceUtils.PREF_HIGH_CONTRAST_TEXT, false)) { 59 | if (ColorUtils.isColorLight(swatch.getRgb())) 60 | return Color.BLACK; 61 | else return Color.WHITE; 62 | } else { 63 | int background = swatch.getRgb(); 64 | if (prefs.getBoolean(PreferenceUtils.PREF_INVERSE_TEXT_COLORS, true)) { 65 | int inverse = -1; 66 | if (palette != null) { 67 | switch (Integer.parseInt(prefs.getString(PreferenceUtils.PREF_COLOR_METHOD, "0"))) { 68 | case PreferenceUtils.COLOR_METHOD_DOMINANT: 69 | inverse = ColorUtils.isColorSaturated(background) ? palette.getMutedColor(-1) : palette.getVibrantColor(-1); 70 | break; 71 | case PreferenceUtils.COLOR_METHOD_VIBRANT: 72 | inverse = palette.getMutedColor(-1); 73 | break; 74 | case PreferenceUtils.COLOR_METHOD_MUTED: 75 | inverse = palette.getVibrantColor(-1); 76 | break; 77 | } 78 | 79 | if (inverse != -1) 80 | return ColorUtils.getReadableText(inverse, background, 150); 81 | } 82 | 83 | /*inverse = ColorUtils.getInverseColor(background); 84 | if (ColorUtils.getDifference(background, inverse) > 120 && ColorUtils.isColorSaturated(background)) 85 | return ColorUtils.getReadableText(inverse, background, 150);*/ 86 | } 87 | return ColorUtils.getReadableText(background, background); 88 | } 89 | } 90 | 91 | private static Palette.Swatch getBestPaletteSwatchFrom(Palette palette) { 92 | if (palette != null) { 93 | if (palette.getVibrantSwatch() != null) 94 | return palette.getVibrantSwatch(); 95 | else if (palette.getMutedSwatch() != null) 96 | return palette.getMutedSwatch(); 97 | else if (palette.getDarkVibrantSwatch() != null) 98 | return palette.getDarkVibrantSwatch(); 99 | else if (palette.getDarkMutedSwatch() != null) 100 | return palette.getDarkMutedSwatch(); 101 | else if (palette.getLightVibrantSwatch() != null) 102 | return palette.getLightVibrantSwatch(); 103 | else if (palette.getLightMutedSwatch() != null) 104 | return palette.getLightMutedSwatch(); 105 | else if (!palette.getSwatches().isEmpty()) 106 | return getBestPaletteSwatchFrom(palette.getSwatches()); 107 | } 108 | return null; 109 | } 110 | 111 | private static Palette.Swatch getBestPaletteSwatchFrom(List swatches) { 112 | if (swatches == null) return null; 113 | return Collections.max(swatches, (opt1, opt2) -> { 114 | int a = opt1 == null ? 0 : opt1.getPopulation(); 115 | int b = opt2 == null ? 0 : opt2.getPopulation(); 116 | return a - b; 117 | }); 118 | } 119 | 120 | public static Palette.Swatch getHighestPopulationSwatch(List swatches) { 121 | Palette.Swatch highestSwatch = null; 122 | for (Palette.Swatch swatch : swatches) { 123 | if (swatch != null) { 124 | if (highestSwatch == null || swatch.getPopulation() > highestSwatch.getPopulation()) 125 | highestSwatch = swatch; 126 | } 127 | } 128 | return highestSwatch; 129 | } 130 | } -------------------------------------------------------------------------------- /app/src/main/java/soptqs/medianotification/utils/PreferenceUtils.java: -------------------------------------------------------------------------------- 1 | package soptqs.medianotification.utils; 2 | 3 | public class PreferenceUtils { 4 | 5 | public static final String PREF_COLOR_METHOD = "colorMethod"; 6 | public static final String PREF_CUSTOM_COLOR = "customColor"; 7 | public static final String PREF_HIGH_CONTRAST_TEXT = "highContrastText"; 8 | public static final String PREF_ALWAYS_DISMISSIBLE = "always_show"; 9 | public static final String PREF_INVERSE_TEXT_COLORS = "inverseTextColors"; 10 | public static final int COLOR_METHOD_DOMINANT = 0; 11 | public static final int COLOR_METHOD_PRIMARY = 1; 12 | public static final int COLOR_METHOD_VIBRANT = 2; 13 | public static final int COLOR_METHOD_MUTED = 3; 14 | public static final int COLOR_METHOD_PHONOGRAPH = 4; 15 | public static final int COLOR_METHOD_DEFAULT = 5; 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_left_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_left_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_right_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_right_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-hdpi/ic_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-hdpi/ic_check.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-hdpi/ic_music.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-hdpi/ic_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-hdpi/ic_play.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_skip_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-hdpi/ic_skip_next.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_skip_previous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-hdpi/ic_skip_previous.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-hdpi/ic_stop.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_thumb_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-hdpi/ic_thumb_down.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_thumb_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-hdpi/ic_thumb_up.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-mdpi/ic_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-mdpi/ic_check.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-mdpi/ic_music.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-mdpi/ic_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-mdpi/ic_play.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_skip_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-mdpi/ic_skip_next.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_skip_previous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-mdpi/ic_skip_previous.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-mdpi/ic_stop.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_thumb_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-mdpi/ic_thumb_down.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_thumb_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-mdpi/ic_thumb_up.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-night/ic_github.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 13 | 16 | 19 | 22 | 25 | 28 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-night/ic_mail_outline.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_add.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_check.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_music.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_pause.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_play.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_skip_next.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_skip_previous.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_stop.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_thumb_down.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_thumb_up.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xhdpi/ic_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xhdpi/ic_check.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xhdpi/ic_music.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xhdpi/ic_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xhdpi/ic_play.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_skip_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xhdpi/ic_skip_next.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_skip_previous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xhdpi/ic_skip_previous.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xhdpi/ic_stop.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_thumb_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xhdpi/ic_thumb_down.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_thumb_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xhdpi/ic_thumb_up.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xxhdpi/ic_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xxhdpi/ic_check.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xxhdpi/ic_music.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xxhdpi/ic_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xxhdpi/ic_play.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_skip_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xxhdpi/ic_skip_next.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_skip_previous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xxhdpi/ic_skip_previous.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xxhdpi/ic_stop.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_thumb_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xxhdpi/ic_thumb_down.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_thumb_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable-xxhdpi/ic_thumb_up.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_drawable.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/edxp.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable/edxp.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/edxp_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable/edxp_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_cancel.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_circle.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_github.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 13 | 16 | 19 | 22 | 25 | 28 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mail_outline.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable/ic_music.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_refresh_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_telegram_logo.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 27 | 30 | 31 | 32 | 38 | 41 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable/icon.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/miui.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable/miui.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/singleneuron.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable/singleneuron.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/taichi.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cryolitia/XposedMusicNotify/9033ea094074ce797d6c34b9a816ae7f9c79be5e/app/src/main/res/drawable/taichi.webp -------------------------------------------------------------------------------- /app/src/main/res/layout-v24/layout_notification_collapsed.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | 43 | 44 | 49 | 50 | 59 | 60 | 61 | 62 | 73 | 74 | 79 | 80 | 89 | 90 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /app/src/main/res/layout-v24/layout_notification_collapsed_stlye2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 38 | 39 | 44 | 45 | 54 | 55 | 56 | 57 | 68 | 69 | 74 | 75 | 84 | 85 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /app/src/main/res/layout-v24/layout_notification_expanded.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 56 | 57 | 66 | 67 | 68 | 69 | 78 | 79 | 87 | 88 | 92 | 93 | 99 | 100 | 106 | 107 | 113 | 114 | 120 | 121 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /app/src/main/res/layout-v24/layout_notification_expanded_stlye2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 37 | 38 | 44 | 45 | 50 | 51 | 60 | 61 | 62 | 63 | 72 | 73 | 81 | 82 | 86 | 87 | 93 | 94 | 100 | 101 | 107 | 108 | 114 | 115 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_notification_collapsed.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 23 | 24 | 30 | 31 | 32 | 33 | 44 | 45 | 50 | 51 | 60 | 61 | 62 | 63 | 73 | 74 | 83 | 84 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_notification_collapsed_stlye2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 38 | 39 | 44 | 45 | 54 | 55 | 56 | 57 | 67 | 68 | 77 | 78 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_notification_expanded.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | 42 | 43 | 49 | 50 | 55 | 56 | 65 | 66 | 67 | 68 | 77 | 78 | 86 | 87 | 91 | 92 | 98 | 99 | 105 | 106 | 112 | 113 | 119 | 120 | 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_notification_expanded_stlye2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 37 | 38 | 44 | 45 | 50 | 51 | 60 | 61 | 62 | 63 | 72 | 73 | 81 | 82 | 86 | 87 | 93 | 94 | 100 | 101 | 107 | 108 | 114 | 115 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /app/src/main/res/layout/log_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 23 | 24 | 25 | 26 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/notifition_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | 42 | 43 | 49 | 50 | 55 | 56 | 65 | 66 | 67 | 68 | 77 | 78 | 87 | 88 | 92 | 93 | 100 | 101 | 107 | 108 | 114 | 115 | 121 | 122 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /app/src/main/res/layout/setting_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 15 | 16 | 29 | 30 | 38 | 39 | 47 | 48 | 55 | 56 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /app/src/main/res/layout/simple_alcatraz_interactive_cardview.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/third_party_source.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #1A73E8 4 | #69a1ff 5 | #101010 6 | #212121 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #1A73E8 4 | #0049b5 5 | #FF5252 6 | #efefef 7 | #F5F5F5 8 | #4CAF50 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 300 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 原生音乐通知 4 | Trying to make music players using standard notification 5 | 6 | 优势 7 | 最优 8 | 活力 9 | 柔和 10 | 主要 11 | 默认 12 | 13 | 14 | Dominant 15 | Primary 16 | Vibrant 17 | Muted 18 | Main 19 | Always Default 20 | 21 | 22 | 0 23 | 1 24 | 2 25 | 3 26 | 4 27 | 5 28 | 29 | 30 | Cloudflare CDN(推荐) 31 | Github(不推荐,无法保证速度且中国大陆极有可能无法访问) 32 | Coding(中国大陆访问备选) 33 | 自定义(仅限调试) 34 | 35 | 36 | 0 37 | 1 38 | 2 39 | 3 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/xml/apps.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/xml/detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 12 | 13 | 14 | 18 | 22 | 25 | 28 | 32 | 35 | 38 | 42 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/xml/experimental.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/xml/json_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/xml/media_notification.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 14 | 17 | 20 | 26 | 27 | 28 | 31 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/xml/music_notification.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 12 | 16 | 21 | 22 | 23 | 26 | 30 | 34 | 37 | 38 | 39 | 40 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/xml/third_party_source.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 14 | 17 | 18 | 21 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | ext.kotlin_version = '1.4.10' 4 | repositories { 5 | maven{ 6 | url "https://maven.google.com" 7 | } 8 | google() 9 | jcenter() 10 | } 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:4.1.0' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | maven{ 20 | url "https://maven.google.com" 21 | } 22 | google() 23 | jcenter() 24 | } 25 | gradle.projectsEvaluated { 26 | tasks.withType(JavaCompile) { 27 | options.compilerArgs << "-Xlint:deprecation" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /debugTool/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /debugTool/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "29.0.2" 6 | 7 | defaultConfig { 8 | applicationId "me.singleneuron.originalmusicnotification_debugtool" 9 | minSdkVersion 24 10 | targetSdkVersion 29 11 | versionCode 2 12 | versionName "1.1" 13 | } 14 | 15 | compileOptions { 16 | sourceCompatibility JavaVersion.VERSION_1_8 17 | targetCompatibility JavaVersion.VERSION_1_8 18 | } 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | 27 | } 28 | 29 | repositories { 30 | maven { url 'https://jitpack.io' } 31 | } 32 | 33 | dependencies { 34 | implementation 'com.github.topjohnwu.libsu:core:2.5.0' 35 | } 36 | -------------------------------------------------------------------------------- /debugTool/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 22 | -------------------------------------------------------------------------------- /debugTool/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /debugTool/src/main/java/me/singleneuron/originalmusicnotification_debugtool/MainActivity.java: -------------------------------------------------------------------------------- 1 | package me.singleneuron.originalmusicnotification_debugtool; 2 | 3 | 4 | import android.app.Activity; 5 | import android.content.ContentResolver; 6 | import android.content.Intent; 7 | import android.net.Uri; 8 | import android.os.Bundle; 9 | import android.util.Log; 10 | import android.widget.TextView; 11 | 12 | import com.topjohnwu.superuser.Shell; 13 | 14 | import org.json.JSONArray; 15 | import org.json.JSONException; 16 | 17 | import java.io.PrintWriter; 18 | import java.io.StringWriter; 19 | 20 | public class MainActivity extends Activity { 21 | 22 | public TextView textView; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_main); 28 | textView = findViewById(R.id.textView); 29 | TextView textView = findViewById(R.id.textView2); 30 | findViewById(R.id.Button1).setOnClickListener(v -> { 31 | try { 32 | String string = getSupportPackages(); 33 | JSONArray jsonArray = new JSONArray(string); 34 | textView.setText(jsonArray.toString(4)); 35 | } catch (JSONException e) { 36 | e.printStackTrace(); 37 | StringWriter stringWriter = new StringWriter(); 38 | PrintWriter printWriter = new PrintWriter(stringWriter); 39 | e.printStackTrace(printWriter); 40 | textView.setText(stringWriter.toString()); 41 | } 42 | }); 43 | findViewById(R.id.Button2).setOnClickListener(v -> { 44 | callBackgroundActivity(); 45 | }); 46 | try { 47 | Shell.Result result = Shell.sh("su --version").exec(); 48 | writeToTextview("su --version: " + (result.isSuccess() ? result.getOut().toString() : result.getErr().toString())); 49 | writeToTextview("taichi_magisk: " + System.getProperty("taichi_magisk")); 50 | Shell.Result result2 = Shell.su("getenforce").exec(); 51 | writeToTextview("SeLinux (real statue go by root):" + (result2.isSuccess() ? result2.getOut().toString() : result2.getErr().toString())); 52 | writeToTextview("---------------"); 53 | toHookOnInit(); 54 | toHook(); 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | StringWriter stringWriter = new StringWriter(); 58 | PrintWriter printWriter = new PrintWriter(stringWriter); 59 | e.printStackTrace(printWriter); 60 | writeToTextview(stringWriter.toString()); 61 | } 62 | } 63 | 64 | public void toHook() { 65 | writeToTextview("原生音乐通知未找到"); 66 | Log.d("XposedMusicNotify_DebugTool", "原生音乐通知未找到"); 67 | } 68 | 69 | public void toHookOnInit() { 70 | writeToTextview("初始化时原生音乐通知未找到"); 71 | Log.d("XposedMusicNotify_DebugTool", "原生音乐通知未附加到Application"); 72 | } 73 | 74 | public void writeToTextview(String string) { 75 | textView.setText(textView.getText() + string + "\n\n"); 76 | } 77 | 78 | private String getSupportPackages() { 79 | Bundle bundle = getBundle("content_provider_json", "packages"); 80 | return bundle.getString("bundle_key_json_string"); 81 | } 82 | 83 | private Bundle getBundle(String position, String key) { 84 | try { 85 | ContentResolver contentResolver = this.getContentResolver(); 86 | Uri uri = Uri.parse("content://cn.nexus6p.QQMusicNotify.provider/"); 87 | Bundle result = null; 88 | try { 89 | result = contentResolver.call(uri, position, key, null); 90 | } catch (RuntimeException e) { 91 | callBackgroundActivity(); 92 | } 93 | if (result == null) { 94 | result = contentResolver.call(uri, position, key, null); 95 | } 96 | if (result == null) { 97 | return null; 98 | } 99 | return result; 100 | } catch (Throwable ignored) { 101 | return null; 102 | } 103 | } 104 | 105 | private void callBackgroundActivity() { 106 | try { 107 | Intent intent = new Intent(); 108 | intent.setClassName("cn.nexus6p.QQMusicNotify", "cn.nexus6p.QQMusicNotify.BackgroundActivity"); 109 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 110 | this.startActivity(intent); 111 | } catch (Throwable e1) { 112 | e1.printStackTrace(); 113 | } 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /debugTool/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 20 | 21 | 25 | 26 | 31 | 32 |