本文来分析 SystemUI 的 VolumeUI 模块,这个模块比较简单,它使用MVP架构完成设计的,以下图java
本文首先会讲解这个架构如何造成的,而后会分析按下 Power 键后处理流程。android
经过 SystemUI之StatusBar建立 可知,VolumeUI 的入口为 VolumeUI#start()
设计模式
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
public void start() {
// ...
// 建立 VolumeDialogComponent 对象
mVolumeComponent = SystemUIFactory.getInstance()
.createVolumeDialogComponent(this, mContext);
mVolumeComponent.setEnableDialogs(enableVolumeUi, enableSafetyWarning);
// ...
// 启动VolumeUI的功能
mVolumeComponent.register();
}
复制代码
VolumeUI 启动的时候会建立一个 VolumeDialogComponent 对象,从名字能够看出,它表明 VolumeUI 组件,经过它能够建立整个MVP。架构
VolumeDialogComponent 对象建立完成后,就会调用它的register()
方法启动 VolumeUI 功能。它其实就是关联 Presenter 层和 Model 层。框架
首先来看看 VolumeDialogComponent 的构造函数ide
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
public VolumeDialogComponent(SystemUI sysui, Context context) {
// ...
// build()以后,会调用createDefault(),而后调用Callback
Dependency.get(ExtensionController.class).newExtension(VolumeDialog.class)
.withPlugin(VolumeDialog.class)
.withDefault(this::createDefault)
.withCallback(dialog -> {
if (mDialog != null) {
mDialog.destroy();
}
mDialog = dialog;
mDialog.init(LayoutParams.TYPE_VOLUME_OVERLAY, mVolumeDialogCallback);
}).build();
// ...省略了Volume Policy功能的代码
}
protected VolumeDialog createDefault() {
VolumeDialogImpl impl = new VolumeDialogImpl(mContext);
impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
impl.setAutomute(true);
impl.setSilentMode(false);
return impl;
}
复制代码
VolumeDialogComponent 经过 createDefault() 建立 VolumeDialogImpl 对象,它表明 View 层,而后经过init() 进行了初始化。函数
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
public VolumeDialogImpl(Context context) {
// VolumeDialogControllerImpl
mController = Dependency.get(VolumeDialogController.class);
}
public void init(int windowType, Callback callback) {
// 建立Dialog并设置参数
initDialog();
// 设置回调
mController.addCallback(mControllerCallbackH, mHandler);
}
复制代码
在 VolumeDialogImpl (View层)的构造函数中,建立了 VolumeDialogControllerImpl 对象,它表明了 Presenter 层。post
在 init() 中,会向 VolumeDialogControllerImpl (Presenter层) 注册一个回调,也就是 View 层与 Presenter 层创建关联,从而能够经过 Presenter 层控制 View 层。ui
如今 View 层已经和 Presenter 层关联了,那么 Model 层呢?还记得前面提到的启动 VolumeUI 功能的代码吗?它调用的是 VolumeDialogComponent#register(),它完成的就是 Model 层与 Presenter 的关联,具体调用的是 VolumeDialogControllerImpl#register()this
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
protected final VC mVolumeController = new VC();
public void register() {
try {
// 向Audio Manager注册了一个Binder,其实就是一个回调
mAudio.setVolumeController(mVolumeController);
} catch (SecurityException e) {
Log.w(TAG, "Unable to set the volume controller", e);
return;
}
}
复制代码
Audio Manager 就是 Model 层,VolumeDialogControllerImpl 向 Audio Manager 注册了一个回调,其实就是 Presenter 层与 Model 层的关联。
如今MVP框架已经造成,如今就来分析下当按下 Power 键后,VolumeUI 是如何显示UI的。
因为 VolumeDialogControllerImpl 向Audio Manager注册了回调,当按下音量键调整了音量后,VolumeDialogControllerImpl 就会收到回调
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
private final class VC extends IVolumeController.Stub {
@Override
public void volumeChanged(int streamType, int flags) throws RemoteException {
// 调用 onVolumeChangedW()
mWorker.obtainMessage(W.VOLUME_CHANGED, streamType, flags).sendToTarget();
}
}
boolean onVolumeChangedW(int stream, int flags) {
final boolean showUI = shouldShowUI(flags);
final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
final boolean showSilentHint = (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0;
boolean changed = false;
if (showUI) {
changed |= updateActiveStreamW(stream);
}
int lastAudibleStreamVolume = getAudioManagerStreamVolume(stream);
changed |= updateStreamLevelW(stream, lastAudibleStreamVolume);
changed |= checkRoutedToBluetoothW(showUI ? AudioManager.STREAM_MUSIC : stream);
if (changed) {
mCallbacks.onStateChanged(mState);
}
if (showUI) {
mCallbacks.onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
}
if (showVibrateHint) {
mCallbacks.onShowVibrateHint();
}
if (showSilentHint) {
mCallbacks.onShowSilentHint();
}
return changed;
}
复制代码
根据 flags 决定要执行哪一个回调,若是要显示UI,就会回调 onShowRequested() , 而这个回调固然是由 View 层实现的。
// frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
private final VolumeDialogController.Callbacks mControllerCallbackH
= new VolumeDialogController.Callbacks() {
@Override
public void onShowRequested(int reason) {
showH(reason);
}
}
private void showH(int reason) {
// 显示Dialog
mDialog.show();
}
复制代码
View 层就完成了一个 Dialog 的显示。
VolumeUI 固然不仅这么只功能,可是只要你懂得了这个 MVP 的设计,分析其它功能就不是什么难事。
另外呢,我在分析代码的时候发现 VolumeDialogComponent 其实能够省略的,它除了建立 View 层外,其实还控制着 Volume Policy 的功能,可是这个功能是由 SettingsProvider 控制的,而最终实现控制 Volume Policy 功能的是 Presenter 层。根据设计模式中的单一职责的原则,Volume Policy 的代码能够彻底由 Presenter 实现,从而就能够省略 VolumeDialogComponent 这一环,固然这只是我我的想法。