系统设置界面中就是使用AudioManager.setStreamVolume(),
说下比较难理解的flag参数在AudioManager在handlerKeyDown()中设置了两个flags,分别是FLAG_SHOW_UI和FLAG_VIBRATE.从字面上可知,前者告诉AudioService需要弹出一个音量控制面板,后者可能,只是可能是设置在为0时震动一下.而设置了FLAG_PLAY_SOUND是松开音量键时有个提示音.
源码:
/**
* Sets the volume index for a particular stream.
* This method has no effect if the device implements a fixed volume policy
* as indicated by {@link #isVolumeFixed()}.
*
From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
* the app has been granted Do Not Disturb Access.
* See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
* @param streamType The stream whose volume index should be set.
* @param index The volume index to set. See
* {@link #getStreamMaxVolume(int)} for the largest valid value.
* @param flags One or more flags.
* @see #getStreamMaxVolume(int)
* @see #getStreamVolume(int)
* @see #isVolumeFixed()
*/
public void setStreamVolume(int streamType, int index, int flags) {
IAudioService service = getService();
try {
service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
只是简单的调用了AudioService的setStreamVolume()方法,下面是AudioService#setStreamVolume()源码:
private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
String caller, int uid) {
if (mUseFixedVolume) {
return;
}
ensureValidStreamType(streamType);
//下面两句是进行流类型转换,后面会详细介绍。mStreamVolumeAlias保存了源类型
//和目标类型的映射关系。mStreamStates是保存了各种流的对应的VolumeStreamState
//VolumeStreamState保存与一个流类型所有音量相关的信息,每种流分配了一个VolumeStreamState对象
int streamTypeAlias = mStreamVolumeAlias[streamType];
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
//获取当前流使用哪一个音频设备进行播放,最终会被调用到AudioPolicyService中
final int device = getDeviceForStream(streamType);
int oldIndex;
// skip a2dp absolute volume control request when the device
// is not an a2dp device
if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
(flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
return;
}
// If we are being called by the system (e.g. hardware keys) check for current user
// so we handle user restrictions correctly.
if (uid == android.os.Process.SYSTEM_UID) {
uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
}
if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
!= AppOpsManager.MODE_ALLOWED) {
return;
}
if (isAndroidNPlus(callingPackage)
&& wouldToggleZenMode(getNewRingerMode(streamTypeAlias, index, flags))
&& !mNm.isNotificationPolicyAccessGrantedForPackage(callingPackage)) {
throw new SecurityException("Not allowed to change Do Not Disturb state");
}
if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
return;
}
synchronized (mSafeMediaVolumeState) {
// reset any pending volume command
mPendingVolumeCommand = null;
//获取当前流的音量
oldIndex = streamState.getIndex(device);//由于流类型转换需要转换设置的音量值 index = rescaleIndex(index * 10, streamType, streamTypeAlias); if (streamTypeAlias == AudioSystem.STREAM_MUSIC && (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) { synchronized (mA2dpAvrcpLock) {
应该是调用VolumeStreamState#setIndext()设置音量值的,但是API24的AudioService的setStreamVolume()代码中找不到这句。
int streamTypeAlias = mStreamVolumeAlias[streamType];
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
以上两句涉及到满足所谓的“将铃声音量作为通知音量”这种需求,如,实现“以铃声音量用作音乐音量”代码如下:
mStreamVolumeAlias[AudioSystem.STREAM_MUSIC] = AudioSystem.STREAM_RING;
这样,当传入AudioSystem.STREAM_MUSIC参数时,实际操作的回事AudioSystem.STREAM_RING这个流对应的VolumeStreamState。