SystemUI启动时通过startServicesIfNeeded(Class<?>[] services) 方法,调用所有继承SystemUI类的service的start()方法,VolumeUI也是其中之一。
public void start() {
//可以通过config配置是否启用volume ui
mEnabled = mContext.getResources().getBoolean(R.bool.enable_volume_ui);
if (!mEnabled) return;
//初始化VolumeDialogComponent元件
mVolumeComponent = new VolumeDialogComponent(this, mContext, null);
putComponent(VolumeComponent.class, getVolumeComponent());
//注册controller
setDefaultVolumeController();
}
1. VolumeDialogComponent
start()方法会初始化一个VolumeDialogComponent元件,后面其实注册controller也是由该元件来操作的,所以先看下它的构造函数:
public VolumeDialogComponent(SystemUI sysui, Context context, Handler handler) {
mSysui = sysui;
mContext = context;
//通过Dependency实例化VolumeDialogController接口
mController = (VolumeDialogControllerImpl) Dependency.get(VolumeDialogController.class);
mController.setUserActivityListener(this);
// Allow plugins to reference the VolumeDialogController.
//允许插件引用VolumeDialogController。
Dependency.get(PluginDependencyProvider.class)
.allowPluginDependency(VolumeDialogController.class);
//初始化一个扩展工具
mExtension = Dependency.get(ExtensionController.class).newExtension(VolumeDialog.class)
.withPlugin(VolumeDialog.class)
//重写了Supplier<T>的get()方法
//createDefault()方法返回了一个VolumeDialogImpl实例化对象
.withDefault(this::createDefault)
//重写了Consumer<T>的accept()方法
//上面两个重写的方法均会在configuration change时通过mExtension的reload()方法里调用
.withCallback(dialog -> {
if (mDialog != null) {
mDialog.destroy();
}
mDialog = dialog;
mDialog.init(LayoutParams.TYPE_VOLUME_OVERLAY, mVolumeDialogCallback);
}).build();
applyConfiguration();
//注册Observer监听,并回调自己的onTuningChanged(),更新mVolumePolicy
Dependency.get(TunerService.class).addTunable(this, VOLUME_DOWN_SILENT, VOLUME_UP_SILENT,
VOLUME_SILENT_DO_NOT_DISTURB);
}
从以上代码可以看到,实例化mVolumeComponent 的时候,相当于进行了一系列插件的初始化。初始化mExtension的时候通过withDefault和withCallback传入的Supplier和Consumer对象,会在onConfigurationChanged()的时候,通过自身的reload()方法,重新初始化dialog的一些配置。
2. VolumeDialogControllerImpl
前面说到过注册controller也是由VolumeDialogComponent元件来实现的,那么接下来再看下setDefaultVolumeController()。
private void setDefaultVolumeController() {
DndTile.setVisible(mContext, true);
if (LOGD) Log.d(TAG, "Registering default volume controller");
getVolumeComponent().register();
}
先把勿扰模式Tile设置可见,随后在VolumeComponent的register()里面,继续调用VolumeDialogControllerImpl的register():
public void register() {
setVolumeController();
setVolumePolicy(mVolumePolicy);
showDndTile(mShowDndTile);
try {
mMediaSessions.init();
} catch (SecurityException e) {
Log.w(TAG, "No access to media sessions", e);
}
}
- setVolumeController():
mVolumeController是IVolumeController接口的实例,里面实现了一系列AudioService的回调函数。这个方法是主动去向AudioService注册自己的VolumeController,后续音量调节也是通过这个VolumeController来完成UI更新的。
mAudio.setVolumeController(mVolumeController);
- setVolumePolicy():
通过AudioManager更新VolumePolicy - showDndTile():
设置勿扰模式DndTile可见 - mMediaSessions.init():
初始化多媒体播放框架
3. 小结
VolumeUI的启动流程基本是各种插件、工具和controller的初始化过程,后续framework处理到音量变化的事件时会通过AudioService回调这些controller来更新音量UI,即SystemUI的VolumeDialog只在有音量相关改变的时候才会显示。