【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
@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
/*** 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
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会恢复音量的逻辑
@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 atomicfinal 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 neededfinal 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 silencedif (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 herefinal 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 {// mutesRingerAndZenModeMutedStreams |= (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
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.StubsendMsg(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 =