前面几篇文章我们具体分析了Android12系统原生的StatusBar和CarStatusBar的启动流程以及视图构建流程,本篇文章我们来自定义实现状态栏和导航栏视图。
1、修改CarSystemUI项目中的config.xml配置文件的config_systemUIServiceComponentsInclude字段,让CarSystemUI模块默认不是启动CarSystemBar,而是启动我们新建的LPCarSystemBar。
packages/apps/Car/SystemUI/res/values/config.xml
<string-array name="config_systemUIServiceComponentsInclude" translatable="false">
<!--<item>com.android.systemui.car.systembar.CarSystemBar</item>-->
<item>com.lp.systemui.LPCarSystemBar</item>
<item>com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier</item>
<item>com.android.systemui.car.window.SystemUIOverlayWindowManager</item>
<item>com.android.systemui.car.toast.CarToastUI</item>
<item>com.android.systemui.car.volume.VolumeUI</item>
<item>com.android.systemui.car.cluster.ClusterDisplayController</item>
</string-array>
2、在CarSystemUI项目里面新建一个类,并在该类中构建状态栏和导航栏视图。
package/app/Car/SystemUI/src/com/lp/systemui/LPCarSystemBar.java
public class LPCarSystemBar extends SystemUI{
private final WindowManager mWindowManager;
//顶部状态栏
private StatusBarViewHelper mStatusBarViewHelper;
//底部Dock栏
private DockBarViewHelper mDockBarViewHelper;
//添加dagger2注解
@Inject
public LPCarSystemBar(Context context
, WindowManager windowManager
, StatusBarViewHelper statusBarViewHelper
, DockBarViewHelper dockBarViewHelper
) {
super(context);
mWindowManager = windowManager;
//状态栏
mStatusBarViewHelper = statusBarViewHelper;
//底部栏
mDockBarViewHelper = dockBarViewHelper;
}
@Override
public void start() {
createSystemBar();
}
private void createSystemBar() {
createTopCarSystemBar();//创建顶部栏
createBottomCarSystemBar();//创建底部栏
}
}
3、在修改完config.xml配置之后,SystemUIApplication的startServicesIfNeeded方法便会调用ContextComponentResolver的resolveSystemUI方法,尝试创建LPCarSystemBar对象实例,并调用该对象的start方法。
frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
public class SystemUIApplication extends Application implements
SystemUIAppComponentFactory.ContextInitializer {
private ContextComponentHelper mComponentHelper;
private void startServicesIfNeeded(String metricsPrefix, String[] services) {
...代码省略...
final int N = services.length;
for (int i = 0; i < N; i++) {
String clsName = services[i];//具体SystemUI组件类的完整路径
...代码省略...
SystemUI obj = mComponentHelper.resolveSystemUI(clsName);//ComponentHelper的resolveSystemUI方法可以通过类名拿到具体的SystemUI实例对象
...代码省略...
mServices[i].start();
...代码省略...
}
}
}
为了让ContextComponentHelper可以成功获得LPCarSystemBar对象实例,我们还需修改Dagger2组件中的代码。
4、修改CarSystemUIBinder类代码,为Dagger2框架提供LPCarSystemBar对象实例。
packages/apps/Car/SystemUI/src/com/android/systemui/CarSystemUIBinder.java
@Module(includes = {RecentsModule.class, StatusBarModule.class, NotificationsModule.class,
KeyguardModule.class, OverlayWindowModule.class, CarNotificationModule.class,
QuickControlsEntryPointsModule.class})
public abstract class CarSystemUIBinder {
// /** Inject Car Navigation Bar. */
// @Binds
// @IntoMap
// @ClassKey(CarSystemBar.class)
// public abstract SystemUI bindCarSystemBar(CarSystemBar sysui);
/** Inject LPCar Navigation Bar. */
@Binds
@IntoMap
@ClassKey(LPCarSystemBar.class)
public abstract SystemUI bindLPCarSystemBar(LPCarSystemBar sysui);
}
1、新建一个状态栏视图管理类StatusBarViewHelper。
packages/apps/Car/SystemUI/src/com/lp/systemui/StatusBarViewHelper.java
public class StatusBarViewHelper{
protected Context mContext;
protected View mRootView;
//为构造方法添加@Inject注解
@Inject
public StatusBarViewHelper(Context mContext) {
this.mContext = mContext;
mRootView = LayoutInflater.from(mContext).inflate(R.layout.lp_layout_status_bar_view, null, false);
}
public View getRootView() {
return mRootView;
}
public void initView() {
//初始化视图内容
}
}
自定义状态栏相关的交互逻辑基本都可以写在StatusBarViewHelper这个类里面,lp_layout_status_bar_view.xml则是自定义状态栏所对应的布局文件,通过修改StatusBarViewHelper和lp_layout_status_bar_view.xml的布局内容,基本就能实现自定义状态栏视图的功能了。另外还需为StatusBarViewHelper的构造方法添加@Inject注解,这样Dagger2在构建LPCarSystemBar对象实例的时候,会通过构造方法为mStatusBarViewHelper属性赋值。
2、LPCarSystemBar和构建状态栏视图相关的代码如下所示。
public class LPCarSystemBar extends SystemUI{
private final WindowManager mWindowManager;
//顶部状态栏
private StatusBarViewHelper mStatusBarViewHelper;
private boolean mIsAddStatusBarViewToWindow = false;
//添加dagger2注解
@Inject
public LPCarSystemBar(Context context
, WindowManager windowManager
, StatusBarViewHelper statusBarViewHelper
, DockBarViewHelper dockBarViewHelper
) {
super(context);
mWindowManager = windowManager;
//状态栏
mStatusBarViewHelper = statusBarViewHelper;
...代码省略...
}
@Override
public void start() {
createSystemBar();
}
private void createSystemBar() {
createTopCarSystemBar();
...代码省略...
}
private void createTopCarSystemBar() {
//初始化顶部栏视图内容
mStatusBarViewHelper.initView();
//把顶部栏添加到窗口上
addTopCarSystemBarToWindow();
}
/**
* 把顶部栏添加到窗口上
*/
private void addTopCarSystemBarToWindow() {
if (mIsAddStatusBarViewToWindow) {
return;
}
if (mStatusBarViewHelper != null) {
//将顶部栏添加到Window中
int statusBarHeight = 88;
WindowManager.LayoutParams lpTopSystemBar = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight,
WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
// WindowManager.LayoutParams.TYPE_STATUS_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
// PixelFormat.TRANSLUCENT);//半透明
PixelFormat.TRANSPARENT);//全透明
lpTopSystemBar.setTitle("LPCarSystemBar");
lpTopSystemBar.providesInsetsTypes = new int[]{InsetsState.ITYPE_STATUS_BAR, InsetsState.ITYPE_TOP_MANDATORY_GESTURES};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
lpTopSystemBar.setFitInsetsTypes(0);
}
lpTopSystemBar.windowAnimations = 0;
lpTopSystemBar.gravity = Gravity.TOP;
mWindowManager.addView(mStatusBarViewHelper.getRootView(), lpTopSystemBar);
mIsAddStatusBarViewToWindow = true;
}
}
}
在通过构造方法拿到StatusBarViewHelper对象并赋值给mStatusBarViewHelper之后,LPCarSystemBar的start方法会被调用,我们在该方法中调用createSystemBar方法,该方法会调用createTopCarSystemBar方法来创建状态栏视图,并调用addTopCarSystemBarToWindow方法将构建完成的视图添加到窗口中。
1、新建一个底部栏视图管理类DockBarViewHelper。
packages/apps/Car/SystemUI/src/com/lp/systemui/DockBarViewHelper.java
public class DockBarViewHelper{
protected Context mContext;
protected View mRootView;
//为构造方法添加@Inject注解
@Inject
public DockBarViewHelper(Context mContext) {
this.mContext = mContext;
mRootView = LayoutInflater.from(mContext).inflate(R.layout.lp_layout_dock_bar_view, null, false);
}
public View getRootView() {
return mRootView;
}
public void initView() {
//初始化视图内容
}
}
自定义底部栏相关的交互逻辑基本都可以写在DockBarViewHelper这个类里面,lp_layout_dock_bar_view.xml则是自定义底部栏所对应的布局文件,通过修改StatusBarViewHelper和lp_layout_status_bar_view.xml的布局内容,基本就能实现自定义状态栏视图的功能了。另外还需为DockBarViewHelper的构造方法添加@Inject注解,这样Dagger2在构建LPCarSystemBar对象实例的时候,会通过构造方法为mDockBarViewHelper属性赋值。
2、LPCarSystemBar和构建底部栏视图相关的代码如下所示。
public class LPCarSystemBar extends SystemUI{
private final WindowManager mWindowManager;
//底部Dock栏
private DockBarViewHelper mDockBarViewHelper;
private boolean mIsAddDockBarViewToWindow = false;
//添加dagger2注解
@Inject
public LPCarSystemBar(Context context
, WindowManager windowManager
, StatusBarViewHelper statusBarViewHelper
, DockBarViewHelper dockBarViewHelper
) {
super(context);
mWindowManager = windowManager;
...代码省略...
//底部栏
mDockBarViewHelper = dockBarViewHelper;
}
@Override
public void start() {
createSystemBar();
}
private void createSystemBar() {
...代码省略...
createBottomCarSystemBar();
}
/**
* 创建底部栏
*/
private void createBottomCarSystemBar() {
//添加底部栏视图内容
mDockBarViewHelper.initView();
//把底部栏添加到窗口上
addBottomCarSystemBarToWindow();
}
/**
* 把底部栏添加到窗口上
*/
private void addBottomCarSystemBarToWindow() {
if (mIsAddDockBarViewToWindow) {
return;
}
if (mDockBarViewHelper != null) {
//将底部栏添加到Window中
int navigationBarHeight = 112;//底部栏高度
WindowManager.LayoutParams lpBottomSystemBar = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, navigationBarHeight,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
// WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
// PixelFormat.TRANSLUCENT);//半透明
PixelFormat.TRANSPARENT);//全透明
lpBottomSystemBar.setTitle("LPBottomCarSystemBar");
lpBottomSystemBar.providesInsetsTypes = new int[]{InsetsState.ITYPE_NAVIGATION_BAR, InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
lpBottomSystemBar.setFitInsetsTypes(0);
}
lpBottomSystemBar.windowAnimations = 0;
lpBottomSystemBar.gravity = Gravity.BOTTOM;
mWindowManager.addView(mDockBarViewHelper.getRootView(), lpBottomSystemBar);
mIsAddDockBarViewToWindow = true;
}
}
}
在通过构造方法拿到StatusBarViewHelper对象并赋值给mStatusBarViewHelper之后,LPCarSystemBar的start方法会被调用,我们在该方法中调用createSystemBar方法,该方法会调用createBottomCarSystemBar方法来创建状态栏视图,并调用addBottomCarSystemBarToWindow方法将构建完成的视图添加到窗口中。