当我们使用按键调节音量时首先会调用到PhoneWindowManager来处理点击事件
public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
int policyFlags) {
final boolean keyguardOn = keyguardOn();
final int keyCode = event.getKeyCode();
final int repeatCount = event.getRepeatCount();
final int metaState = event.getMetaState();
final int flags = event.getFlags();
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
final int displayId = event.getDisplayId();
final long key_consumed = -1;
final long key_not_consumed = 0;
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
+ repeatCount + " keyguardOn=" + keyguardOn + " canceled=" + canceled);
}
if (mKeyCombinationManager.isKeyConsumed(event)) {
return key_consumed;
}
if ((flags & KeyEvent.FLAG_FALLBACK) == 0) {
final long now = SystemClock.uptimeMillis();
final long interceptTimeout = mKeyCombinationManager.getKeyInterceptTimeout(keyCode);
if (now < interceptTimeout) {
return interceptTimeout - now;
}
}
// Cancel any pending meta actions if we see any other keys being pressed between the down
// of the meta key and its corresponding up.
if (mPendingMetaAction && !KeyEvent.isMetaKey(keyCode)) {
mPendingMetaAction = false;
}
// Any key that is not Alt or Meta cancels Caps Lock combo tracking.
if (mPendingCapsLockToggle && !KeyEvent.isMetaKey(keyCode) && !KeyEvent.isAltKey(keyCode)) {
mPendingCapsLockToggle = false;
}
if (isUserSetupComplete() && !keyguardOn) {
if (mModifierShortcutManager.interceptKey(event)) {
dismissKeyboardShortcutsMenu();
mPendingMetaAction = false;
mPendingCapsLockToggle = false;
return key_consumed;
}
}
switch(keyCode) {
case KeyEvent.KEYCODE_HOME:
return handleHomeShortcuts(displayId, focusedToken, event);
case KeyEvent.KEYCODE_MENU:
// Hijack modified menu keys for debugging features
final int chordBug = KeyEvent.META_SHIFT_ON;
if (down && repeatCount == 0) {
if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
null, null, null, 0, null, null);
return key_consumed;
}
}
break;
case KeyEvent.KEYCODE_RECENT_APPS:
if (down && repeatCount == 0) {
showRecentApps(false /* triggeredFromAltTab */);
}
return key_consumed;
case KeyEvent.KEYCODE_APP_SWITCH:
if (!keyguardOn) {
if (down && repeatCount == 0) {
preloadRecentApps();
} else if (!down) {
toggleRecentApps();
}
}
return key_consumed;
case KeyEvent.KEYCODE_A:
if (down && event.isMetaPressed()) {
launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
event.getDeviceId(),
event.getEventTime(), AssistUtils.INVOCATION_TYPE_UNKNOWN);
return key_consumed;
}
break;
case KeyEvent.KEYCODE_H:
case KeyEvent.KEYCODE_ENTER:
if (event.isMetaPressed()) {
return handleHomeShortcuts(displayId, focusedToken, event);
}
break;
case KeyEvent.KEYCODE_I:
if (down && event.isMetaPressed()) {
showSystemSettings();
return key_consumed;
}
break;
case KeyEvent.KEYCODE_N:
if (down && event.isMetaPressed()) {
if (event.isCtrlPressed()) {
sendSystemKeyToStatusBarAsync(event);
} else {
toggleNotificationPanel();
}
return key_consumed;
}
break;
case KeyEvent.KEYCODE_S:
if (down && event.isMetaPressed() && event.isCtrlPressed() && repeatCount == 0) {
interceptScreenshotChord(SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
return key_consumed;
}
break;
case KeyEvent.KEYCODE_T:
if (down && event.isMetaPressed()) {
toggleTaskbar();
return key_consumed;
}
break;
case KeyEvent.KEYCODE_DPAD_UP:
if (down && event.isMetaPressed() && event.isCtrlPressed() && repeatCount == 0) {
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
if (statusbar != null) {
statusbar.goToFullscreenFromSplit();
}
return key_consumed;
}
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
if (down && event.isMetaPressed() && event.isCtrlPressed() && repeatCount == 0) {
enterStageSplitFromRunningApp(true /* leftOrTop */);
return key_consumed;
}
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (down && event.isMetaPressed() && event.isCtrlPressed() && repeatCount == 0) {
enterStageSplitFromRunningApp(false /* leftOrTop */);
return key_consumed;
}
break;
case KeyEvent.KEYCODE_SLASH:
if (down && repeatCount == 0 && event.isMetaPressed() && !keyguardOn) {
toggleKeyboardShortcutsMenu(event.getDeviceId());
return key_consumed;
}
break;
case KeyEvent.KEYCODE_ASSIST:
Slog.wtf(TAG, "KEYCODE_ASSIST should be handled in interceptKeyBeforeQueueing");
return key_consumed;
case KeyEvent.KEYCODE_VOICE_ASSIST:
Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in"
+ " interceptKeyBeforeQueueing");
return key_consumed;
case KeyEvent.KEYCODE_VIDEO_APP_1:
case KeyEvent.KEYCODE_VIDEO_APP_2:
case KeyEvent.KEYCODE_VIDEO_APP_3:
case KeyEvent.KEYCODE_VIDEO_APP_4:
case KeyEvent.KEYCODE_VIDEO_APP_5:
case KeyEvent.KEYCODE_VIDEO_APP_6:
case KeyEvent.KEYCODE_VIDEO_APP_7:
case KeyEvent.KEYCODE_VIDEO_APP_8:
case KeyEvent.KEYCODE_FEATURED_APP_1:
case KeyEvent.KEYCODE_FEATURED_APP_2:
case KeyEvent.KEYCODE_FEATURED_APP_3:
case KeyEvent.KEYCODE_FEATURED_APP_4:
case KeyEvent.KEYCODE_DEMO_APP_1:
case KeyEvent.KEYCODE_DEMO_APP_2:
case KeyEvent.KEYCODE_DEMO_APP_3:
case KeyEvent.KEYCODE_DEMO_APP_4:
Slog.wtf(TAG, "KEYCODE_APP_X should be handled in interceptKeyBeforeQueueing");
return key_consumed;
case KeyEvent.KEYCODE_BRIGHTNESS_UP:
case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
if (down) {
int direction = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP ? 1 : -1;
// Disable autobrightness if it's on
int auto = Settings.System.getIntForUser(
mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
UserHandle.USER_CURRENT_OR_SELF);
if (auto != 0) {
Settings.System.putIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
UserHandle.USER_CURRENT_OR_SELF);
}
int screenDisplayId = displayId < 0 ? DEFAULT_DISPLAY : displayId;
float minLinearBrightness = mPowerManager.getBrightnessConstraint(
PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
float maxLinearBrightness = mPowerManager.getBrightnessConstraint(
PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
float linearBrightness = mDisplayManager.getBrightness(screenDisplayId);
float gammaBrightness = BrightnessUtils.convertLinearToGamma(linearBrightness);
float adjustedGammaBrightness =
gammaBrightness + 1f / BRIGHTNESS_STEPS * direction;
adjustedGammaBrightness = MathUtils.constrain(adjustedGammaBrightness, 0f,
1f);
float adjustedLinearBrightness = BrightnessUtils.convertGammaToLinear(
adjustedGammaBrightness);
adjustedLinearBrightness = MathUtils.constrain(adjustedLinearBrightness,
minLinearBrightness, maxLinearBrightness);
mDisplayManager.setBrightness(screenDisplayId, adjustedLinearBrightness);
startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG),
UserHandle.CURRENT_OR_SELF);
}
return key_consumed;
case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN:
if (down) {
mInputManagerInternal.decrementKeyboardBacklight(event.getDeviceId());
}
return key_consumed;
case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP:
if (down) {
mInputManagerInternal.incrementKeyboardBacklight(event.getDeviceId());
}
return key_consumed;
case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE:
// TODO: Add logic
return key_consumed;
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE:
if (mUseTvRouting || mHandleVolumeKeysInWM) {
// On TVs or when the configuration is enabled, volume keys never
// go to the foreground app.
dispatchDirectAudioEvent(event);
return key_consumed;
}
// If the device is in VR mode and keys are "internal" (e.g. on the side of the
// device), then drop the volume keys and don't forward it to the
// application/dispatch the audio event.
if (mDefaultDisplayPolicy.isPersistentVrModeEnabled()) {
final InputDevice d = event.getDevice();
if (d != null && !d.isExternal()) {
return key_consumed;
}
}
break;
case KeyEvent.KEYCODE_TAB:
if (down && event.isMetaPressed()) {
if (!keyguardOn && isUserSetupComplete()) {
showRecentApps(false);
return key_consumed;
}
} else if (down && repeatCount == 0) {
// Display task switcher for ALT-TAB.
if (mRecentAppsHeldModifiers == 0 && !keyguardOn && isUserSetupComplete()) {
final int shiftlessModifiers =
event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
if (KeyEvent.metaStateHasModifiers(
shiftlessModifiers, KeyEvent.META_ALT_ON)) {
mRecentAppsHeldModifiers = shiftlessModifiers;
showRecentApps(true);
return key_consumed;
}
}
}
break;
case KeyEvent.KEYCODE_ALL_APPS:
if (!keyguardOn) {
if (down && repeatCount == 0) {
preloadRecentApps();
} else if (!down) {
toggleRecentApps();
}
}
return key_consumed;
case KeyEvent.KEYCODE_NOTIFICATION:
if (!down) {
toggleNotificationPanel();
}
return key_consumed;
case KeyEvent.KEYCODE_SEARCH:
if (down && repeatCount == 0 && !keyguardOn()) {
switch(mSearchKeyBehavior) {
case SEARCH_BEHAVIOR_TARGET_ACTIVITY: {
launchTargetSearchActivity();
return key_consumed;
}
case SEARCH_BEHAVIOR_DEFAULT_SEARCH:
default:
break;
}
}
break;
case KeyEvent.KEYCODE_LANGUAGE_SWITCH:
if (down && repeatCount == 0) {
int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
sendSwitchKeyboardLayout(event, direction);
return key_consumed;
}
break;
case KeyEvent.KEYCODE_SPACE:
// Handle keyboard layout switching. (META + SPACE)
if ((metaState & KeyEvent.META_META_MASK) == 0) {
return key_not_consumed;
}
if (down && repeatCount == 0) {
int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
sendSwitchKeyboardLayout(event, direction);
return key_consumed;
}
break;
case KeyEvent.KEYCODE_META_LEFT:
case KeyEvent.KEYCODE_META_RIGHT:
if (down) {
if (event.isAltPressed()) {
mPendingCapsLockToggle = true;
mPendingMetaAction = false;
} else {
mPendingCapsLockToggle = false;
mPendingMetaAction = true;
}
} else {
// Toggle Caps Lock on META-ALT.
if (mPendingCapsLockToggle) {
mInputManagerInternal.toggleCapsLock(event.getDeviceId());
mPendingCapsLockToggle = false;
} else if (mPendingMetaAction) {
if (!canceled) {
launchAllAppsViaA11y();
}
mPendingMetaAction = false;
}
}
return key_consumed;
case KeyEvent.KEYCODE_ALT_LEFT:
case KeyEvent.KEYCODE_ALT_RIGHT:
if (down) {
if (event.isMetaPressed()) {
mPendingCapsLockToggle = true;
mPendingMetaAction = false;
} else {
mPendingCapsLockToggle = false;
}
} else {
// hide recent if triggered by ALT-TAB.
if (mRecentAppsHeldModifiers != 0
&& (metaState & mRecentAppsHeldModifiers) == 0) {
mRecentAppsHeldModifiers = 0;
hideRecentApps(true, false);
return key_consumed;
}
// Toggle Caps Lock on META-ALT.
if (mPendingCapsLockToggle) {
mInputManagerInternal.toggleCapsLock(event.getDeviceId());
mPendingCapsLockToggle = false;
return key_consumed;
}
}
break;
case KeyEvent.KEYCODE_STYLUS_BUTTON_PRIMARY:
case KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY:
case KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY:
case KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL:
Slog.wtf(TAG, "KEYCODE_STYLUS_BUTTON_* should be handled in"
+ " interceptKeyBeforeQueueing");
return key_consumed;
}
if (isValidGlobalKey(keyCode)
&& mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
return key_consumed;
}
// Reserve all the META modifier combos for system behavior
if ((metaState & KeyEvent.META_META_ON) != 0) {
return key_consumed;
}
// Let the application handle the key.
return key_not_consumed;
}
方法有点长,我们主要看下音量调节的
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE:
if (mUseTvRouting || mHandleVolumeKeysInWM) {
// On TVs or when the configuration is enabled, volume keys never
// go to the foreground app.
dispatchDirectAudioEvent(event);
return key_consumed;
}
接下来他就会调用dispatchDirectAudioEvent,
private void dispatchDirectAudioEvent(KeyEvent event) {
// When System Audio Mode is off, volume keys received by AVR can be either consumed by AVR
// or forwarded to the TV. It's up to Amplifier manufacturer’s implementation.
HdmiControlManager hdmiControlManager = getHdmiControlManager();
if (null != hdmiControlManager
&& !hdmiControlManager.getSystemAudioMode()
&& shouldCecAudioDeviceForwardVolumeKeysSystemAudioModeOff()) {
HdmiAudioSystemClient audioSystemClient = hdmiControlManager.getAudioSystemClient();
if (audioSystemClient != null) {
audioSystemClient.sendKeyEvent(
event.getKeyCode(), event.getAction() == KeyEvent.ACTION_DOWN);
return;
}
}
try {
//这里得到服务并开始设置,这里用到了binder=
getAudioService().handleVolumeKey(event, mUseTvRouting,
mContext.getOpPackageName(), TAG);
} catch (Exception e) {
Log.e(TAG, "Error dispatching volume key in handleVolumeKey for event:"
+ event, e);
}
}
static IAudioService getAudioService() {
IAudioService audioService = IAudioService.Stub.asInterface(
ServiceManager.checkService(Context.AUDIO_SERVICE));
if (audioService == null) {
Log.w(TAG, "Unable to find IAudioService interface.");
}
return audioService;
}
接下来我们找下IAudioService的实现类AudioService
他这里要调用handleVolumeKey
public void handleVolumeKey(@NonNull KeyEvent event, boolean isOnTv,
@NonNull String callingPackage, @NonNull String caller) {
int keyEventMode = AudioDeviceVolumeManager.ADJUST_MODE_NORMAL;
if (isOnTv) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
keyEventMode = AudioDeviceVolumeManager.ADJUST_MODE_START;
} else { // may catch more than ACTION_UP, but will end vol adjustement
// the vol key is either released (ACTION_UP), or multiple keys are pressed
// (ACTION_MULTIPLE) and we don't know what to do for volume control on CEC, end
// the repeated volume adjustement
keyEventMode = AudioDeviceVolumeManager.ADJUST_MODE_END;
}
} else if (event.getAction() != KeyEvent.ACTION_DOWN) {
return;
}
int flags = AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_PLAY_SOUND
| AudioManager.FLAG_FROM_KEY;
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_VOLUME_UP:
adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
Binder.getCallingUid(), Binder.getCallingPid(), true, keyEventMode);
break;
case KeyEvent.KEYCODE_VOLUME_DOWN:
adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
Binder.getCallingUid(), Binder.getCallingPid(), true, keyEventMode);
break;
case KeyEvent.KEYCODE_VOLUME_MUTE:
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
adjustSuggestedStreamVolume(AudioManager.ADJUST_TOGGLE_MUTE,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
Binder.getCallingUid(), Binder.getCallingPid(),
true, AudioDeviceVolumeManager.ADJUST_MODE_NORMAL);
}
break;
default:
Log.e(TAG, "Invalid key code " + event.getKeyCode() + " sent by " + callingPackage);
return; // not needed but added if code gets added below this switch statement
}
}
之后会调用adjustSuggestedStreamVolume来处理点击事件
private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage, String caller, int uid, int pid, boolean hasModifyAudioSettings,
int keyEventMode) {
if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
+ ", flags=" + flags + ", caller=" + caller
+ ", volControlStream=" + mVolumeControlStream
+ ", userSelect=" + mUserSelectedVolumeControlStream);
if (direction != AudioManager.ADJUST_SAME) {
sVolumeLogger.enqueue(
new VolumeEvent(VolumeEvent.VOL_ADJUST_SUGG_VOL, suggestedStreamType,
direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage)
.append("/").append(caller).append(" uid:").append(uid).toString()));
}
boolean hasExternalVolumeController = notifyExternalVolumeController(direction);
new MediaMetrics.Item(mMetricsId + "adjustSuggestedStreamVolume")
.setUid(Binder.getCallingUid())
.set(MediaMetrics.Property.CALLING_PACKAGE, callingPackage)
.set(MediaMetrics.Property.CLIENT_NAME, caller)
.set(MediaMetrics.Property.DIRECTION, direction > 0
? MediaMetrics.Value.UP : MediaMetrics.Value.DOWN)
.set(MediaMetrics.Property.EXTERNAL, hasExternalVolumeController
? MediaMetrics.Value.YES : MediaMetrics.Value.NO)
.set(MediaMetrics.Property.FLAGS, flags)
.record();
if (hasExternalVolumeController) {
return;
}
final int streamType;
synchronized (mForceControlStreamLock) {
// Request lock in case mVolumeControlStream is changed by other thread.
if (mUserSelectedVolumeControlStream) { // implies mVolumeControlStream != -1
streamType = mVolumeControlStream;
} else {
// TODO discard activity on a muted stream?
final int maybeActiveStreamType = getActiveStreamType(suggestedStreamType);
final boolean activeForReal;
if (maybeActiveStreamType == AudioSystem.STREAM_RING
|| maybeActiveStreamType == AudioSystem.STREAM_NOTIFICATION) {
activeForReal = wasStreamActiveRecently(maybeActiveStreamType, 0);
} else {
activeForReal = mAudioSystem.isStreamActive(maybeActiveStreamType, 0);
}
if (activeForReal || mVolumeControlStream == -1) {
streamType = maybeActiveStreamType;
} else {
streamType = mVolumeControlStream;
}
}
}
final boolean isMute = isMuteAdjust(direction);
ensureValidStreamType(streamType);
final int resolvedStream = mStreamVolumeAlias[streamType];
// Play sounds on STREAM_RING only.
if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
resolvedStream != AudioSystem.STREAM_RING) {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
}
// For notifications/ring, show the ui before making any adjustments
// Don't suppress mute/unmute requests
// Don't suppress adjustments for single volume device
if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)
&& !mIsSingleVolume) {
direction = 0;
flags &= ~AudioManager.FLAG_PLAY_SOUND;
flags &= ~AudioManager.FLAG_VIBRATE;
if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
}
adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid, pid,
null, hasModifyAudioSettings, keyEventMode);
}
这个方法最后会调用adjustStreamVolume,到这个方法后会执行两个操作,一个向上通知来让ui做出响应,一个向下来让系统调节音量
protected void adjustStreamVolume(int streamType, int direction, int flags,
String callingPackage, String caller, int uid, int pid, String attributionTag,
boolean hasModifyAudioSettings, int keyEventMode) {
if (mUseFixedVolume) {
return;
}
if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
+ ", flags=" + flags + ", caller=" + caller);
ensureValidDirection(direction);
ensureValidStreamType(streamType);
boolean isMuteAdjust = isMuteAdjust(direction);
if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
return;
}
// If adjust is mute and the stream is STREAM_VOICE_CALL or STREAM_BLUETOOTH_SCO, make sure
// that the calling app have the MODIFY_PHONE_STATE permission.
if (isMuteAdjust &&
(streamType == AudioSystem.STREAM_VOICE_CALL ||
streamType == AudioSystem.STREAM_BLUETOOTH_SCO) &&
mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
!= PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: adjustStreamVolume from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
return;
}
// If the stream is STREAM_ASSISTANT,
// make sure that the calling app have the MODIFY_AUDIO_ROUTING permission.
if (streamType == AudioSystem.STREAM_ASSISTANT &&
mContext.checkPermission(
android.Manifest.permission.MODIFY_AUDIO_ROUTING, pid, uid)
!= PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "MODIFY_AUDIO_ROUTING Permission Denial: adjustStreamVolume from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
return;
}
// use stream type alias here so that streams with same alias have the same behavior,
// including with regard to silent mode control (e.g the use of STREAM_RING below and in
// checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
int streamTypeAlias = mStreamVolumeAlias[streamType];
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
final int device = getDeviceForStream(streamTypeAlias);
int aliasIndex = streamState.getIndex(device);
boolean adjustVolume = true;
int step;
// skip a2dp absolute volume control request when the device
// is neither an a2dp device nor BLE device
if ((!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& !AudioSystem.DEVICE_OUT_ALL_BLE_SET.contains(device))
&& (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));
}
// validate calling package and app op
if (!checkNoteAppOp(
STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage, attributionTag)) {
return;
}
mSoundDoseHelper.invalidatPendingVolumeCommand();
flags &= ~AudioManager.FLAG_FIXED_VOLUME;
if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {
flags |= AudioManager.FLAG_FIXED_VOLUME;
// Always toggle between max safe volume and 0 for fixed volume devices where safe
// volume is enforced, and max and 0 for the others.
// This is simulated by stepping by the full allowed volume range
step = mSoundDoseHelper.getSafeMediaVolumeIndex(device);
if (step < 0) {
step = streamState.getMaxIndex();
}
if (aliasIndex != 0) {
aliasIndex = step;
}
} else {
// convert one UI step (+/-1) into a number of internal units on the stream alias
step = rescaleStep(10, streamType, streamTypeAlias);
}
// If either the client forces allowing ringer modes for this adjustment,
// or stream is used for UI sonification
if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
(isUiSoundsStreamType(streamTypeAlias))) {
int ringerMode = getRingerModeInternal();
// do not vibrate if already in vibrate mode
if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
flags &= ~AudioManager.FLAG_VIBRATE;
}
// Check if the ringer mode handles this adjustment. If it does we don't
// need to adjust the volume further.
final int result = checkForRingerModeChange(aliasIndex, direction, step,
streamState.mIsMuted, callingPackage, flags);
adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
// If suppressing a volume adjustment in silent mode, display the UI hint
if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
}
// If suppressing a volume down adjustment in vibrate mode, display the UI hint
if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
}
} else if (isStreamMutedByRingerOrZenMode(streamTypeAlias) && streamState.mIsMuted) {
// if the stream is currently muted streams by ringer/zen mode
// then it cannot be unmuted (without FLAG_ALLOW_RINGER_MODES) with an unmute or raise
if (direction == AudioManager.ADJUST_TOGGLE_MUTE
|| direction == AudioManager.ADJUST_UNMUTE
|| direction == AudioManager.ADJUST_RAISE) {
adjustVolume = false;
}
}
// If the ringer mode or zen is muting the stream, do not change stream unless
// it'll cause us to exit dnd
if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
adjustVolume = false;
}
int oldIndex = mStreamStates[streamType].getIndex(device);
// Check if the volume adjustment should be handled by an absolute volume controller instead
if (isAbsoluteVolumeDevice(device)
&& (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) {
AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device);
if (info.mHandlesVolumeAdjustment) {
dispatchAbsoluteVolumeAdjusted(streamType, info, oldIndex, direction,
keyEventMode);
return;
}
}
if (adjustVolume && (direction != AudioManager.ADJUST_SAME)
&& (keyEventMode != AudioDeviceVolumeManager.ADJUST_MODE_END)) {
mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
if (isMuteAdjust && !mFullVolumeDevices.contains(device)) {
boolean state;
if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
state = !streamState.mIsMuted;
} else {
state = direction == AudioManager.ADJUST_MUTE;
}
muteAliasStreams(streamTypeAlias, state);
} else if ((direction == AudioManager.ADJUST_RAISE)
&& mSoundDoseHelper.raiseVolumeDisplaySafeMediaVolume(streamTypeAlias,
aliasIndex + step, device, flags)) {
Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
} else if (!isFullVolumeDevice(device)
&& (streamState.adjustIndex(direction * step, device, caller,
hasModifyAudioSettings)
|| streamState.mIsMuted)) {
// Post message to set system volume (it in turn will post a
// message to persist).
if (streamState.mIsMuted) {
// Unmute the stream if it was previously muted
if (direction == AudioManager.ADJUST_RAISE) {
// unmute immediately for volume up
muteAliasStreams(streamTypeAlias, false);
} else if (direction == AudioManager.ADJUST_LOWER) {
if (mIsSingleVolume) {
sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
}
}
}
sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
0);
}
int newIndex = mStreamStates[streamType].getIndex(device);
// Check if volume update should be send to 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, "adjustStreamVolume: postSetAvrcpAbsoluteVolumeIndex index="
+ newIndex + "stream=" + streamType);
}
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex / 10);
} else if (isAbsoluteVolumeDevice(device)
&& (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) {
AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device);
dispatchAbsoluteVolumeChanged(streamType, info, newIndex);
}
if (AudioSystem.isLeAudioDeviceType(device)
&& (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
int nowStreamType = getBluetoothContextualVolumeStream();
if (streamType == nowStreamType ||
(streamType == AudioSystem.STREAM_MUSIC
&& nowStreamType == AudioSystem.STREAM_VOICE_CALL
&& direction == AudioManager.ADJUST_UNMUTE)) {
streamType = nowStreamType;
newIndex = mStreamStates[streamType].getIndex(device);
if (DEBUG_VOL) {
Log.d(TAG, "adjustStreamVolume postSetLeAudioVolumeIndex index="
+ newIndex + " stream=" + streamType);
}
mDeviceBroker.postSetLeAudioVolumeIndex(newIndex,
mStreamStates[streamType].getMaxIndex(), streamType);
}
}
// Check if volume update should be send to Hearing Aid
if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
// only modify the hearing aid attenuation when the stream to modify matches
// the one expected by the hearing aid
if (streamType == getBluetoothContextualVolumeStream()) {
if (DEBUG_VOL) {
Log.d(TAG, "adjustStreamVolume postSetHearingAidVolumeIndex index="
+ newIndex + " stream=" + streamType);
}
mDeviceBroker.postSetHearingAidVolumeIndex(newIndex, streamType);
}
}
}
final int newIndex = mStreamStates[streamType].getIndex(device);
if (adjustVolume) {
synchronized (mHdmiClientLock) {
if (mHdmiManager != null) {
// At most one of mHdmiPlaybackClient and mHdmiTvClient should be non-null
HdmiClient fullVolumeHdmiClient = mHdmiPlaybackClient;
if (mHdmiTvClient != null) {
fullVolumeHdmiClient = mHdmiTvClient;
}
if (fullVolumeHdmiClient != null
&& mHdmiCecVolumeControlEnabled
&& streamTypeAlias == AudioSystem.STREAM_MUSIC
// vol change on a full volume device
&& isFullVolumeDevice(device)) {
int keyCode = KeyEvent.KEYCODE_UNKNOWN;
switch (direction) {
case AudioManager.ADJUST_RAISE:
keyCode = KeyEvent.KEYCODE_VOLUME_UP;
break;
case AudioManager.ADJUST_LOWER:
keyCode = KeyEvent.KEYCODE_VOLUME_DOWN;
break;
case AudioManager.ADJUST_TOGGLE_MUTE:
case AudioManager.ADJUST_MUTE:
case AudioManager.ADJUST_UNMUTE:
// Many CEC devices only support toggle mute. Therefore, we send the
// same keycode for all three mute options.
keyCode = KeyEvent.KEYCODE_VOLUME_MUTE;
break;
default:
break;
}
if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
final long ident = Binder.clearCallingIdentity();
try {
switch (keyEventMode) {
case AudioDeviceVolumeManager.ADJUST_MODE_NORMAL:
fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, true);
fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, false);
break;
case AudioDeviceVolumeManager.ADJUST_MODE_START:
fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, true);
break;
case AudioDeviceVolumeManager.ADJUST_MODE_END:
fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, false);
break;
default:
Log.e(TAG, "Invalid keyEventMode " + keyEventMode);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
if (streamTypeAlias == AudioSystem.STREAM_MUSIC
&& (oldIndex != newIndex || isMuteAdjust)) {
maybeSendSystemAudioStatusCommand(isMuteAdjust);
}
}
}
}
sendVolumeUpdate(streamType, oldIndex, newIndex, flags, device);
/// M: Volume sync for cg and hfp @{
if (DEBUG_VOL) {
Log.d(TAG, "adjustStreamVolume oldIndex=" + oldIndex
+ " ,newIndex="+ newIndex
+ " ,streamType=" + streamType
+ " ,device = " + AudioSystem.getOutputDeviceName(device));
}
if (oldIndex != newIndex) {
setRescaleStreamVolume(streamType, device, newIndex);
} /// @}
}
之后调用到streamState.adjustIndex,这个会发送一个intent交给上层处理
public boolean adjustIndex(int deltaIndex, int device, String caller,
boolean hasModifyAudioSettings) {
return setIndex(getIndex(device) + deltaIndex, device, caller,
hasModifyAudioSettings);
}
public boolean setIndex(int index, int device, String caller,
boolean hasModifyAudioSettings) {
boolean changed;
int oldIndex;
final boolean isCurrentDevice;
synchronized (mSettingsLock) {
synchronized (VolumeStreamState.class) {
oldIndex = getIndex(device);
index = getValidIndex(index, hasModifyAudioSettings);
if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
index = mIndexMax;
}
mIndexMap.put(device, index);
changed = oldIndex != index;
// Apply change to all streams using this one as alias if:
// - the index actually changed OR
// - there is no volume index stored for this device on alias stream.
// If changing volume of current device, also change volume of current
// device on aliased stream
isCurrentDevice = (device == getDeviceForStream(mStreamType));
final int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
final VolumeStreamState aliasStreamState = mStreamStates[streamType];
if (streamType != mStreamType &&
mStreamVolumeAlias[streamType] == mStreamType &&
(changed || !aliasStreamState.hasIndexForDevice(device))) {
final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
aliasStreamState.setIndex(scaledIndex, device, caller,
hasModifyAudioSettings);
if (isCurrentDevice) {
aliasStreamState.setIndex(scaledIndex,
getDeviceForStream(streamType), caller,
hasModifyAudioSettings);
}
}
}
// Mirror changes in SPEAKER ringtone volume on SCO when
if (changed && mStreamType == AudioSystem.STREAM_RING
&& device == AudioSystem.DEVICE_OUT_SPEAKER) {
for (int i = 0; i < mIndexMap.size(); i++) {
int otherDevice = mIndexMap.keyAt(i);
if (AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(otherDevice)) {
mIndexMap.put(otherDevice, index);
}
}
}
}
}
if (changed) {
// If associated to volume group, update group cache
updateVolumeGroupIndex(device, /* forceMuteState= */ false);
oldIndex = (oldIndex + 5) / 10;
index = (index + 5) / 10;
// log base stream changes to the event log
if (mStreamVolumeAlias[mStreamType] == mStreamType) {
if (caller == null) {
Log.w(TAG, "No caller for volume_changed event", new Throwable());
}
EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
caller);
}
// fire changed intents for all streams, but only when the device it changed on
// is the current device
if ((index != oldIndex) && isCurrentDevice) {
mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
mStreamVolumeAlias[mStreamType]);
AudioService.sVolumeLogger.enqueue(new VolChangedBroadcastEvent(
mStreamType, mStreamVolumeAlias[mStreamType], index));
//通过这个发送
sendBroadcastToAll(mVolumeChanged, mVolumeChangedOptions);
}
}
return changed;
}
还有一个就是要给底层的,他会通过发送sendMsg来处理,
别问我咋知道的,问就是看的前辈们的
之后我们就先处理上层的吧,毕竟我是上层开发,发送了intent,我们就需要看哪里处理了这个intent ,这里只需要grep下就可以轻松找到VolumeDialogControllerImpl在这个类有添加这个intent的动作
public void init() {
final IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mWorker);
}
那我们肯定要看下他是如何处理这个intent的
if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
final int level = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
final int oldLevel = intent
.getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1);
if (D.BUG) Log.d(TAG, "onReceive VOLUME_CHANGED_ACTION stream=" + stream
+ " level=" + level + " oldLevel=" + oldLevel);
changed = updateStreamLevelW(stream, level);
}
他会调用updateStreamLevelW,来获取是否changed
在这个方法最后,如果changed它会调用
if (changed) {
mCallbacks.onStateChanged(mState);
}
这个找到callback的类C
public void onStateChanged(final State state) {
final long time = System.currentTimeMillis();
final State copy = state.copy();
for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
entry.getValue().post(new Runnable() {
@Override
public void run() {
entry.getKey().onStateChanged(copy);
}
});
}
Events.writeState(time, copy);
}
这个方法是这样实现的
,那我们就要看下callbackmap里面有哪些值,
public void add(Callbacks callback, Handler handler) {
if (callback == null || handler == null) throw new IllegalArgumentException();
mCallbackMap.put(callback, handler);
}
他是在这里添加的,调用这个方法的是
public void addCallback(Callbacks callback, Handler handler) {
mCallbacks.add(callback, handler);
callback.onAccessibilityModeChanged(mShowA11yStream);
}
然后就要看哪些给这个controller添加了callback,我是通过grep找到的
public void init(int windowType, Callback callback) {
initDialog(mActivityManager.getLockTaskModeState());
mController.addCallback(mControllerCallbackH, mHandler);
mController.getState();
mConfigurationController.addCallback(this);
if (mDevicePostureController != null) {
mDevicePostureController.addCallback(mDevicePostureControllerCallback);
}
}
这是哪个类呢,是VolumeDialogImpl这个类
private final VolumeDialogController.Callbacks mControllerCallbackH
= new VolumeDialogController.Callbacks() {
@Override
public void onShowRequested(int reason, boolean keyguardLocked, int lockTaskModeState) {
showH(reason, keyguardLocked, lockTaskModeState);
}
@Override
public void onDismissRequested(int reason) {
dismissH(reason);
}
@Override
public void onScreenOff() {
dismissH(Events.DISMISS_REASON_SCREEN_OFF);
}
@Override
public void onStateChanged(State state) {
onStateChangedH(state);
}
@Override
public void onLayoutDirectionChanged(int layoutDirection) {
mDialogView.setLayoutDirection(layoutDirection);
}
会调用callback的onStateChanged
之后调用onStateChangedH
protected void onStateChangedH(State state) {
if (D.BUG) Log.d(TAG, "onStateChangedH() state: " + state.toString());
if (mState != null && state != null
&& mState.ringerModeInternal != -1
&& mState.ringerModeInternal != state.ringerModeInternal
&& state.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) {
mController.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK));
}
mState = state;
mDynamic.clear();
// add any new dynamic rows
for (int i = 0; i < state.states.size(); i++) {
final int stream = state.states.keyAt(i);
final StreamState ss = state.states.valueAt(i);
if (!ss.dynamic) continue;
mDynamic.put(stream, true);
if (findRow(stream) == null) {
addRow(stream, R.drawable.ic_volume_remote, R.drawable.ic_volume_remote_mute, true,
false, true);
}
}
if (mActiveStream != state.activeStream) {
mPrevActiveStream = mActiveStream;
mActiveStream = state.activeStream;
VolumeRow activeRow = getActiveRow();
updateRowsH(activeRow);
if (mShowing) rescheduleTimeoutH();
}
for (VolumeRow row : mRows) {
updateVolumeRowH(row);
}
updateRingerH();
mWindow.setTitle(composeWindowTitle());
}
音量调节有好几列,所以最后调用了
for (VolumeRow row : mRows) {
updateVolumeRowH(row);
}
之后就该如何显示在systemui上了
分析完上层了,我们看下底层是如何实现的,上文提到他会通过发送消息来处理,我们看下消息是如何处理的
/*package*/ class AudioHandler extends Handler {
AudioHandler() {
super();
}
AudioHandler(Looper looper) {
super(looper);
}
private void setAllVolumes(VolumeStreamState streamState) {
// Apply volume
streamState.applyAllVolumes();
// Apply change to all streams using this one as alias
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (streamType != streamState.mStreamType &&
mStreamVolumeAlias[streamType] == streamState.mStreamType) {
mStreamStates[streamType].applyAllVolumes();
}
}
}
private void persistVolume(VolumeStreamState streamState, int device) {
if (mUseFixedVolume) {
return;
}
if (mIsSingleVolume && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
return;
}
if (streamState.hasValidSettingsName()) {
mSettings.putSystemIntForUser(mContentResolver,
streamState.getSettingNameForDevice(device),
(streamState.getIndex(device) + 5) / 10,
UserHandle.USER_CURRENT);
}
}
private void persistRingerMode(int ringerMode) {
if (mUseFixedVolume) {
return;
}
mSettings.putGlobalInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
}
private void onNotifyVolumeEvent(@NonNull IAudioPolicyCallback apc,
@AudioManager.VolumeAdjustment int direction) {
try {
apc.notifyVolumeAdjust(direction);
} catch(Exception e) {
// nothing we can do about this. Do not log error, too much potential for spam
}
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
//重点看下这个
case MSG_SET_DEVICE_VOLUME:
setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
break;
case MSG_SET_ALL_VOLUMES:
setAllVolumes((VolumeStreamState) msg.obj);
break;
case MSG_PERSIST_VOLUME:
persistVolume((VolumeStreamState) msg.obj, msg.arg1);
break;
case MSG_PERSIST_VOLUME_GROUP:
final VolumeGroupState vgs = (VolumeGroupState) msg.obj;
vgs.persistVolumeGroup(msg.arg1);
break;
case MSG_PERSIST_RINGER_MODE:
// note that the value persisted is the current ringer mode, not the
// value of ringer mode as of the time the request was made to persist
persistRingerMode(getRingerModeInternal());
break;
case MSG_AUDIO_SERVER_DIED:
onAudioServerDied();
break;
case MSG_DISPATCH_AUDIO_SERVER_STATE:
onDispatchAudioServerStateChange(msg.arg1 == 1);
break;
case MSG_UNLOAD_SOUND_EFFECTS:
mSfxHelper.unloadSoundEffects();
break;
case MSG_LOAD_SOUND_EFFECTS:
{
LoadSoundEffectReply reply = (LoadSoundEffectReply) msg.obj;
if (mSystemReady) {
mSfxHelper.loadSoundEffects(reply);
} else {
Log.w(TAG, "[schedule]loadSoundEffects() called before boot complete");
if (reply != null) {
reply.run(false);
}
}
}
break;
case MSG_PLAY_SOUND_EFFECT:
mSfxHelper.playSoundEffect(msg.arg1, msg.arg2);
break;
case MSG_SET_FORCE_USE:
{
final String eventSource = (String) msg.obj;
final int useCase = msg.arg1;
final int config = msg.arg2;
if (useCase == AudioSystem.FOR_MEDIA) {
Log.wtf(TAG, "Invalid force use FOR_MEDIA in AudioService from "
+ eventSource);
break;
}
new MediaMetrics.Item(MediaMetrics.Name.AUDIO_FORCE_USE
+ MediaMetrics.SEPARATOR + AudioSystem.forceUseUsageToString(useCase))
.set(MediaMetrics.Property.EVENT, "setForceUse")
.set(MediaMetrics.Property.FORCE_USE_DUE_TO, eventSource)
.set(MediaMetrics.Property.FORCE_USE_MODE,
AudioSystem.forceUseConfigToString(config))
.record();
sForceUseLogger.enqueue(
new AudioServiceEvents.ForceUseEvent(useCase, config, eventSource));
mAudioSystem.setForceUse(useCase, config);
}
break;
case MSG_DISABLE_AUDIO_FOR_UID:
mPlaybackMonitor.disableAudioForUid( msg.arg1 == 1 /* disable */,
msg.arg2 /* uid */);
mAudioEventWakeLock.release();
break;
case MSG_INIT_STREAMS_VOLUMES:
onInitStreamsAndVolumes();
mAudioEventWakeLock.release();
break;
case MSG_INIT_SPATIALIZER:
onInitSpatializer();
mAudioEventWakeLock.release();
break;
case MSG_INIT_HEADTRACKING_SENSORS:
mSpatializerHelper.onInitSensors();
break;
case MSG_RESET_SPATIALIZER:
mSpatializerHelper.reset(/* featureEnabled */ mHasSpatializerEffect);
break;
case MSG_SYSTEM_READY:
onSystemReady();
break;
case MSG_INDICATE_SYSTEM_READY:
onIndicateSystemReady();
break;
case MSG_ACCESSORY_PLUG_MEDIA_UNMUTE:
onAccessoryPlugMediaUnmute(msg.arg1);
break;
case MSG_UNMUTE_STREAM:
onUnmuteStream(msg.arg1, msg.arg2);
break;
case MSG_DYN_POLICY_MIX_STATE_UPDATE:
onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
break;
case MSG_NOTIFY_VOL_EVENT:
onNotifyVolumeEvent((IAudioPolicyCallback) msg.obj, msg.arg1);
break;
case MSG_ENABLE_SURROUND_FORMATS:
onEnableSurroundFormats((ArrayList<Integer>) msg.obj);
break;
他的方法实现是
/*package*/ void setDeviceVolume(VolumeStreamState streamState, int device) {
synchronized (VolumeStreamState.class) {
sendMsg(mAudioHandler, SoundDoseHelper.MSG_CSD_UPDATE_ATTENUATION, SENDMSG_REPLACE,
device, (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device)
|| AudioSystem.isLeAudioDeviceType(device) ? 1 : 0),
streamState, /*delay=*/0);
// Apply volume
streamState.applyDeviceVolume_syncVSS(device);
// Apply change to all streams using this one as alias
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (streamType != streamState.mStreamType &&
mStreamVolumeAlias[streamType] == streamState.mStreamType) {
// Make sure volume is also maxed out on A2DP device for aliased stream
// that may have a different device selected
int streamDevice = getDeviceForStream(streamType);
if ((device != streamDevice)
&& (isAbsoluteVolumeDevice(device)
|| isA2dpAbsoluteVolumeDevice(device)
|| AudioSystem.isLeAudioDeviceType(device))) {
mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
}
mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
}
}
}
// Post a persist volume msg
sendMsg(mAudioHandler,
MSG_PERSIST_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
PERSIST_DELAY);
}
注意别找错了,可以看下方法参数来找到正确的方法
streamState.applyDeviceVolume_syncVSS(device);这个方法是应用音频的
/*package*/ void applyDeviceVolume_syncVSS(int device) {
int index;
if (isFullyMuted()) {
index = 0;
} else if (isAbsoluteVolumeDevice(device)
|| isA2dpAbsoluteVolumeDevice(device)
|| AudioSystem.isLeAudioDeviceType(device)) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
} /* M: sync ble volume @{ */else if (AudioSystem.DEVICE_OUT_ALL_BLE_SET.contains(device)
&& mBleVcAbsVolSupported) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
} /* @} */else if (isFullVolumeDevice(device)) {
index = (mIndexMax + 5)/10;
} else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
index = (mIndexMax + 5)/10;
} else {
index = (getIndex(device) + 5)/10;
}
setStreamVolumeIndex(index, device);
}
这个就是实现,我们看下最后的设置setStreamVolumeIndex
private void setStreamVolumeIndex(int index, int device) {
// Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
// This allows RX path muting by the audio HAL only when explicitly muted but not when
// index is just set to 0 to repect BT requirements
if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0
&& !isFullyMuted()) {
index = 1;
}
mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, device);
}
我们找到这个系统然后看下这个方法setStreamVolumeIndexAS,我们找到他使用了一个native方法
public static int setStreamVolumeIndexAS(int stream, int index, int device) {
if (DEBUG_VOLUME) {
Log.i(TAG, "setStreamVolumeIndex: " + STREAM_NAMES[stream]
+ " dev=" + Integer.toHexString(device) + " idx=" + index);
}
return setStreamVolumeIndex(stream, index, device);
}
private static native int setStreamVolumeIndex(int stream, int index, int device);