从类的名字上看,这个类应该是一个音量的SeekBar。
1、对于SeekBar,需要着重关注的就是其三个回调函数。
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
if (fromTouch) {
postSetVolume(progress);
}
if (mCallback != null) {
mCallback.onProgressChanged(seekBar, progress, fromTouch);
}
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onStopTrackingTouch(SeekBar seekBar) {
postStartSample();
}
2、对于音量,这个类注册了广播监听,Action为:
AudioManager.VOLUME_CHANGED_ACTION
AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION
NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED
AudioManager.STREAM_DEVICES_CHANGED_ACTION
3、同时注册了一个关于StreamType音量变化的监听
mVolumeObserver = new Observer(mHandler);
mContext.getContentResolver().registerContentObserver(
System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
false, mVolumeObserver);
知道了以上三个信息,现在来分析,当我们滑动SeekBar的时候会发生什么情况。
从onProgressChanged回调可以知道,滑动SeekBar的过程中会不断地去设置音量。
从onStopTrackingTouch回调可以知道,滑动完成之后,会播放sample。
注:这里可以看到,如果我们第一次滑动完毕,其实sample正在播放,我们在播放过程中滑动SeekBar的滑,此时sample播放的声音会随着我们的滑动而改变。
因为我们注册了AudioManager.VOLUME_CHANGED_ACTION,所以在滑动的过程中,由于我们设置了音量,那么我们将会收到这个广播,于是收到该广播我们又会去更新SeekBar。
对于两个成员变量的作用:
mAffectedByRingerMode = mAudioManager.isStreamAffectedByRingerMode(mStreamType);
mNotificationOrRing = isNotificationOrRing(mStreamType);
mAffectedByRingerMode的作用比较明显,就是判断StreamType是否受响铃模式影响。
mNotificationOrRing从变量名可以看出,是判断Stream是否属于Notification或者Ring其中一种的一个标识位。
这个变量的具体作用在于,当我们收到音量变化的广播的时候,我们需要去判断,发生音量变化的StreamType和我们这个类所控制的StreamType是否一样,如果一样,我们才会去更新SeekBar。也就是说,当Ring和Notification的音量会同时变化,当我们调整Ring的音量的时候,Notificaion的音量也会发生改变,要使得Notification和Ring互相不影响,只需要把streamMatch = streamType == mStreamType就可以了,也就是说,当跟我当前表示的StreamType发生音量变化的时候,我才去更新SeekBar.
private void updateVolumeSlider(int streamType, int streamValue) {
final boolean streamMatch = mNotificationOrRing ? isNotificationOrRing(streamType)
: (streamType == mStreamType);
if (mSeekBar != null && streamMatch && streamValue != -1) {
final boolean muted = mAudioManager.isStreamMute(mStreamType)
|| streamValue == 0;
mUiHandler.postUpdateSlider(streamValue, mLastAudibleStreamVolume, muted);
}
}
相关类图:我们知道SeekBarVolumizer是一个可以播放Uri并且控制音量的SeekBar。而VolumeSeekBarPrefernce则是一个可以播放Uri并且控制音量的SeekBarPreference。所以这里VolumeSeekBarPreference继承SeekBarPreference代表一种特别的SeekBarPreference,而其“可以播放Uri并且控制音量”这个功能则通过 "has-a" SeekBarVolumizer来实现。
Note for myself:对于Notification图标的修改,需要RingVolumePreferenceController.java中的updatePreferenceIcon(),同时需要修改SeekBarVolumizer.java中收到RingerMode变化广播的时候,更新图标。
else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
if (mNotificationOrRing) {