今日公司,安卓设备的音量显示不正常,让我来修复这个bug,现在已修复,做个博客,记录一下,以后碰到类似一下子就好解决。
frameworks\base\services\core\java\com\android\server\audio\AudioService.java
这个文件包含了关于android音量调节的代码逻辑。
音量调节那里,调小会直接变成0,而且过程我发现他会有跳动的感觉。
找到apk,调用这个文件的接口,添加打印了解对应逻辑。
找到问题点
数值对不上(修改apk与底层数值对应关系)
多次调用(把对应干扰流都屏蔽掉)
/**
* 设置音频流的音量。
*
* @param streamType 要设置音量的音频流类型,例如 AudioManager.STREAM_MUSIC。
* @param index 要设置的音量索引,通常是一个在音频流范围内的整数值。
* @param flags 设置标志,包括有关音量设置的额外信息,例如 AudioManager.FLAG_FIXED_VOLUME。
* @param callingPackage 调用该方法的应用程序的包名。
* @param caller 调用者的标识。
* @param uid 调用者的用户标识。
* @param hasModifyAudioSettings 是否有修改音频设置的权限。
*/
private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
String caller, int uid, boolean hasModifyAudioSettings) {
if (DEBUG_VOL) {
Log.d(TAG, "setStreamVolume(stream=" + streamType + ", index=" + index
+ ", calling=" + callingPackage + ")");
}
if(streamType != 3){
return ;
}
// 如果使用了固定音量,直接返回
if (mUseFixedVolume) {
return;
}
Log.d(TAG, "************************");
// 确保音频流类型有效
ensureValidStreamType(streamType);
// 获取音频流类型别名和对应的音量流状态
int streamTypeAlias = mStreamVolumeAlias[streamType];
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
// 获取与音频流类型别名对应的设备
final int device = getDeviceForStream(streamType);
int oldIndex;
// 如果不是 A2DP 设备,并且标志包含了 AudioManager.FLAG_BLUETOOTH_ABS_VOLUME,
// 则跳过 A2DP 绝对音量控制请求
if (!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
return;
}
// 如果是系统调用(例如硬件按键),检查当前用户以正确处理用户限制
if (uid == android.os.Process.SYSTEM_UID) {
uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
}
// 验证调用包和 app op 权限
if (!checkNoteAppOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)) {
return;
}
// 在 Android N 及以上版本,如果音量调整将切换 Zen 模式,
// 则检查是否已授予调用包通知策略的访问权限
if (isAndroidNPlus(callingPackage)
&& wouldToggleZenMode(getNewRingerMode(streamTypeAlias, index, flags))
&& !mNm.isNotificationPolicyAccessGrantedForPackage(callingPackage)) {
throw new SecurityException("Not allowed to change Do Not Disturb state");
}
// 如果音量调整在当前 Do Not Disturb 模式下不允许,则直接返回
if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
return;
}
synchronized (mSafeMediaVolumeStateLock) {
// 重置任何挂起的音量命令
mPendingVolumeCommand = null;
// 获取旧的音量索引
oldIndex = streamState.getIndex(device);
// 对索引进行重新缩放
Log.d(TAG, "缩放前 index=+"+index);
index = index * 10;//rescaleIndex(index * 10, streamType, streamTypeAlias);
Log.d(TAG, "缩放后 index=+"+index);
// 如果音频流类型别名是 STREAM_MUSIC
// 且设备是 A2DP 设备并且标志不包含 AudioManager.FLAG_BLUETOOTH_ABS_VOLUME,
// 则发送 Avrcp 绝对音量索引的消息
if (streamTypeAlias == AudioSystem.STREAM_MUSIC
&& AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
if (DEBUG_VOL) {
Log.d(TAG, "setStreamVolume postSetAvrcpAbsoluteVolumeIndex index=" + index
+ "stream=" + streamType);
}
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10);
}
// 如果设备是 HEARING_AID 设备且音频流是 HEARING_AID 类型,
// 则发送设置 HEARING_AID 音量索引的消息
if (device == AudioSystem.DEVICE_OUT_HEARING_AID
&& streamType == getHearingAidStreamType()) {
Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
+ " stream=" + streamType);
mDeviceBroker.postSetHearingAidVolumeIndex(index, streamType);
}
// 如果音频流类型别名是 STREAM_MUSIC,发送设置系统音频音量的消息
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
}
// 清除 AudioManager.FLAG_FIXED_VOLUME 标志
flags &= ~AudioManager.FLAG_FIXED_VOLUME;
// 如果音频流类型别名是 STREAM_MUSIC 且是固定音量设备,则设置 AudioManager.FLAG_FIXED_VOLUME 标志
if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {
flags |= AudioManager.FLAG_FIXED_VOLUME;
// 对于固定音量设备,音量要么为 0,要么为允许的最大值
if (index != 0) {
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
mSafeMediaVolumeDevices.contains(device)) {
index = safeMediaVolumeIndex(device);
} else {
index = streamState.getMaxIndex();
}
}
Log.d(TAG,"STREAM_MUSIC index = " + index);
}
// 如果音量超出安全范围,显示安全音量警告,并设置挂起的音量命令
if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
mVolumeController.postDisplaySafeVolumeWarning(flags);
mPendingVolumeCommand = new StreamVolumeCommand(
streamType, index, flags, device);
} else {
// 否则,调用 onSetStreamVolume 设置音量
onSetStreamVolume(streamType, index, flags, device, caller, hasModifyAudioSettings);
// 获取最终的音量索引
index = mStreamStates[streamType].getIndex(device);
Log.d(TAG, "获取最终的音量索引"+ "index=" + index + ")");
}
}
轻描淡写的俩个问题,看上去简单,如果你什么也不知道情况下调试,你就知道了。
刚解决完,马上发一篇博客,帮助更多的人,因为有问题找不到答案真的很无助,做点力所能及的事情吧。