[ Android SystemUi ] 动态修改系统状态栏颜色【沉浸式状态栏】

平台: Android MTK 4.4 

     个人很少在CSDN上写博客,做Android开发几年来,一直都是在印象笔记上写文档,写总结,可能是自己的性格原因吧~!在CSDN上一直保持索取的’姿态’,不管在哪里写,只要能写写博客总结一下自己的进步,总会掌握的更加牢固一些,也会让自己更接近所谓大神吧~!

     这是进到进新公司的第一个任务:需求是,系统应用层,入口可以更换主题,修改背景颜色,要求状态栏也跟随系统颜色变化,也就是动态修改状态栏颜色;

     虽然,做过1年的系统应用开发,也接触到framework层的一些代码,但是系统开发都是划分清晰,有些人可能做phone、systemui、launcher、settings、sms等等,就会一直做那块,哪怕是换工作也是一直做这块,但是你一旦换到小公司,就会涉及到很多其他模块的工作,我这次跳槽就是,之前做过1年的settings 、launcher的开发,这次一上来就做systemui了,不过,还好自己有自己一套看源码的方法,上手不算太难。

     很多人拿到需求,习惯性的百度去了,我个人认为,百度可以,尤其是系统开发,用百度也很正常(因为Android每次的版本升级,都会对源码更新改动,尤其4.4到5.0,再到6.0,这种大版本的发布,更是各种源码颠覆,更新一次,陌生一回),但是,自己总要先看看熟悉一些你需要开发模块的运行流程,实在不理解的地方再去搜索。自己多耐着性子去看陌生的源码,长期以往,对自己阅读源码的能力,会有很大程度的提升。

     好了,废话不多说,进入主题~!

1、systenUI,statusbar启动的大致流程
          拿到一个陌生模块的代码,首先肯定会去看看大致运行流程,manifest文件,第一个activity,或者service,systemUI中, 首先启动的是  SystemUIService.java,它是从外部启动的,开机完成后, 在SystemService启动时就被调用了。

manifest

<intent-filter>
                 
 
                 <category android:name= "android.intent.category.LAUNCHER" >
             </category></action></intent-filter>

SystemService.java中调用 SystemUIService
static final void startSystemUi(Context context) {
     Intent intent = new Intent();
     intent.setComponent( new ComponentName( "com.android.systemui" ,
                 "com.android.systemui.SystemUIService" ));
     //Slog.d(TAG, "Starting service: " + intent);
     context.startServiceAsUser(intent, UserHandle.OWNER);
}
SystemUIService 这个类中,首先初始了几大涉及到的子模块,他们都继承自systemui.java类。


我主要是做了statusbar这块,因此再来看看这个类是怎么调用到statusbar的, 在SystemUIService的OnCreate()函数中会创建实例,并调用mServices[i].start();方法调用各个子类的start()方法,初始化子类。
/**
 * Hold a reference on the stuff we start.
 */
private final SystemUI[] mServices =  new SystemUI[SERVICES.length] ;


@Override
public void onCreate() {
    HashMap<Class<?> Object> components =  new HashMap<Class<?> Object>() ;
    final int N = SERVICES.length ;
    for ( int i= 0 i<N i++) {
        Class<?> cl = SERVICES[i] ;
        Log.d(TAG "loading: " + cl) ;
        try {
            mServices[i] = (SystemUI)cl.newInstance() ;
       catch (IllegalAccessException ex) {
            throw new RuntimeException(ex) ;
       catch (InstantiationException ex) {
            throw new RuntimeException(ex) ;
        }
        mServices[i].mContext =  this;
        mServices[i].mComponents = components ;
        Log.d(TAG "running: " + mServices[i]) ;
        mServices[i].start() ;
    }
}

                   注:由于MTK平台的Android源码带动特别大,看起源码来,相对于aosp、高通,mavell平台相对繁杂,因为他们改变了Google的Android工程师代码习惯,风格混乱,

     
SystemBars  extends SystemUI  implements ServiceMonitor.Callbacks

systembar类中,start()方法中,初始化ServiceMonitor,并调用它的start()方法,添加了内容提供者并注册了监听后,发handler回调了system bar的 no service()方法,去根据默认config场景状态栏,记者在createStatusBarFromConfig()中,实例化了BaseStatusBar对象,并调用了BaseStatusBar中start()方法;【注:BaseStatusBar.java类网上很多资料这里写的StatusBar.java类,我没有深究到底是MTK改动,还是原生系统版本升级的改动,我这版本是MTK 4.4.2】

BaseStatusBar.java
public void start() {
    mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE) ;
    mWindowManagerService = WindowManagerGlobal.getWindowManagerService() ;
    mDisplay = mWindowManager.getDefaultDisplay() ;

    mDreamManager = IDreamManager.Stub.asInterface(
            ServiceManager.checkService(DreamService.DREAM_SERVICE)) ;
    mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE) ;

    mProvisioningObserver.onChange( false) // set up
    mContext.getContentResolver().registerContentObserver(
            Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED) , true,
            mProvisioningObserver) ;

    mBarService = IStatusBarService.Stub.asInterface(
            ServiceManager.getService(Context.STATUS_BAR_SERVICE)) ;

    mRecents = getComponent(RecentsComponent. class) ;

    mLocale = mContext.getResources().getConfiguration().locale ;
    mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale) ;

    // Connect in to the status bar manager service
    StatusBarIconList iconList =  new StatusBarIconList() ;
    ArrayList<IBinder> notificationKeys =  new ArrayList<IBinder>() ;
    ArrayList<StatusBarNotification> notifications =  new ArrayList<StatusBarNotification>() ;
    mCommandQueue =  new CommandQueue( this, iconList) ;

    int[] switches =  new int[ 7] ;
    ArrayList<IBinder> binders =  new ArrayList<IBinder>() ;
    try {
        mBarService.registerStatusBar(mCommandQueue iconList notificationKeys notifications ,
                switches binders) ;
   catch (RemoteException ex) {
        // If the system process isn't there we're doomed anyway.
    }

    createAndAddWindows() ;


BaseStatusBar类的start()方法中,才是真的开始准备初始化状态栏界面,window manager类也是各种ask想直接实现沉浸式状态栏的必掉的一个类,进过各种公用的初始化,走到createAndAddWindows()方法,点过去,我们发现他是一个抽象方法,那么这个方法就是有子类来实现的,查看集成体系,锁定BaseStatusBar.java类
public class PhoneStatusBar  extends BaseStatusBar  implements DemoMode {


@Override
public void createAndAddWindows() {
    addStatusBarWindow() ;
}

private void addStatusBarWindow() {
    // Put up the view
    final int height = getStatusBarHeight() ;
  final WindowManager.LayoutParams lp =  new WindowManager.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT ,
            height ,
            WindowManager.LayoutParams.TYPE_STATUS_BAR ,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH ,
            PixelFormat.TRANSLUCENT) ;

    lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED ;

    lp.gravity = getStatusBarGravity() ;
    lp.setTitle( "StatusBar") ;
    lp.packageName = mContext.getPackageName() ;

    makeStatusBarView() ;

    /// M: [SystemUI] For SystemUI AT.
    if (AutoTestHelper.isNotRunningInTest()) {
        mWindowManager.addView(mStatusBarWindow lp) ;
    }
}
添加状态栏window,开始对状态栏的初始化,走到 makeStatusBarView()方法。这就是直接初始化layout和view的具体方法,我们来详细看看这个方法:
protected PhoneStatusBarView makeStatusBarView() {
    final Context context = mContext ;

    Resources res = context.getResources() ;

    updateDisplaySize() // populates mDisplayMetrics
    loadDimens() ;

    mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size) ;

    /// M: Support "Change font size of phone".
    Configuration config = res.getConfiguration() ;
    mPreviousConfigFontScale = config.fontScale ;
    mPrevioutConfigOrientation = config.orientation ;
    updateAirplaneMode() ;


首先,获取当前屏幕的现实尺寸,然后再底层dimes中拿到系统对应默认的statusbar 图标和字体的size;

紧接着初始化当前的飞行模式,如果是飞行,后面就直接先飞行模式的icon。

然后,关键点来的:super_statu_bar.xml, 这就是,MTK平台状态栏主要的layout文件,注释中不难看出,并不是它,他只是原生的layout给including到了这个super_stat_bar的layout中,添加了一些MTK自己想要现实的状态布局;
        /// M: [SystemUI] Support "Dual SIM". {
//        if (FeatureOption.MTK_GEMINI_SUPPORT) {
//            mStatusBarWindow = (StatusBarWindowView)View.inflate(context, R.layout.gemini_super_status_bar, null);
//        } else {
            mStatusBarWindow = (StatusBarWindowView) View.inflate(context R.layout.super_status_bar , null) ;
//        }
        mStatusBarWindow.mService =  this;
//        mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
//            @Override
//            public boolean onTouch(View v, MotionEvent event) {
//                checkUserAutohide(v, event);
//                if (event.getAction() == MotionEvent.ACTION_DOWN) {
//                    if (mExpandedVisible) {
//                        animateCollapsePanels();
//                    }
//                }
//                return mStatusBarWindow.onTouchEvent(event);
//            }});
//yangxilin.INWATCH_STATUSBAR.inwatch
        InwatchMakeView() ;

我们来看看这layout布局文件的结构:


而status_bar.xml才是原生的layout,从结构中可以看到3部分布局:从布局结构不难看出各部分功能状态显示的划分;
ImageView--------@+id/notification_lights_out      
     通知状态图标icon
LinearLayout-----@+id/status_bar_contents
     状态栏内容主体:蓝牙,飞行,WiFi信号,phone信号,
                    电池(百分比+电池icon),时间
               | —--LinearLayout-- notification_icon_area
               | ——- LinearLayout-- system_icon_area
                              | ——-statusIcons
                              |---signal_battery_cluster
                              |---statusbar.policy.Clock
LinearLayout-----@+id/ticker
     

回到   makeStatusBarView()方法,紧接着,就是一大串的对其  子view 的初始化  findviewbyid(),初始化view的时候,也根据之前拿到的状态,初始化一些应该显示状态图标




【持续更新。。。。。】








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值