【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 =
相关推荐
用户2018792831676 小时前
View设置setSoundEffectsEnabled为false后点击时还发出反馈音之谜
android
爱学习的小道长6 小时前
使用 Dify 和 LangBot 搭建飞书通信机器人
android·java·飞书
胖虎16 小时前
Android入门到实战(六):Android主流图片加载框架
android·glide·android图片加载
Kapaseker6 小时前
Compose 图片加载新姿势 — Coil 精通
android·kotlin
MiniCode6 小时前
EllipsizeEndTextview末尾省略自定义View
android·java·前端
得物技术6 小时前
R8疑难杂症分析实战:外联优化设计缺陷引起的崩溃|得物技术
android·性能优化·编译器
webbin6 小时前
Glide GifDrawable加载流程
android·glide
帅得不敢出门6 小时前
Android Framework打电话禁止播放运营商视频彩铃
android·java·framework·音视频
非凡ghost6 小时前
Solid Explorer文件管理器:功能强大的安卓文件管理器及网盘文件管理器
android·学习·软件需求