【Audio】切换至静音或振动模式时媒体音自动置 0

一、问题描述

基于 Android 14平台,AudioService 中当用户切换到静音模式(RINGER_MODE_SILENT)或振动模式(RINGER_MODE_VIBRATE)时会自动将响铃和通知音量置0,当切换成响铃模式(RINGER_MODE_NORMAL)时,响铃和通知音量恢复原来大小。现在需要添加开关,当切换到静音或振动模式时将媒体音量置为0,切换到响铃模式时恢复之前音量大小。

二、问题分析

首先可以根据 SystemUI 下拉快速设置的 ProfileTile 点击切换模式的所执行的代码找到切入点,这里我们可以看到执行的方法是 audioManager.setRingerModeInternal

src/com/android/systemui/qs/tiles/ProfileTile.java

java 复制代码
@Override
protected void handleClick(@Nullable View view) {
    if (ActivityManager.isUserAMonkey()) {
        return;
    }
    if (audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL) {
        audioManager.setRingerModeInternal(AudioManager.RINGER_MODE_VIBRATE);
    } else if (audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
        audioManager.setRingerModeInternal(AudioManager.RINGER_MODE_SILENT);
    } else if (audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
        audioManager.setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL);
    }
    boolean newState = true;
    refreshState(newState);
}

接着在 AudioManager -> AudioService 找到 setRingerModeInternal 的具体实现方法

frameworks/base/media/java/android/media/AudioManager.java

java 复制代码
/**
 * Only useful for volume controllers.
 * @hide
 */
@UnsupportedAppUsage
public void setRingerModeInternal(int ringerMode) {
    try {
        getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

frameworks/base/services/core/java/com/android/server/audio/AudioService.java

java 复制代码
public void setRingerModeInternal(int ringerMode, String caller) {
    /**
    * Unisoc: testAdjustVolumeInTotalSilenceMode failed,to improve audioservice priority
    * BUG: 2314524
    * Unisoc Code @{
    */
    int prePriority = Thread.currentThread().getPriority();
    Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
    enforceVolumeController("setRingerModeInternal");
    setRingerMode(ringerMode, caller, false /*external*/);
    Thread.currentThread().setPriority(prePriority);
    /* @}*/
}

setRingerMode -> setRingerModeInt -> muteRingerModeStreams 通过这几层的调用找到将响铃和通知音量置为0会恢复音量的逻辑

java 复制代码
@GuardedBy("mSettingsLock")
private void muteRingerModeStreams() {
    // Mute stream if not previously muted by ringer mode and (ringer mode
    // is not RINGER_MODE_NORMAL OR stream is zen muted) and stream is affected by ringer mode.
    // Unmute stream if previously muted by ringer/zen mode and ringer mode
    // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
    int numStreamTypes = AudioSystem.getNumStreamTypes();
    if (mNm == null) {
        mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    }
    final int ringerMode = mRingerMode; // Read ringer mode as reading primitives is atomic
    final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
            || ringerMode == AudioManager.RINGER_MODE_SILENT;
    final boolean shouldRingSco = ringerMode == AudioManager.RINGER_MODE_VIBRATE
            && mDeviceBroker.isBluetoothScoActive();
    // Ask audio policy engine to force use Bluetooth SCO channel if needed
    final String eventSource = "muteRingerModeStreams() from u/pid:" + Binder.getCallingUid()
            + "/" + Binder.getCallingPid();
    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, AudioSystem.FOR_VIBRATE_RINGING,
            shouldRingSco ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE, eventSource, 0);
            
    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
        final boolean isMuted = isStreamMutedByRingerOrZenMode(streamType);
        final boolean muteAllowedBySco =
                !(shouldRingSco && streamType == AudioSystem.STREAM_RING);
        final boolean shouldZenMute = shouldZenMuteStream(streamType);
        final boolean shouldMute = shouldZenMute || (ringerModeMute
                && isStreamAffectedByRingerMode(streamType) && muteAllowedBySco);
        if (isMuted == shouldMute) continue;
        if (!shouldMute) {
            // unmute
            // ring and notifications volume should never be 0 when not silenced
            if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING
                    || mStreamVolumeAlias[streamType] == AudioSystem.STREAM_NOTIFICATION) {
                synchronized (VolumeStreamState.class) {
                    final VolumeStreamState vss = mStreamStates[streamType];
                    for (int i = 0; i < vss.mIndexMap.size(); i++) {
                        int device = vss.mIndexMap.keyAt(i);
                        int value = vss.mIndexMap.valueAt(i);
                        if (value == 0) {
                            vss.setIndex(10, device, TAG, true /*hasModifyAudioSettings*/);
                        }
                    }
                    // Persist volume for stream ring when it is changed here
                  final int device = getDeviceForStream(streamType);
                  sendMsg(mAudioHandler,
                          MSG_PERSIST_VOLUME,
                          SENDMSG_QUEUE,
                          device,
                          0,
                          mStreamStates[streamType],
                          PERSIST_DELAY);
                }
            }
            sRingerAndZenModeMutedStreams &= ~(1 << streamType);
            sMuteLogger.enqueue(new AudioServiceEvents.RingerZenMutedStreamsEvent(
                    sRingerAndZenModeMutedStreams, "muteRingerModeStreams"));
            mStreamStates[streamType].mute(false, "muteRingerModeStreams");
        } else {
            // mute
            sRingerAndZenModeMutedStreams |= (1 << streamType);
            sMuteLogger.enqueue(new AudioServiceEvents.RingerZenMutedStreamsEvent(
                    sRingerAndZenModeMutedStreams, "muteRingerModeStreams"));
            mStreamStates[streamType].mute(true, "muteRingerModeStreams");
        }
    }
}

三、解决方案

直接在 AudioService 的 muteRingerModeStreams 中将 STREAM_MUSIC 音频流设置为 mute 或 unmute 来达到置 0 和恢复效果

frameworks/base/services/core/java/com/android/server/audio/AudioService.java

java 复制代码
diff --git a/sprdroid14_sys_main/frameworks/base/services/core/java/com/android/server/audio/AudioService.java b/sprdroid14_sys_main/frameworks/base/services/core/java/com/android/server/audio/AudioService.java
index 2359afe..4451852 100755
--- a/sprdroid14_sys_main/frameworks/base/services/core/java/com/android/server/audio/AudioService.java
+++ b/sprdroid14_sys_main/frameworks/base/services/core/java/com/android/server/audio/AudioService.java
@@ -5628,6 +5628,13 @@ public class AudioService extends IAudioService.Stub
         sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, AudioSystem.FOR_VIBRATE_RINGING,
                 shouldRingSco ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE, eventSource, 0);

+        //*/ support auto mute media.
+        if (mSettings.getSecureIntForUser(mContentResolver,
+                Settings.Secure.AUTO_MUTE_MEDIA_ENABLED, 0, UserHandle.USER_CURRENT) == 1) {
+            mStreamStates[AudioSystem.STREAM_MUSIC].mute(ringerModeMute ? true : false, "muteRingerModeStreams");
+        }
+        //*/
+
         for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
             final boolean isMuted = isStreamMutedByRingerOrZenMode(streamType);
             final boolean muteAllowedBySco =
相关推荐
2501_916007475 小时前
iOS文件管理工具深度剖析,从系统沙盒到跨平台文件操作的多工具协同实践
android·macos·ios·小程序·uni-app·cocoa·iphone
Android疑难杂症5 小时前
鸿蒙Notification Kit通知服务开发快速指南
android·前端·harmonyos
lcanfly5 小时前
Mysql作业5
android·数据库·mysql
进阶的小叮当7 小时前
Vue代码打包成apk?Cordova帮你解决!
android·前端·javascript
-指短琴长-7 小时前
MySQL快速入门——基本查询(上)
android·数据库·mysql
下位子8 小时前
『OpenGL学习滤镜相机』- Day6: EGL 与 GLSurfaceView 深入理解
android·opengl
java干货8 小时前
MySQL “灵异事件”:我 INSERT id=11,为什么被 UPDATE id=10 锁住了?
android·数据库·mysql
正经教主9 小时前
【App开发】ADB 详细使用教程- Android 开发新人指南
android·adb
gx23489 小时前
MySQL-5-触发器和储存过程
android·mysql·adb
六件套是我17 小时前
redission实现延时队列
android·java·servlet