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