Android源码学习 --SystemUI 3 SystemBars 与 StatusBar

根据上上一篇文章,我这里知道,SystemServer会通过 SystemUIService,SystemUIApplication类来 通过反射的方式将继承了SystemUI的各个子服务类实例化 , 其中我们可以看到:

 <item>com.android.systemui.SystemBars</item>

这就是我们今天的主角了。
SystemBars 里面的代码并不多,可谓是一目了然,如下:

/**
 * Ensure a single status bar service implementation is running at all times, using the in-process implementation according to the product config.
根据产品配置使用进程内实现,确保始终运行单个状态栏服务实现。
 */
public class SystemBars extends SystemUI {
    private static final String TAG = "SystemBars";
    private static final boolean DEBUG = false;
    private static final int WAIT_FOR_BARS_TO_DIE = 500;

    // in-process fallback implementation, per the product config   根据产品配置 进程内回退实现
    private SystemUI mStatusBar;

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

    @Override
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        if (mStatusBar != null) {
            mStatusBar.dump(fd, pw, args);
        }
    }

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

    private RuntimeException andLog(String msg, Throwable t) {
        Log.w(TAG, msg, t);
        throw new RuntimeException(msg, t);
    }
}

看看 frameworks\base\packages\SystemUI\res\values 路径下的config.xml文件,搜索里面的config_statusBarComponent,可以得到:

    <!-- Component to be used as the status bar service.  
    Must implement the IStatusBar  interface. 
    This name is in the ComponentName flattened format (package/class)
	要用作状态栏服务的组件必须实现IStatusBar接口
	此名称采用componentname扁平格式(包/类)  -->
    <string name="config_statusBarComponent" translatable="false">
    com.android.systemui.statusbar.phone.StatusBar</string>

好吧,我们需要来到我们的下一站:StatusBar
StatusBar 也继承了SystemUI
这里来看下start方法

   @Override
    public void start() {
        mGroupManager = Dependency.get(NotificationGroupManager.class);
        ...
        mNotificationLogger = Dependency.get(NotificationLogger.class);
        ...
        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        ...
        // 1. 获取服务端信息
		// 1.1 获取StatusBarManagerService的服务端代理对象
        mBarService = IStatusBarService.Stub.asInterface(
            ServiceManager.getService(Context.STATUS_BAR_SERVICE));
		...
		mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
        mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
                Context.DEVICE_POLICY_SERVICE);
        ...
        // 1.2 为CommandQueue对象添加回调
		mCommandQueue = getComponent(CommandQueue.class);
		mCommandQueue.addCallbacks(this);
        int[] switches = new int[9];
        ArrayList<IBinder> binders = new ArrayList<>();
        ArrayList<String> iconSlots = new ArrayList<>();
        ArrayList<StatusBarIcon> icons = new ArrayList<>();
        Rect fullscreenStackBounds = new Rect();
        Rect dockedStackBounds = new Rect();
        try {
        // 1.3 从StatusBarManagerService获取信息
            mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
                    fullscreenStackBounds, dockedStackBounds);
        } catch (RemoteException ex) {
            // If the system process isn't there we're doomed anyway.
        }
        // 2. 创建视图,并添加到窗口中
        createAndAddWindows();

        // Make sure we always have the most current wallpaper info.
        //确保我们总是有最新的壁纸信息。
        IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
        mContext.registerReceiver(mWallpaperChangedReceiver, wallpaperChangedFilter);
        mWallpaperChangedReceiver.onReceive(mContext, null);
        ...
        // 3. 利用从StatusBarManagerService获取到的信息,设置图标的初始状态
		int N = iconSlots.size();
        for (int i=0; i < N; i++) {
            mCommandQueue.setIcon(iconSlots.get(i), icons.get(i));
         }
         // 4. 设置系统启动完毕需要显示的图标
		mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
         ...
        //还监听了 BANNER_ACTION_CANCEL 和 BANNER_ACTION_SETUP
        IntentFilter internalFilter = new IntentFilter();
        internalFilter.addAction(BANNER_ACTION_CANCEL);
        internalFilter.addAction(BANNER_ACTION_SETUP);
        mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
                null);

        IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
                Context.VR_SERVICE));
        ...
        
        } 
   private static final String BANNER_ACTION_CANCEL = "com.android.systemui.statusbar.banner_action_cancel";
    private static final String BANNER_ACTION_SETUP = "com.android.systemui.statusbar.banner_action_setup";

看下上面所说的createAndAddWindows方法:

 public void createAndAddWindows() {
        addStatusBarWindow();
    }

    private void addStatusBarWindow() {
        makeStatusBarView();
        mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
       ...
    }
    //	初始化view
     protected void makeStatusBarView() {
        final Context context = mContext;
        updateDisplaySize(); // populates mDisplayMetrics
        updateResources();
        updateTheme();

        inflateStatusBarWindow(context);
        mStatusBarWindow.setService(this);
        mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());

        // TODO: Deal with the ugliness that comes from having some of the statusbar broken out
        // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
        mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
        mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
        mZenController.addCallback(this);
        mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow, this, mNotificationPanel, mStackScroller);
    }
    ...
    mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
                R.id.notification_container_parent));
	mKeyguardStatusBar = mStatusBarWindow.findViewById(R.id.keyguard_header);
	...
	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);
                    mStatusBarView.setBouncerShowing(mBouncerShowing);
                    if (mHeadsUpAppearanceController != null) {
                        // This view is being recreated, let's destroy the old one
                        mHeadsUpAppearanceController.destroy();
                    }
                    mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                            mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);
                    setAreThereNotifications();
                    checkBarModes();
                }).getFragmentManager()
                .beginTransaction()
                //把status_bar_container启动了一个CollapsedStatusBarFragment。
                .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
                        CollapsedStatusBarFragment.TAG)
                .commit();
...
		mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
        mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front);
        mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back);
...

方法如下:

    void updateDisplaySize() {
        mDisplay.getMetrics(mDisplayMetrics);
        mDisplay.getSize(mCurrentDisplaySize);
        if (DEBUG_GESTURES) {
            mGestureRec.tag("display",
                    String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
        }
    }
    /**
     配置更改时重新加载一些资源。在配置更改时,我们不会重新加载所有内容——我们可能应该这样做,但要获得平滑是很困难的总有一天我们会解决的。同时,更新我们知道的变化
     */
    void updateResources() {
        // Update the quick setting tiles
        if (mQSPanel != null) {
            mQSPanel.updateResources();
        } 
        loadDimens(); 
        if (mStatusBarView != null) {
            mStatusBarView.updateResources();
        }
        if (mNotificationPanel != null) {
            mNotificationPanel.updateResources();
        }
        if (mBrightnessMirrorController != null) {
            mBrightnessMirrorController.updateResources();
        }
    }
    //重要的总是在最后面
    protected void inflateStatusBarWindow(Context context) {
        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                R.layout.super_status_bar, null);
    }

下面图片引用自 文章
好吧,简单陈述一下:
StatusBar.java

-> start

-> createAndAddWindows

-> addStatusBarWindow

-> makeStatusBarView

-> inflateStatusBarWindow
在这里插入图片描述
上面代码中可以看到 把status_bar_container启动了一个CollapsedStatusBarFragment

 	@Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            Bundle savedInstanceState) {
        return inflater.inflate(R.layout.status_bar, container, false);
    }
     
    @Override
	public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    mStatusBar = (PhoneStatusBarView) view;
    //icons
    mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
    //mSystemIconArea用来显示状态栏左边图标的区域
    mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
    //carrierText用来显示网络供应商的名称
    carrierText = (CarrierText)mStatusBar.findViewById(R.id.system_carrier_text);
    //mSignalClusterView则是用来显示信号相关的信息
    mSignalClusterView = mStatusBar.findViewById(R.id.signal_cluster);
    // Default to showing until we know otherwise.
    showSystemIconArea(false);
    initEmergencyCryptkeeperText();
}

在这里插入图片描述
在这里插入图片描述1 对应的是notification_icon_area,平日里显示的都是notifications,如三方和系统的一些通知。
2 对应的是statusIcons,平日里显示的一些系统状态,如蓝牙、闹铃等。
3 是信号集群,显示的是信号相关的view,如wifi,cell信号格等,对应的是signal_cluster_view.xml。
4 则是剩余的两个独立的图标, 分别为电池电量显示、时间显示。

更多细节,请看下篇
status_bar.xml 去掉部分不重要的代码:

<com.android.systemui.statusbar.phone.PhoneStatusBarView  
    android:id="@+id/status_bar"
    android:background="@drawable/system_bar_background" 
    android:focusable="false"
    android:descendantFocusability="afterDescendants"
    android:accessibilityPaneTitle="@string/status_bar"
    >

    <ImageView
        android:id="@+id/notification_lights_out" 
        android:src="@drawable/ic_sysbar_lights_out_dot_small"
        android:scaleType="center"
        android:visibility="gone"
        />

    <LinearLayout android:id="@+id/status_bar_contents" 
        android:orientation="horizontal"
        >
        <ViewStub
            android:id="@+id/operator_name" 
            android:layout="@layout/operator_name" />
        <FrameLayout
            android:layout_height="match_parent"
            android:layout_width="0dp"
            android:layout_weight="1">

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

            <!-- The alpha of the left side is controlled by PhoneStatusBarTransitions, and the
             individual views are controlled by StatusBarManager disable flags DISABLE_CLOCK and
             DISABLE_NOTIFICATION_ICONS, respectively
             左侧的alpha由PhoneStatusBarTransitions控制,各个视图分别由StatusBarManager disable flags DISABLE_CLOCK 和	
             	DISABLE_NOTIFICATION_ICONS图标控制 -->
            <LinearLayout
                android:id="@+id/status_bar_left_side" 
                android:clipChildren="false"
            >
                <com.android.systemui.statusbar.policy.Clock
                    android:id="@+id/clock" 
                    android:textAppearance="@style/TextAppearance.StatusBar.Clock"
                    android:singleLine="true" 
                    android:gravity="center_vertical|start"
                />

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

            </LinearLayout>
        </FrameLayout>

        <!-- Space should cover the notch (if it exists) and let other views lay out around it -->
        <android.widget.Space
            android:id="@+id/cutout_space_view"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:gravity="center_horizontal|center_vertical"
        />

        <com.android.keyguard.AlphaOptimizedLinearLayout 
        	android:id="@+id/system_icon_area"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="horizontal"
            android:gravity="center_vertical|end"
            >

            <include layout="@layout/system_icons" />
        </com.android.keyguard.AlphaOptimizedLinearLayout>
    </LinearLayout>

    <ViewStub
        android:id="@+id/emergency_cryptkeeper_text" 
        android:layout="@layout/emergency_cryptkeeper_text"
    />

</com.android.systemui.statusbar.phone.PhoneStatusBarView>

system_icons:信号区域:signal_cluster_view、状态栏电池,statusIcons(蓝牙、飞行模式statusIcons)。

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

    <com.android.systemui.statusbar.phone.StatusIconContainer android:id="@+id/statusIcons"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:paddingEnd="@dimen/signal_cluster_battery_padding"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:tag="@string/status_bar_tag"/>

    <com.android.systemui.BatteryMeterView android:id="@+id/battery"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:clipToPadding="false"
        android:clipChildren="false"
        android:tag="statusbar" />
</LinearLayout>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值