android(cm11)状态栏源码分析(一)

简介: 版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/50216563 (一):写在前面最近由于工作需要,需要了解CM11中的有关于StatusBar相关的内容。
+关注继续查看
版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/50216563

(一):写在前面

最近由于工作需要,需要了解CM11中的有关于StatusBar相关的内容。总的来说,刚开始阅读其源码的时候,是有点困难,不过通过构建相关代码的脑图和流程图,几天下来,我已经对其源码有了一个大体的了解,不过其内部细节还有很多不是很明白,但是这对于我的工作来说就已经足够了。

在android系统中,有关于系统状态栏有关的代码位于/framework/base/packages/SystemUI/中,很明显,该SystemUI是一个app源码,当系统进行编译的时候,就会生成SystemUI.apk。所以我们对待它就像是对待普通app程序一样。

好了,现在开始我们的代码分析。

(二):StatusBar流程分析

对于android系统来说,SystemUI的启动是有位于packages下面的android系统launcher启动器启动的,启动方式其实是通过java的反射机制实现的。其启动SystemUI的SystemUIService,该SystemUIService是Service的一个子类,同时,在该类中通过反射机制同时启动6个和系统UI相关的类,这个我们后面再分析。

这6个和系统UI相关的类都继承自SystemUI类,在SystemUIService中实例化这6个类的时候同时启动该类对应的start()方法来启动服务。而他们的start()函数中主要是启动相关ServiceMonitor的start方法,在该ServiceMonitor中主要是启动相关的包的服务,即调用startService()函数。在启动服务的时候,就会实例化StatusBar,并且调用其onStart()函数。这个就是StatusBar的启动流程,这样说的话可能理解起来比较繁琐,下面的这张图就是系统状态栏的启动过程的流程图:

这里写图片描述

(三):SystemUIService源码分析

下面我们来分析一下SystemUIService的源码。

该SystemUIService类继承自Service类,说明该类是一个服务类,在该类中都是干了什么工作呢?我们先找到Service类中的onCreate()方法:

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();
        }
    }

从这里可以看出,通过一个for循环将数组SERVICES中保存的类实例化,即调用newInstance()函数,实例化完成之后,对其对象中的属性进行赋值,最后再调用相应的start()函数。

下面我们来看一下SERVICES数组中的保存的6个类:

 private final Class<?>[] SERVICES = new Class[] {
            com.android.systemui.recent.Recents.class,
            com.android.systemui.statusbar.SystemBars.class,
            com.android.systemui.usb.StorageNotification.class,
            com.android.systemui.power.PowerUI.class,
            com.android.systemui.media.RingtonePlayer.class,
            com.android.systemui.settings.SettingsUI.class,
        };

当然,在这个类里面也存有其他相关的函数,包括配置发生改变的函数,销毁函数等,下面我们来看一下该类的脑图:

这里写图片描述

由于在这里启动了6个相关的类,但是我们在这篇文章中,我们先分析SystemBars.class类。

(四):SystemBars源码分析

在上面的流程图中,我们知道,启动的6个类都是继承自SystemUI类,我们先来看一下SystemUI类:

SystemUI类是一个抽象类,在该类中定义了一些方法,其中包括启动方法,配置发生改变的函数,销毁函数等。下面我们先来看一下该类的代码:

 public Context mContext;
    public Map<Class<?>, Object> mComponents;

    public abstract void start();

    protected void onConfigurationChanged(Configuration newConfig) {
    }

    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    }

    @SuppressWarnings("unchecked")
    public <T> T getComponent(Class<T> interfaceType) {
        return (T) (mComponents != null ? mComponents.get(interfaceType) : null);
    }

    public <T, C extends T> void putComponent(Class<T> interfaceType, C component) {
        if (mComponents != null) {
            mComponents.put(interfaceType, component);
        }
    }

在这个类中,比较有意思的就是Map对象,该对象就是保存相关类的组件。下面我们来看一下脑图:

这里写图片描述

下面我们来看SystemBars的源码,在这里我们主要查看的是其start()函数:

mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
                mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
        mServiceMonitor.start();  // will call onNoService if no remote service is found

在这里,主要是初始化ServiceMonitor对象,并且调用其start()函数。

但是对于ServiceMonitor类的对象来说,其start()函数,最终都要调用位于SystemBars类中的createStatusBarFromConfig()函数,在该函数中,主要是调用BaseStatusBar对象的start()函数。

private void createStatusBarFromConfig() {
        if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
        final String clsName = mContext.getString(R.string.config_statusBarComponent);
        if (clsName == null || clsName.length() == 0) {
            throw andLog("No status bar component configured", null);
        }
        Class<?> cls = null;
        try {
            cls = mContext.getClassLoader().loadClass(clsName);
        } catch (Throwable t) {
            throw andLog("Error loading status bar component: " + clsName, t);
        }
        try {
            mStatusBar = (BaseStatusBar) cls.newInstance();
        } catch (Throwable t) {
            throw andLog("Error creating status bar component: " + clsName, t);
        }
        mStatusBar.mContext = mContext;
        mStatusBar.mComponents = mComponents;
        mStatusBar.start();
        if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
    }

下面我们来看一下SystemBars类的脑图:

这里写图片描述

(五):ServiceMonitor源码分析

在ServiceMonitor类中主要是使用Handler中的信息类来进行包服务管理,其中有启动服务,继续服务,暂停服务,停止服务等函数,在这里辗转反侧最终还是回归到SystemBars中的StatusBars的启动:

这里写图片描述

(六):最终流程分析

上面我们提到了,最终还是要启动StatusBar,而这里启动的StatusBar并不是其真正的StatusBar,而是他的子类,也就是位于com/android/systemui/statusbar/phone/PhoneStatusBar.java,下面我们来看一下他的start()函数:

@Override
    public void start() {
        mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
                .getDefaultDisplay();
        updateDisplaySize();

        ThemeConfig currentTheme = mContext.getResources().getConfiguration().themeConfig;
        if (currentTheme != null) {
            mCurrentTheme = (ThemeConfig)currentTheme.clone();
        } else {
            mCurrentTheme = ThemeConfig.getSystemTheme();
        }

        mLocationController = new LocationController(mContext);
        mBatteryController = new BatteryController(mContext);
        mDockBatteryController = new DockBatteryController(mContext);
        mBluetoothController = new BluetoothController(mContext);

        super.start(); // calls createAndAddWindows()

        addNavigationBar();

        SettingsObserver observer = new SettingsObserver(mHandler);
        observer.observe();

        // Developer options - Force Navigation bar
        try {
            boolean needsNav = mWindowManagerService.needsNavigationBar();
            if (!needsNav) {
                mDevForceNavbarObserver = new DevForceNavbarObserver(mHandler);
                mDevForceNavbarObserver.observe();
            }
        } catch (RemoteException ex) {
            // no window manager? good luck with that
        }

        // Lastly, call to the icon policy to install/update all the icons.
        mIconPolicy = new PhoneStatusBarPolicy(mContext);

        mHeadsUpObserver.onChange(true); // set up
        if (ENABLE_HEADS_UP) {
            mContext.getContentResolver().registerContentObserver(
                    Settings.System.getUriFor(Settings.System.HEADS_UP_NOTIFICATION), true,
                    mHeadsUpObserver, mCurrentUserId);
        }
    }

在这个代码中,我们看到代码中,有一个类PhoneStatusBarPolicy类,该类就是向状态栏中添加图标的管理类。下面我们来看一下该类的构造方法:

    public PhoneStatusBarPolicy(Context context) {
        mContext = context;
        mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);

        // listen for broadcasts
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_ALARM_CHANGED);
        filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
        filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);

        int numPhones = MSimTelephonyManager.getDefault().getPhoneCount();
        mSimState = new IccCardConstants.State[numPhones];
        for (int i=0; i < numPhones; i++) {
            mSimState[i] = IccCardConstants.State.READY;
        }

        // TTY status
        mService.setIcon("tty",  R.drawable.stat_sys_tty_mode, 0, null);
        mService.setIconVisibility("tty", false);

        // Cdma Roaming Indicator, ERI
        mService.setIcon("cdma_eri", R.drawable.stat_sys_roaming_cdma_0, 0, null);
        mService.setIconVisibility("cdma_eri", false);

        // bluetooth status
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        int bluetoothIcon = R.drawable.stat_sys_data_bluetooth;
        if (adapter != null) {
            mBluetoothEnabled = (adapter.getState() == BluetoothAdapter.STATE_ON);
            if (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED) {
                bluetoothIcon = R.drawable.stat_sys_data_bluetooth_connected;
            }
        }
        mService.setIcon("bluetooth", bluetoothIcon, 0, null);
        mService.setIconVisibility("bluetooth", mBluetoothEnabled);

        // Alarm clock
        mService.setIcon("alarm_clock", R.drawable.stat_sys_alarm, 0, null);
        mService.setIconVisibility("alarm_clock", false);

        // Sync state
        mService.setIcon("sync_active", R.drawable.stat_sys_sync, 0, null);
        mService.setIconVisibility("sync_active", false);
        // "sync_failing" is obsolete: b/1297963

        // volume
        mService.setIcon("volume", R.drawable.stat_sys_ringer_silent, 0, null);
        mService.setIconVisibility("volume", false);
        updateVolume();
    }

而这里主要是添加监听广播,并且添加其他相关图标。

还有有些图标是在布局文件中添加的,其中于StatusBar相关的布局文件是在下面几个文件中的:

  • SystemUI/res/layout/status_bar.xml
  • SystemUI/res/layout/super_status_bar.xml

以及其内部include的相关文件。

好了,至此,有关与android系统状态栏相关的代码已经了解的差不多了,通过这个,我们可以向状态栏中添加图标或者是删除图标,这个是比较简单了。

好了,有关与状态栏的代码我们就分析到此,后面我们再来分析QuickSettings的相关的代码。

目录
相关文章
|
4月前
|
Android开发
Android PackageManagerService源码分析和APK安装原理详解
Android PackageManagerService源码分析和APK安装原理详解
98 1
|
9月前
|
XML 存储 搜索推荐
|
10月前
|
Java 调度 Android开发
android体系课-系统启动流程-之zygote进程启动过程源码分析
笔者刚开始学习Android的时候也和大部分同学一样,只会使用一些应用层面的知识,对于一些比较常见的开源框架如<mark>RxJava</mark>,<mark>OkHttp</mark>,<mark>Retrofit</mark>,以及后来谷歌推出的<mark>协程</mark>等,都只在使用层面,对于他们<mark>内部原理</mark>,基本没有去了解觉得够用就可以了,又比如Activity,Service等四大组件的使用原理,系统开机过程,Launcher启动过程等知之甚少,知其然而不知其所以然,结果就是出现某些问题,不知道从哪里找原因,只能依赖万能的百度,但是百度看多了,你会发现自己
|
10月前
|
Java 调度 Android开发
android体系课-系统启动流程-之SystemServer启动过程源码分析
笔者刚开始学习Android的时候也和大部分同学一样,只会使用一些应用层面的知识,对于一些比较常见的开源框架如<mark>RxJava</mark>,<mark>OkHttp</mark>,<mark>Retrofit</mark>,以及后来谷歌推出的<mark>协程</mark>等,都只在使用层面,对于他们<mark>内部原理</mark>,基本没有去了解觉得够用就可以了,又比如Activity,Service等四大组件的使用原理,系统开机过程,Launcher启动过程等知之甚少,知其然而不知其所以然,结果就是出现某些问题,不知道从哪里找原因,只能依赖万能的百度,但是百度看多了,你会发现自己
|
10月前
|
设计模式 XML 缓存
Android体系课学习 之 网络请求库Retrofit源码分析-看这一篇就够了
- 网络请求在我们开发中起的很大比重,有一个好的网络框架可以节省我们的开发工作量,也可以避免一些在开发中不该出现的bug - *Retrofit*是一个轻量级框架,基于*OkHttp*的一个*Restful*框架
|
10月前
|
存储 缓存 Java
Android体系课-开源框架-这是一份详细的Glide源码分析文章
最近在`组件化`开发中准备封装一个`图片加载库`,于是乎就有了这篇文章 本篇文章对`Glide`源码过程做了一个详细的讲解,也是为了记录下自己对`Glide`的理解,以后忘记还可以从这里查找。
|
11月前
|
存储 前端开发 Android开发
Android | LiveData 源码分析
Android | LiveData 源码分析
|
11月前
|
存储 Android开发
Android ThreadLocal源码分析
Android ThreadLocal源码分析
|
存储 监控 Android开发
Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)
Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)
|
Java Android开发
❤️ Android startActivity源码分析(含启动新应用) ❤️(下)
9、ActivityTaskSupervisor.class 9.1 startSpecificActivity() 9.2 进程已启动 9.2.1 realStartActivityLocked() 9.2.2 ClientLifecycleManager.scheduleTransaction() 9.2.3 ClientTransaction.schedule() 9.2.4 ApplicationThread.scheduleTransaction() 9.2.5 ClientTransactionHandler.scheduleTransaction()
319 0
相关产品
云迁移中心
推荐文章
更多