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

来源:互联网 发布:python 文件重命名 编辑:程序博客网 时间:2024/04/27 23:12
平台: 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
staticfinalvoid startSystemUi(Context context) {
    Intent intent = new Intent();
    intent.setComponent(newComponentName("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=0i<Ni++) {
        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(mCommandQueueiconListnotificationKeysnotifications,
                switchesbinders);
   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(mStatusBarWindowlp);
    }
}
添加状态栏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(contextR.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的时候,也根据之前拿到的状态,初始化一些应该显示状态图标




【持续更新。。。。。】








1 0
原创粉丝点击