在Android平台上,音量键,主页键(home),都是全局按键,但是主页键是个例外不能被应用所捕获。下面分析一下音量按键的流程,主要从framework层处理开始,至于
EventHub 从驱动的/dev/input/event0获取按键信息到上抛属于Android input 系统方面的流程,下面基于android KK平台分析。
系统层接收音量按键
ViewRootImpl.processKeyEvent 处理Activity 上面收到的按键
从中可以看到mView.dispatchKeyEvent(event),完成将按键发送给Activity处理,由于每个Activity都是view的子类,所有这些按键将dispatchKeyEvent传递给onKeyDown
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (mInputEventConsistencyVerifier != null) {
- mInputEventConsistencyVerifier.onKeyEvent(event, 0);
- }
-
-
-
- ListenerInfo li = mListenerInfo;
- if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
- && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
- return true;
- }
-
- if (event.dispatch(this, mAttachInfo != null
- ? mAttachInfo.mKeyDispatchState : null, this)) {
- return true;
- }
-
- if (mInputEventConsistencyVerifier != null) {
- mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
- }
- return false;
- }
由上面View.dispatchKeyEvent方法可知,通过event.dispatch进一步分发
- public final boolean dispatch(Callback receiver, DispatcherState state,
- Object target) {
- switch (mAction) {
- case ACTION_DOWN: {
- mFlags &= ~FLAG_START_TRACKING;
- if (DEBUG) Log.v(TAG, "Key down to " + target + " in " + state
- + ": " + this);
- boolean res = receiver.onKeyDown(mKeyCode, this);
- if (state != null) {
- if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) {
- if (DEBUG) Log.v(TAG, " Start tracking!");
- state.startTracking(this, target);
- } else if (isLongPress() && state.isTracking(this)) {
- try {
- if (receiver.onKeyLongPress(mKeyCode, this)) {
- if (DEBUG) Log.v(TAG, " Clear from long press!");
- state.performedLongPress(this);
- res = true;
- }
- } catch (AbstractMethodError e) {
- }
- }
- }
- return res;
- }
- case ACTION_UP:
- if (DEBUG) Log.v(TAG, "Key up to " + target + " in " + state
- + ": " + this);
- if (state != null) {
- state.handleUpEvent(this);
- }
- return receiver.onKeyUp(mKeyCode, this);
- case ACTION_MULTIPLE:
- final int count = mRepeatCount;
- final int code = mKeyCode;
- if (receiver.onKeyMultiple(code, count, this)) {
- return true;
- }
- if (code != KeyEvent.KEYCODE_UNKNOWN) {
- mAction = ACTION_DOWN;
- mRepeatCount = 0;
- boolean handled = receiver.onKeyDown(code, this);
- if (handled) {
- mAction = ACTION_UP;
- receiver.onKeyUp(code, this);
- }
- mAction = ACTION_MULTIPLE;
- mRepeatCount = count;
- return handled;
- }
- return false;
- }
- return false;
- }
KeyEvent.dispatch通过receiver.onKeyDown将最终的按键消息发送给当前的Activity,而receiver即为KeyEvent.Callback的实现类(View的子类等等),至此如果上面上传
应用处理完了就会返回,如果没有处理就会流向mFallbackEventHandler.dispatchKeyEvent(event),其实mFallbackEventHandler就是PhoneFallbackEventHandler,接着看
PhoneFallbackEventHandler.dispatchKeyEvent的处理流程
- public boolean dispatchKeyEvent(KeyEvent event) {
-
- final int action = event.getAction();
- final int keyCode = event.getKeyCode();
-
- if (action == KeyEvent.ACTION_DOWN) {
- return onKeyDown(keyCode, event);
- } else {
- return onKeyUp(keyCode, event);
- }
- }
进入onKeyDown
- boolean onKeyDown(int keyCode, KeyEvent event) {
-
-
-
-
- final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
-
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- case KeyEvent.KEYCODE_VOLUME_MUTE: {
- getAudioManager().handleKeyDown(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
- return true;
- }
-
- ......
-
- }
- return false;
- }
AudioManager处理音量
从上面分析知道PhoneFallbackEventHandler处理一些Activity没有处理的全局按键,音量键接着进入handleKeyDown处理流程
- public void handleKeyDown(KeyEvent event, int stream) {
- int keyCode = event.getKeyCode();
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
-
-
-
-
- int flags = FLAG_SHOW_UI | FLAG_VIBRATE;
-
- if (mUseMasterVolume) {
- adjustMasterVolume(
- keyCode == KeyEvent.KEYCODE_VOLUME_UP
- ? ADJUST_RAISE
- : ADJUST_LOWER,
- flags);
- } else {
- adjustSuggestedStreamVolume(
- keyCode == KeyEvent.KEYCODE_VOLUME_UP
- ? ADJUST_RAISE
- : ADJUST_LOWER,
- stream,
- flags);
- }
- break;
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- if (event.getRepeatCount() == 0) {
- if (mUseMasterVolume) {
- setMasterMute(!isMasterMute());
- } else {
-
- }
- }
- break;
- }
- }
mUseMasterVolume ( =
com.android.internal.R.bool.config_useMasterVolume),配置文件config.xml中该值为0,那么将进入adjustSuggestedStreamVolume,
再接着就进入adjustSuggestedStreamVolume,如果当前的streamType为STREAM_REMOTE_MUSIC,则走mMediaFocusControl.adjustRemoteVolume,其它类型
走音量的通用设置流程adjustStreamVolume
AudioService音量控制流程
从adjustSuggestedStreamVolume 过渡到adjustStreamVolume,进入音量设置的主要流程,主要对流类型,设备,声音设备状态,步进大小进行判断处理,另外蓝牙设
备音量和主设备音量进行了控制,最后通过mVolumePanel刷新界面音量显示,并且广播通过上层应用。
- public void adjustStreamVolume(int streamType, int direction, int flags,
- String callingPackage) {
- if (mUseFixedVolume) {
- return;
- }
- if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction);
-
- ensureValidDirection(direction);
- ensureValidStreamType(streamType);
-
-
-
-
- int streamTypeAlias = mStreamVolumeAlias[streamType];
- VolumeStreamState streamState = mStreamStates[streamTypeAlias];
-
- final int device = getDeviceForStream(streamTypeAlias);
-
- int aliasIndex = streamState.getIndex(device);
- boolean adjustVolume = true;
- int step;
-
-
-
- if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
- (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
- return;
- }
-
- if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return;
- }
-
-
- synchronized (mSafeMediaVolumeState) {
- mPendingVolumeCommand = null;
- }
-
- flags &= ~AudioManager.FLAG_FIXED_VOLUME;
- if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
- ((device & mFixedVolumeDevices) != 0)) {
- flags |= AudioManager.FLAG_FIXED_VOLUME;
-
-
-
-
- if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
- (device & mSafeMediaVolumeDevices) != 0) {
- step = mSafeMediaVolumeIndex;
- } else {
- step = streamState.getMaxIndex();
- }
- if (aliasIndex != 0) {
- aliasIndex = step;
- }
- } else {
-
- step = rescaleIndex(10, streamType, streamTypeAlias);
- }
-
-
-
- if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
- (streamTypeAlias == getMasterStreamType())) {
- int ringerMode = getRingerMode();
-
- if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
- flags &= ~AudioManager.FLAG_VIBRATE;
- }
-
-
- adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
- }
-
- int oldIndex = mStreamStates[streamType].getIndex(device);
-
- if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
-
-
- if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
- (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
- (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
- synchronized (mA2dpAvrcpLock) {
- if (mA2dp != null && mAvrcpAbsVolSupported) {
- mA2dp.adjustAvrcpAbsoluteVolume(direction);
- }
- }
- }
-
- if ((direction == AudioManager.ADJUST_RAISE) &&
- !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
- Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
- mVolumePanel.postDisplaySafeVolumeWarning(flags);
- } else if (streamState.adjustIndex(direction * step, device)) {
-
-
- sendMsg(mAudioHandler,
- MSG_SET_DEVICE_VOLUME,
- SENDMSG_QUEUE,
- device,
- 0,
- streamState,
- 0);
- }
- }
- int index = mStreamStates[streamType].getIndex(device);
- sendVolumeUpdate(streamType, oldIndex, index, flags);
- }
蓝牙音量的控制
有上可知,如果当前连接了蓝牙也将对音量进行控制,mA2dp.adjustAvrcpAbsoluteVolume,以后分析。
音频处理设置
音频处理由AudioHandler来进行,adjustStreamVolume做完相关处理后,通过sendMsg发送音量变化消息MSG_SET_DEVICE_VOLUME进入
AudioHandler.handleMessage调用AudioHandler.setDeviceVolume
- private void setDeviceVolume(VolumeStreamState streamState, int device) {
-
-
- streamState.applyDeviceVolume(device);
-
-
- int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
- if (streamType != streamState.mStreamType &&
- mStreamVolumeAlias[streamType] == streamState.mStreamType) {
-
-
- int streamDevice = getDeviceForStream(streamType);
- if ((device != streamDevice) && mAvrcpAbsVolSupported &&
- ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
- mStreamStates[streamType].applyDeviceVolume(device);
- }
- mStreamStates[streamType].applyDeviceVolume(streamDevice);
- }
- }
-
-
- sendMsg(mAudioHandler,
- MSG_PERSIST_VOLUME,
- SENDMSG_QUEUE,
- device,
- 0,
- streamState,
- PERSIST_DELAY);
-
- }
VolumeStreamState.applyDeviceVolume设置设备音量
- public void applyDeviceVolume(int device) {
- int index;
- if (isMuted()) {
- index = 0;
- } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
- mAvrcpAbsVolSupported) {
- index = (mIndexMax + 5)/10;
- } else {
- index = (getIndex(device) + 5)/10;
- }
- AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
- }
接着发送MSG_PERSIST_VOLUME消息通过handleMessage进入persistVolume,最终调用System.putIntForUser将用户设置的内容设置到Settings.system中。
AudioSystem处理
applyDeviceVolume处理完,AudioSystem就开始接着往下设置setStreamVolumeIndex,该接口也即android_media_AudioSystem_setStreamVolumeIndex
在frameworks\base\core\jni\android_media_AudioSystem.cpp中有定义。
- static int android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
- jobject thiz,
- jint stream,
- jint index,
- jint device)
- {
- return check_AudioSystem_Command(
- AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
- index,
- (audio_devices_t)device));
- }
进入AudioSystem.cpp中setStreamVolumeIndex
- status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,
- int index,
- audio_devices_t device)
- {
- const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
- return aps->setStreamVolumeIndex(stream, index, device);
- }
获取去音频策略服务(AudioPolicyService.cpp),进行设置
- status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream,
- int index,
- audio_devices_t device)
- {
- if (mpAudioPolicy == NULL) {
- return NO_INIT;
- }
- if (!settingsAllowed()) {
- return PERMISSION_DENIED;
- }
- if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
- return BAD_VALUE;
- }
- Mutex::Autolock _l(mLock);
- if (mpAudioPolicy->set_stream_volume_index_for_device) {
- return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy,
- stream,
- index,
- device);
- } else {
- return mpAudioPolicy->set_stream_volume_index(mpAudioPolicy, stream, index);
- }
- }
AudioPolicyService为音频策略系统服务在main_mediaserver.cpp中注册,AudioFlinger也在其中注册。
mpAudioPolicy作为audio_policy类型的对象,其方法主要在Hardware层实现,可以查看相关文件audio_policy_hal.cpp 或者 audio_policy.c,也就是在库
audio.a2dp.xxx.so ,audio.btmic.xxx.so,audio.primary.xxxx 库中实现.
AudioPolicyService.cpp构造函数中就有hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);打印HAL层的库。
通知上层应用
sendVolumeUpdate在音量设置完成之后,完成画面刷新,并广播通知上层应用。
扩展连接:http://www.2cto.com/kf/201409/337102.html
更多音频策略相关流程后续分析。