草庐IT

Android 12系统源码_SystemUI(五)自定义状态栏和导航栏视图

AFinalStone 2023-04-11 原文

前言

前面几篇文章我们具体分析了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方法将构建完成的视图添加到窗口中。

有关Android 12系统源码_SystemUI(五)自定义状态栏和导航栏视图的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  3. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  4. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  5. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  6. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  7. ruby - 如何在 Grape 中定义哈希数组? - 2

    我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>

  8. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  9. ruby - 这两个 Ruby 类初始化定义有什么区别? - 2

    我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是

  10. ruby-on-rails - 如何生成传递一些自定义参数的 `link_to` URL? - 2

    我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些

随机推荐