標籤:framework 音量大小 系統音量條顯示 源碼解析
上篇裡面提到了聲音調整的兩種操作,接下來就要具體分析下音量大小的大概步驟,分別涉及到兩部分:
android\frameworks\base\media\java\android\media\AudioService.java
android\frameworks\base\media\java\android\media\IAudioService.aidl
其中adjustStreamVolume(int streamType, int direction, int flags)函數的聲明是在AudioService.aidl中,而函數的實現是在AudioService.java中。
下面具體可以看源碼:
/** @see AudioManager#adjustStreamVolume(int, int, int) */ public void adjustStreamVolume(int streamType, int direction, int flags) { if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction); ensureValidDirection(direction); ensureValidStreamType(streamType); // 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); // get last audible index if stream is muted, current index otherwise final int aliasIndex = streamState.getIndex(device, (streamState.muteCount() != 0) /* lastAudible */); boolean adjustVolume = true; // convert one UI step (+/-1) into a number of internal units on the stream alias int step = rescaleIndex(10, streamType, streamTypeAlias); // If either the client forces allowing ringer modes for this adjustment, // or the stream type is one that is affected by ringer modes if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || (streamTypeAlias == getMasterStreamType())) { int ringerMode = getRingerMode(); // do not vibrate if already in vibrate mode if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { flags &= ~AudioManager.FLAG_VIBRATE; } // Check if the ringer mode changes with this volume adjustment. If // it does, it will handle adjusting the volume, so we won't below adjustVolume = checkForRingerModeChange(aliasIndex, direction, step); if ((streamTypeAlias == getMasterStreamType()) && (mRingerMode == AudioManager.RINGER_MODE_SILENT)) { streamState.setLastAudibleIndex(0, device); } } // If stream is muted, adjust last audible index only int index; final int oldIndex = mStreamStates[streamType].getIndex(device, (mStreamStates[streamType].muteCount() != 0) /* lastAudible */); if (streamState.muteCount() != 0) { if (adjustVolume) { // Post a persist volume msg // no need to persist volume on all streams sharing the same alias streamState.adjustLastAudibleIndex(direction * step, device); sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, SENDMSG_QUEUE, PERSIST_LAST_AUDIBLE, device, streamState, PERSIST_DELAY); } index = mStreamStates[streamType].getIndex(device, true /* lastAudible */); } else { if (adjustVolume && streamState.adjustIndex(direction * step, device)) { // Post message to set system volume (it in turn will post a message // to persist). Do not change volume if stream is muted. sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE, device, 0, streamState, 0); } index = mStreamStates[streamType].getIndex(device, false /* lastAudible */); } sendVolumeUpdate(streamType, oldIndex, index, flags); } 解析上面函數可知,函數最開始會有一個對於前兩個參數有效性的檢測,貼出具體的檢測代碼:
private void ensureValidDirection(int direction) { if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { throw new IllegalArgumentException("Bad direction " + direction); } } private void ensureValidSteps(int steps) { if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) { throw new IllegalArgumentException("Bad volume adjust steps " + steps); } } private void ensureValidStreamType(int streamType) { if (streamType < 0 || streamType >= mStreamStates.length) { throw new IllegalArgumentException("Bad stream type " + streamType); } } 繼續跟進源碼,可以看到
int step = rescaleIndex(10, streamType, streamTypeAlias);
此參數為調整步進數值的
再下面的判斷條件if (streamState.muteCount() != 0)為判斷是否是從靜音狀態發起的音量調整以便進行不同的操作。
在函數的最後
sendVolumeUpdate(streamType, oldIndex, index, flags);
此函數則是用於更新系統音量條的顯示
// UI update and Broadcast Intent private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) { if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) { streamType = AudioSystem.STREAM_NOTIFICATION; } mVolumePanel.postVolumeChanged(streamType, flags); oldIndex = (oldIndex + 5) / 10; index = (index + 5) / 10; Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION); if (streamType == AudioManager.STREAM_VOICE_CALL) streamType = AudioManager.STREAM_MUSIC; intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index); intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex); mContext.sendBroadcast(intent); } 可以看到源碼中調用了
\android\frameworks\base\core\java\android\view\VolumePanel.java
其中VolumePanel.java則用於顯示系統音量條的顯示,其中具體如何顯示可以參考代碼。同時此部分代碼中會涉及到系統所有音量相關的表徵圖顯示,需要進行修改美化等操作的可以具體找到資源檔進行修改。
具體路徑可以在
android\frameworks\base\core\res\res
另一種設定音量的方法setStreamVolume(int streamType, int index, int flags)也是同樣的可以在上述代碼中找到,關於音量調整的部分解析到此基本結束,暫時可以明白的就上述的流程了。
Android FrameWork音頻管理AudioManager的一點解析(續一)