diff --git a/app/src/main/java/com/sevtinge/hyperceiler/module/hook/systemframework/VolumeDisableSafe.java b/app/src/main/java/com/sevtinge/hyperceiler/module/hook/systemframework/VolumeDisableSafe.java
index 1dc30c44ff..92a0502aaf 100644
--- a/app/src/main/java/com/sevtinge/hyperceiler/module/hook/systemframework/VolumeDisableSafe.java
+++ b/app/src/main/java/com/sevtinge/hyperceiler/module/hook/systemframework/VolumeDisableSafe.java
@@ -1,44 +1,125 @@
/*
- * This file is part of HyperCeiler.
+ * This file is part of HyperCeiler.
- * HyperCeiler is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License.
+ * HyperCeiler is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
- * Copyright (C) 2023-2024 HyperCeiler Contributions
-*/
+ * Copyright (C) 2023-2024 HyperCeiler Contributions
+ */
package com.sevtinge.hyperceiler.module.hook.systemframework;
import static com.sevtinge.hyperceiler.utils.devicesdk.SystemSDKKt.isMoreAndroidVersion;
-import com.sevtinge.hyperceiler.module.base.BaseHook;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
-public class VolumeDisableSafe extends BaseHook {
+import com.hchen.hooktool.callback.IAction;
+import com.hchen.hooktool.tool.ParamTool;
+import com.sevtinge.hyperceiler.module.base.BaseTool;
- Class> mAudioService;
+public class VolumeDisableSafe extends BaseTool {
+ private static boolean isHeadsetOn = false;
+
+ private static final int mode = mPrefsMap.getStringAsInt("system_framework_volume_disable_safe_new", 0);
@Override
- public void init() {
+ public void doHook() {
if (isMoreAndroidVersion(34)) {
- // by starVoyager
- mAudioService = findClassIfExists("com.android.server.audio.SoundDoseHelperStubImpl");
- returnIntConstant(mAudioService, "updateSafeMediaVolumeIndex");
+ hcHook.findClass("sound", "com.android.server.audio.SoundDoseHelperStubImpl")
+ .getMethod("updateSafeMediaVolumeIndex", int.class)
+ .hook(new IAction() {
+ @Override
+ public void before(ParamTool param) {
+ if (mode == 1) {
+ param.setResult(2147483646);
+ return;
+ }
+ if (isHeadsetOn) param.setResult(2147483646);
+ }
+ })
+ .findClass("SoundDoseHelper", "com.android.server.audio.SoundDoseHelper")
+ .getMethod("safeMediaVolumeIndex", int.class)
+ .hook(new IAction() {
+ @Override
+ public void before(ParamTool param) {
+ if (mode == 1) {
+ param.setResult(2147483646);
+ return;
+ }
+ if (isHeadsetOn) param.setResult(2147483646);
+ }
+ })
+ .getAnyConstructor()
+ .hook(new IAction() {
+ @Override
+ public void after(ParamTool param) {
+ if (mode == 1) {
+ return;
+ }
+ Context context = param.second();
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
+ intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+ intentFilter.addAction(AudioManager.ACTION_HEADSET_PLUG);
+ context.registerReceiver(new Listener(), intentFilter);
+ }
+ })
+ ;
} else {
- mAudioService = findClassIfExists("com.android.server.audio.AudioService");
- returnIntConstant(mAudioService, "safeMediaVolumeIndex");
+ hcHook.findClass("audio", "com.android.server.audio.AudioService")
+ .getAnyMethod("safeMediaVolumeIndex")
+ .hook(new IAction() {
+ @Override
+ public void before(ParamTool param) {
+ if (mode == 1) {
+ param.setResult(2147483646);
+ return;
+ }
+ if (isHeadsetOn) param.setResult(2147483646);
+ }
+ });
}
}
- private void returnIntConstant(Class> cls, String methodName) {
- hookAllMethods(cls, methodName, MethodHook.returnConstant(2147483646));
+ private static class Listener extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action != null) {
+ switch (action) {
+ case BluetoothDevice.ACTION_ACL_CONNECTED -> {
+ isHeadsetOn = true;
+ }
+ case BluetoothDevice.ACTION_ACL_DISCONNECTED -> {
+ isHeadsetOn = false;
+ }
+ case AudioManager.ACTION_HEADSET_PLUG -> {
+ if (intent.hasExtra("state")) {
+ int state = intent.getIntExtra("state", 0);
+ if (state == 1) {
+ isHeadsetOn = true;
+ } else if (state == 0) {
+ isHeadsetOn = false;
+ }
+ }
+ }
+ }
+ }
+ }
}
}
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 1422fc6e28..f9acfc7df3 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -220,6 +220,18 @@
- 5
+
+ - @string/array_default
+ - @string/default_volume_safe_all
+ - @string/default_volume_safe_headset
+
+
+
+ - 0
+ - 1
+ - 2
+
+
- @string/open_with_test_picture
- @string/open_with_test_audio
diff --git a/app/src/main/res/xml/framework_volume.xml b/app/src/main/res/xml/framework_volume.xml
index ea4f2d4747..cc37a11086 100644
--- a/app/src/main/res/xml/framework_volume.xml
+++ b/app/src/main/res/xml/framework_volume.xml
@@ -4,62 +4,64 @@
app:myLocation="@string/system_framework_volume_title">
+ app:entryValues="@array/default_volume_streame_value" />
+
+
+ android:title="@string/system_framework_volume_first_press" />
+ android:title="@string/system_framework_volume_separate_control" />
-
-
+ android:dependency="prefs_key_system_framework_volume_separate_control"
+ android:key="prefs_key_system_framework_volume_separate_slider"
+ android:title="@string/system_framework_volume_separate_slider" />
+ android:summary="@string/system_framework_volume_media_steps_desc"
+ android:title="@string/system_framework_volume_media_steps" />
+ app:showSeekBarValue="true"
+ app:stepValue="1" />
+ app:stepValue="25" />
\ No newline at end of file