Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ on:
- main
- dev
- test
pull_request:
branches:
- main
- dev
- test

env:
BUILD_TYPE: ${{ inputs.build-type || 'debug' }}
Expand Down
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ android {
}

dependencies {
implementation(platform("org.jetbrains.kotlin:kotlin-bom:2.0.21"))
implementation(platform("org.jetbrains.kotlin:kotlin-bom:2.1.0"))
implementation 'androidx.core:core-ktx:1.15.0'

// Xposed Framework API dependencies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package ru.hepolise.volumekeytrackcontrolmodule
import de.robv.android.xposed.XposedBridge

object LogHelper {
fun log(text: String) {
if (BuildConfig.DEBUG) XposedBridge.log(text)
fun log(prefix: String, text: String) {
if (BuildConfig.DEBUG) XposedBridge.log("[$prefix] $text")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import androidx.annotation.Keep
import de.robv.android.xposed.IXposedHookLoadPackage
import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam
import ru.hepolise.volumekeytrackcontrolmodule.LogHelper.log
import ru.hepolise.volumekeytrackcontrolmodule.VolumeKeyHandlers.handleConstructPhoneWindowManager
import ru.hepolise.volumekeytrackcontrolmodule.VolumeKeyHandlers.handleInterceptKeyBeforeQueueing
import ru.hepolise.volumekeytrackcontrolmodule.model.HookInfo
import ru.hepolise.volumekeytrackcontrolmodule.VolumeKeyControlModuleHandlers.handleConstructPhoneWindowManager
import ru.hepolise.volumekeytrackcontrolmodule.VolumeKeyControlModuleHandlers.handleInterceptKeyBeforeQueueing
import java.io.Serializable

@Keep
class VolumeControlModule : IXposedHookLoadPackage {
Expand All @@ -20,6 +19,9 @@ class VolumeControlModule : IXposedHookLoadPackage {
private const val CLASS_IWINDOW_MANAGER = "android.view.IWindowManager"
private const val CLASS_WINDOW_MANAGER_FUNCS =
"com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs"

private fun log(text: String) =
LogHelper.log(VolumeControlModule::class.java.simpleName, text)
}

@Throws(Throwable::class)
Expand All @@ -30,61 +32,66 @@ class VolumeControlModule : IXposedHookLoadPackage {
init(lpparam.classLoader)
}

private val initMethodSignatures = mapOf(
// Android 14 & 15 signature
// https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-14.0.0_r18/services/core/java/com/android/server/policy/PhoneWindowManager.java#2033
// https://android.googlesource.com/platform/frameworks/base/+/refs/heads/android15-release/services/core/java/com/android/server/policy/PhoneWindowManager.java#2199
arrayOf(
Context::class.java,
CLASS_WINDOW_MANAGER_FUNCS
) to "Using Android 14 or 15 method signature",

// Android 13 signature
// https://android.googlesource.com/platform/frameworks/base/+/refs/heads/android13-dev/services/core/java/com/android/server/policy/PhoneWindowManager.java#1873
arrayOf(
Context::class.java,
CLASS_IWINDOW_MANAGER,
CLASS_WINDOW_MANAGER_FUNCS
) to "Using Android 13 method signature",

// HyperOS-specific signature
arrayOf(
Context::class.java,
CLASS_WINDOW_MANAGER_FUNCS,
CLASS_IWINDOW_MANAGER
) to "Using HyperOS-specific method signature"
)

private fun init(classLoader: ClassLoader) {
val hookInfoList = listOf(
// Android 14 & 15 signature
// https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-14.0.0_r18/services/core/java/com/android/server/policy/PhoneWindowManager.java#2033
// https://android.googlesource.com/platform/frameworks/base/+/refs/heads/android15-release/services/core/java/com/android/server/policy/PhoneWindowManager.java#2199
HookInfo(
params = arrayOf(Context::class.java, CLASS_WINDOW_MANAGER_FUNCS),
logMessage = "Using Android 14 or 15 method signature"
),
// Android 13 signature
// https://android.googlesource.com/platform/frameworks/base/+/refs/heads/android13-dev/services/core/java/com/android/server/policy/PhoneWindowManager.java#1873
HookInfo(
params = arrayOf(
Context::class.java,
CLASS_IWINDOW_MANAGER,
CLASS_WINDOW_MANAGER_FUNCS
),
logMessage = "Using Android 13 method signature"
),
// HyperOS-specific signature
HookInfo(
params = arrayOf(
Context::class.java,
CLASS_WINDOW_MANAGER_FUNCS,
CLASS_IWINDOW_MANAGER
),
logMessage = "Using HyperOS-specific method signature"
),
)
val foundMethod = initMethodSignatures.any { (params, logMessage) ->
tryHookMethod(classLoader, params, logMessage)
}

var foundMethod = false
for (hookInfo in hookInfoList) {
try {
XposedHelpers.findAndHookMethod(
CLASS_PHONE_WINDOW_MANAGER, classLoader, "init",
*hookInfo.params, handleConstructPhoneWindowManager
)
foundMethod = true
log(hookInfo.logMessage)
break
} catch (ignored: NoSuchMethodError) {
}
if (!foundMethod) {
log("Method hook failed for init!")
return
}
if (foundMethod) {
// https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-14.0.0_r18/services/core/java/com/android/server/policy/PhoneWindowManager.java#4117

// https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-14.0.0_r18/services/core/java/com/android/server/policy/PhoneWindowManager.java#4117
XposedHelpers.findAndHookMethod(
CLASS_PHONE_WINDOW_MANAGER,
classLoader,
"interceptKeyBeforeQueueing",
KeyEvent::class.java,
Int::class.javaPrimitiveType,
handleInterceptKeyBeforeQueueing
)
}

private fun tryHookMethod(
classLoader: ClassLoader,
params: Array<Serializable>,
logMessage: String
): Boolean {
return try {
XposedHelpers.findAndHookMethod(
CLASS_PHONE_WINDOW_MANAGER,
classLoader,
"interceptKeyBeforeQueueing",
KeyEvent::class.java,
Int::class.javaPrimitiveType,
handleInterceptKeyBeforeQueueing
CLASS_PHONE_WINDOW_MANAGER, classLoader, "init",
*params, handleConstructPhoneWindowManager
)
} else {
log("Method hook failed for init!")
log(logMessage)
true
} catch (ignored: NoSuchMethodError) {
false
}
}
}
Loading
Loading