SystemUI---RAT

System UI的内容很多,包括状态栏、通知栏、锁屏、Navigation bar和Recent等;本篇主要分析状态栏中的RAT图标、数据图标以及信号格的更新。每一个新版本,Google都会对这一块进行修改,所以不同版本之间会有些差异,本篇内容是基于Android O。
本文分成三部分:
1. System UI的启动
2. System UI的布局
3. 图标的更新


1. System UI的启动

下方的流程图从SystemServer启动,即SystemServer.main方法开始简单展示了StatusBar的启动流程。
SystemUI---RAT_第1张图片

SystemServer.startSystemUi方法负责去启动SystemUIService:

    static final void startSystemUi(Context context, WindowManagerService windowManager) {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.android.systemui",
                    "com.android.systemui.SystemUIService"));
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        //Slog.d(TAG, "Starting service: " + intent);
        context.startServiceAsUser(intent, UserHandle.SYSTEM);
        windowManager.onSystemUiStarted();
    }

在启动SystemUIService时,SystemUIApplication会先被启动。SystemUIService的onCreate方法会调用SystemUIApplication.startServicesIfNeeded方法,后者构造了一系列SystemUI类型(子类)的对象,并调用了它们的start方法,其中就包括SystemBars,SystemBars.start方法如下:

 @Override
    public void start() {
        if (DEBUG) Log.d(TAG, "start");
        createStatusBarFromConfig();
    }

    private void createStatusBarFromConfig() {
        if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
        //"获取类信息,R.string.config_statusBarComponent的默认值是com.android.systemui.statusbar.phone.StatusBar"
        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 = (SystemUI) cls.newInstance();//new一个实例
        } catch (Throwable t) {
            throw andLog("Error creating status bar component: " + clsName, t);
        }
        mStatusBar.mContext = mContext;
        mStatusBar.mComponents = mComponents;
        mStatusBar.start();//调用StatusBar.start方法
        if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
    }

R.string.config_statusBarComponent的值是com.android.systemui.statusbar.phone.StatusBar

相比于之前的版本,Android O上没有了PhoneStatusBar.java类,取而代之的是StatusBar.java。布局文件super_status_bar.xml也发生了一些改变,不再include “status_bar.xml”,而是用CollapsedStatusBarFragment加载; CollapsedStatusBarFragment本身的加载是在StatusBar.makeStatusBarView方法中,下面即是这部分代码:

    FragmentHostManager.get(mStatusBarWindow)
                .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                    CollapsedStatusBarFragment statusBarFragment =
                            (CollapsedStatusBarFragment) fragment;
                    statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
                    mStatusBarView = (PhoneStatusBarView) fragment.getView();
                    mStatusBarView.setBar(this);
                    mStatusBarView.setPanel(mNotificationPanel);
                    mStatusBarView.setScrimController(mScrimController);
                    setAreThereNotifications();
                    checkBarModes();
                }).getFragmentManager()
                .beginTransaction()
                .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
                        CollapsedStatusBarFragment.TAG)
                .commit();

这段代码或许看起来不是那么清晰明了,因为里面包含了多个方法调用还夹杂了Java 8的的Lambda表达式; 其实addTagListener方法中的Lambda部分是回调,所以可以先忽略掉,只关注addTagListener方法的返回对象。
下面是FragmentHostManager.get方法的code:

    public static FragmentHostManager get(View view) {
        try {
            return Dependency.get(FragmentService.class).getFragmentHostManager(view);
        } catch (ClassCastException e) {
            // TODO: Some auto handling here?
            throw e;
        }
    }

这个方法只是调用了FragmentService的getFragmentHostManager方法,code如下:

    public FragmentHostManager getFragmentHostManager(View view) {
        View root = view.getRootView();
        FragmentHostState state = mHosts.get(root);
        if (state == null) {
            state = new FragmentHostState(root);
            mHosts.put(root, state);
        }
        return state.getFragmentHostManager();
    }

FragmentService.getFragmentHostManager方法创建了一个FragmentHostState对象,然后调用这个对象的getFragmentHostManager方法,下面是FragmentHostState的相关code:

        public FragmentHostState(View view) {
            mView = view;
            //创建一个FragmentHostManager对象
            mFragmentHostManager = new FragmentHostManager(mContext, FragmentService.this, mView);
        }
        public FragmentHostManager getFragmentHostManager() {
            return mFragmentHostManager;
        }

通过上面的一些列调用,我们可以看到FragmentHostManager.get方法使用参数View创建了一个新的FragmentHostManager对象,而FragmentHostManager.addTagListener方法返回的仍是对象本身。

那么FragmentHostManager.getFragmentManager()方法返回的又是什么呢?
下面是看下FragmentHostManager的构造方法和createFragmentHost方法:

    FragmentHostManager(Context context, FragmentService manager, View rootView) {
        mContext = context;
        mManager = manager;
        mRootView = rootView;
        mConfigChanges.applyNewConfig(context.getResources());
        createFragmentHost(null);
    }

    private void createFragmentHost(Parcelable savedState) {
        mFragments = FragmentController.createController(new HostCallbacks());
        mFragments.attachHost(null);
        mLifecycleCallbacks = new FragmentLifecycleCallbacks() {
            @Override
            public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v,
                    Bundle savedInstanceState) {
                FragmentHostManager.this.onFragmentViewCreated(f);
            }

            @Override
            public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {
                FragmentHostManager.this.onFragmentViewDestroyed(f);
            }

            @Override
            public void onFragmentDestroyed(FragmentManager fm, Fragment f) {
                Dependency.get(LeakDetector.class).trackGarbage(f);
            }
        };
        mFragments.getFragmentManager().registerFragmentLifecycleCallbacks(mLifecycleCallbacks,
                true);
        if (savedState != null) {
            mFragments.restoreAllState(savedState, (FragmentManagerNonConfig) null);
        }
        // For now just keep all fragments in the resumed state.
        mFragments.dispatchCreate();
        mFragments.dispatchStart();
        mFragments.dispatchResume();
    }

FragmentHostManager的构造函数没什么重要内容,只是调用了内部Private 方法createFragmentHost,该方法构造了一个FragmentController类型的对象mFragments,并设置了HostCallbacks对象作为回调; HostCallbacks(继承了FragmentHostCallback)内部有FragmentManagerImpl对象,FragmentManagerImpl是FragmentManager.java的内部类,继承了FragmentManager类。
下面是FragmentHostManager.getFragmentManager()的代码:

    public FragmentManager getFragmentManager() {
        return mFragments.getFragmentManager();
    }

又调用了FragmentController的getFragmentManager()方法,对应code如下:

    /**
     * Returns a {@link FragmentManager} for this controller.
     */
    public FragmentManager getFragmentManager() {
        return mHost.getFragmentManagerImpl();
    }

代码中的mHost即是HostCallbacks对象,HostCallbacks.getFragmentManagerImpl()方法返回的就是FragmentManagerImpl对象。即FragmentHostManager.getFragmentManager()方法返回了一个FragmentManagerImpl对象。再回到StatusBar.makeStatusBarView方法中:

    FragmentHostManager.get(mStatusBarWindow)
                .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                    CollapsedStatusBarFragment statusBarFragment =
                            (CollapsedStatusBarFragment) fragment;
                    statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
                    mStatusBarView = (PhoneStatusBarView) fragment.getView();
                    mStatusBarView.setBar(this);
                    mStatusBarView.setPanel(mNotificationPanel);
                    mStatusBarView.setScrimController(mScrimController);
                    setAreThereNotifications();
                    checkBarModes();
                }).getFragmentManager()
                .beginTransaction()
                .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
                        CollapsedStatusBarFragment.TAG)
                .commit();

FragmentManagerImpl.beginTransaction方法会返回一个BackStackRecord对象; BackStackRecord继承了FragmentTransaction, 折腾了一圈还是回到了FragmentTransaction,然后使用replace方法将CollapsedStatusBarFragment放进布局中super_status_bar.xml中; CollapsedStatusBarFragment会加载R.layout.status_bar布局(PhoneStatusBarView)。

代码流程是看懂了,但是由于对Android UI这套理解不深,所以不明白这个设计的初衷,是为了解耦,模块化?

Dependency.java

SystemUIApplication启动的service就包含Dependency, Dependency包含一个ArrayMap 类型的成员变量mProviders, Dependency.start方法中会重要类的对象放到mProviders中, 下面是部分代码:

        mProviders.put(NetworkController.class, () ->
                new NetworkControllerImpl(mContext, getDependency(BG_LOOPER),
                        getDependency(DeviceProvisionedController.class)));

        mProviders.put(ZenModeController.class, () ->
                new ZenModeControllerImpl(mContext, getDependency(MAIN_HANDLER)));

        mProviders.put(HotspotController.class, () ->
                new HotspotControllerImpl(mContext));

        mProviders.put(CastController.class, () ->
                new CastControllerImpl(mContext));

        mProviders.put(FlashlightController.class, () ->
                new FlashlightControllerImpl(mContext));

2. System UI的布局

System UI的布局大致分成两部分,左边用来显示通知信息,右边用来显示时钟、信号格等信息; 而且这两部分向相反方向扩展,即左边部分从右向左扩展,右边部分从左向右扩展。本文主要关注右边部分的布局,下图简单的展示了相关的布局关系:
SystemUI---RAT_第2张图片
super_status_bar.xml没有直接include “status_bar.xml”,而是用CollapsedStatusBarFragment加载到了下面的FrameLayout布局中:

    <FrameLayout
        android:id="@+id/status_bar_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

status_bar.xml部分布局如下:



<LinearLayout android:id="@+id/status_bar_contents"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingStart="6dp"
        android:paddingEnd="8dp"
        android:orientation="horizontal"
        >

        
        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
            android:id="@+id/notification_icon_area"
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="horizontal" />

        
        <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            >

            
            <include layout="@layout/system_icons" />

            
            <com.android.systemui.statusbar.policy.Clock
                android:id="@+id/clock"
                android:textAppearance="@style/TextAppearance.StatusBar.Clock"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:singleLine="true"
                android:paddingStart="@dimen/status_bar_clock_starting_padding"
                android:paddingEnd="@dimen/status_bar_clock_end_padding"
                android:gravity="center_vertical|start"
                />
        com.android.keyguard.AlphaOptimizedLinearLayout>
    LinearLayout>
    

system_icons.xml布局比较简单,如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/system_icons"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:gravity="center_vertical">

    <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/statusIcons"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal"/>

    
    <include layout="@layout/signal_cluster_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/signal_cluster_margin_start"/>

    
    <com.android.systemui.BatteryMeterView android:id="@+id/battery"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        />
LinearLayout>

signal_cluster_view.xml对应的是SignalClusterView对象,当SignalClusterView.onAttachedToWindow方法被系统调用时,SignalClusterView会调用NetworkControllerImpl.addCallback方法,在这个方法中SignalClusterView.setSubs方法会被调用:

    @Override
    public void setSubs(List subs) {
        //如果已经包含了subs信息,那么直接return
        if (hasCorrectSubs(subs)) {
            return;
        }
        //下面两句清空了之前的数据
        mPhoneStates.clear();
        if (mMobileSignalGroup != null) {
            mMobileSignalGroup.removeAllViews();
        }
        final int n = subs.size();
        //根据subscription信息开始加载布局
        for (int i = 0; i < n; i++) {
            inflatePhoneState(subs.get(i).getSubscriptionId());
        }
        if (isAttachedToWindow()) {
            applyIconTint();
        }
    }

    //PhoneState是SignalClusterView的内部类,每个PhoneState对象都会加载一个mobile_signal_group.xml布局,
    //所以mobile_signal_group.xml布局数量和active Subscription数量(SIM 数量)一致。
    private PhoneState inflatePhoneState(int subId) {
        PhoneState state = new PhoneState(subId, mContext);
        if (mMobileSignalGroup != null) {
            mMobileSignalGroup.addView(state.mMobileGroup);
        }
        mPhoneStates.add(state);
        return state;
    }

3. 图标更新

下面的流程图简单展示了UI更新的过程:
SystemUI---RAT_第3张图片
NetworkControllerImpl的构造函数使用mReceiverHandler.post方法将Runnable对象mRegisterListeners放到了消息队列里面,当mRegisterListeners执行的时候run方法会调用NetworkControllerImpl.registerListeners方法,这个方法监听了很多广播(NetworkControllerImpl是BroadcastReceiver的子类)。

    private void registerListeners() {
        for (int i = 0; i < mMobileSignalControllers.size(); i++) {
            MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
            mobileSignalController.registerListener();
        }
        if (mSubscriptionListener == null) {
            mSubscriptionListener = new SubListener();
        }
        mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);

        // broadcasts
        IntentFilter filter = new IntentFilter();
        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
        filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
        filter.addAction(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
        filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
        filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        mContext.registerReceiver(this, filter, null, mReceiverHandler);
        mListening = true;

        updateMobileControllers();
    }

不同的广播,处理自然也不一样。
当收到广播ACTION_SIM_STATE_CHANGED的时候,updateMobileControllers、doUpdateMobileControllers、setCurrentSubscriptions等方法会先后被调用。setCurrentSubscriptions方法会根据最新的subscriptions信息构造MobileSignalController方法,并调用新对象的registerListener方法在TelephonyManager中设置监听:

    /**
     * Start listening for phone state changes.
     */
    public void registerListener() {
        mPhone.listen(mPhoneStateListener,
                PhoneStateListener.LISTEN_SERVICE_STATE
                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
                        | PhoneStateListener.LISTEN_CALL_STATE
                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
                        | PhoneStateListener.LISTEN_DATA_ACTIVITY
                        | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE);
        mContext.getContentResolver().registerContentObserver(Global.getUriFor(Global.MOBILE_DATA),
                true, mObserver);
        mContext.getContentResolver().registerContentObserver(Global.getUriFor(
                Global.MOBILE_DATA + mSubscriptionInfo.getSubscriptionId()),
                true, mObserver);
    }

MobileSignalController监听了service state、signal strength和call state等,当这些状态变化时MobileSignalController会通知自己的监听者,调用方法顺序是:
notifyListenersIfNecessary()
–>notifyListeners()
–>notifyListeners(mCallbackHandler)
mCallbackHandler是NetworkControllerImpl在构造MobileSignalController对象的时候传进来的,即NetworkControllerImpl.mCallbackHandler。NetworkControllerImpl.mCallbackHandler可以把状态变化通知到SignalClusterView对象,因为SignalClusterView.onAttachedToWindow方法被调用的时候,SignalClusterView调用了NetworkControllerImpl.addCallback方法在NetworkControllerImpl.mCallbackHandler中设置了监听。针对MobileSignalController的调用NetworkControllerImpl.mCallbackHandler会调用setMobileDataIndicators方法,其实这个方法只是做了赋值操作,真正更新是在apply方法中。


结束!

你可能感兴趣的:(SystemUI---RAT)