一、问题描述
基于 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 =