Android SystemUI之StatusBar,状态栏(二)

2023-11-08

Android  SystemUI系列:

     1.Android  SystemUI之启动流程(一)

     2.Android SystemUI之StatusBar,状态栏(二)

     3.Android SystemUI之下拉菜单,通知栏,快捷面板(三)

     4.Android SystemUI之NavigationBar,导航栏(四)

     5.Android SystemUI之Recent,近期列表(五)

 

一、StatusBar简介

      systemui其实结构是比较复杂,里面管理各种服务,导航栏,状态栏,近期列表,下拉菜单,关机界面等,其中以导航栏和状态栏,近期列表用的比较多,也是本博文会重点讲解的内容。从结构上来讲下拉菜单和状态栏都是属于statusbar,结构树上也是属于顶层的super_status_bar.xml(StatusBarWindowView),说这么多还不如直接上图,这样大家看的比较清晰直观

从上图可以比较直观的看出来顶层树是super_status_bar,之后会走两个分支status_bar_container和status_bar_expanded,status_bar_container这个分支主要呈现的是状态栏界面,状态栏细分左边和右边,左边是通知栏,右边是系统功能的状态图标显示,status_bar_expanded这个分支主要呈现的下拉菜单界面,其实下拉菜单中又分快捷图标和短信通知栏,但是这些内容在后续的章节会详细说。本章博文主要讲解status_bar_container这个分支

二、StatusBar创建

   在前面的博文(Android SystemUI之启动流程)有讲过服务的其中mServices[i].start();StatusBar也是SystemUI的一个服务,所以它的启动入口也是从start()方法开始,包括后面的近期列表服务(Recents)。

 1.StatusBar  start

    public void start() {
    //主要是有关notification的服务类获取
        mGroupManager = Dependency.get(NotificationGroupManager.class);
        mVisualStabilityManager = Dependency.get(VisualStabilityManager.class);
        mNotificationLogger = Dependency.get(NotificationLogger.class);
        mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
        mNotificationListener =  Dependency.get(NotificationListener.class);//notification监听信息的service
        mGroupManager = Dependency.get(NotificationGroupManager.class);
        mNetworkController = Dependency.get(NetworkController.class);
        mUserSwitcherController = Dependency.get(UserSwitcherController.class);
        mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
        mScreenLifecycle.addObserver(mScreenObserver);
        mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
        mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
        mBatteryController = Dependency.get(BatteryController.class);//电池管理控制类。
        mAssistManager = Dependency.get(AssistManager.class);
        mOverlayManager = IOverlayManager.Stub.asInterface(
                ServiceManager.getService(Context.OVERLAY_SERVICE));
        mLockscreenUserManager = Dependency.get(NotificationLockscreenUserManager.class);
        mGutsManager = Dependency.get(NotificationGutsManager.class);
        mMediaManager = Dependency.get(NotificationMediaManager.class);
        mEntryManager = Dependency.get(NotificationEntryManager.class);//notification管理类,
        mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
        mAppOpsListener = Dependency.get(AppOpsListener.class);
        mAppOpsListener.setUpWithPresenter(this, mEntryManager);
        mZenController = Dependency.get(ZenModeController.class);
        mKeyguardViewMediator = getComponent(KeyguardViewMediator.class);

        mColorExtractor = Dependency.get(SysuiColorExtractor.class);
        mColorExtractor.addOnColorsChangedListener(this);

        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);

        mDisplay = mWindowManager.getDefaultDisplay();
        updateDisplaySize();

        Resources res = mContext.getResources();
        mVibrateOnOpening = mContext.getResources().getBoolean(
                R.bool.config_vibrateOnIconAnimation);
        mVibratorHelper = Dependency.get(VibratorHelper.class);
        mScrimSrcModeEnabled = res.getBoolean(R.bool.config_status_bar_scrim_behind_use_src);
        mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll);

        DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER));
        putComponent(StatusBar.class, this);

        // start old BaseStatusBar.start().
        mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
        mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
                Context.DEVICE_POLICY_SERVICE);

        mAccessibilityManager = (AccessibilityManager)
                mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);

        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);

        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
     //StatusBarManagerService,这个服务端在framework中 :base\services\core\java\com\android\server\statusbar
        mBarService = IStatusBarService.Stub.asInterface(
                ServiceManager.getService(Context.STATUS_BAR_SERVICE));

        mRecents = getComponent(Recents.class);//近期任务列表

        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
        mLockPatternUtils = new LockPatternUtils(mContext);//锁屏工具类。密码锁屏,滑动锁屏都会调用这个工具类来解锁。

        mMediaManager.setUpWithPresenter(this, mEntryManager);

        // Connect in to the status bar manager service
        //统筹systemui与mBarService数据交换,方法调用,app设置全屏显示隐藏任务栏,都是通过mCommandQueue来实现的。
        mCommandQueue = getComponent(CommandQueue.class);
        mCommandQueue.addCallbacks(this);


         /* switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1);
            switches[1] = mSystemUiVisibility;
            switches[2] = mMenuVisible ? 1 : 0;
            switches[3] = mImeWindowVis;
            switches[4] = mImeBackDisposition;
            switches[5] = mShowImeSwitcher ? 1 : 0;
            switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2);
            switches[7] = mFullscreenStackSysUiVisibility;
            switches[8] = mDockedStackSysUiVisibility;
            */
            //上面的参数都是通过CommandQueue.Callbacks里面的函数来设置的。因此在systemui初始化的时候都是空或者0
		
        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 {
			//mCommandQueue继承IStatusBar.Stub,mCommandQueue是IStatusBar的BN端,mBarService是BP端
			//向IStatusBarServie进行注册,并获取所有保存在IStatusBarService中的信息
            mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
                    fullscreenStackBounds, dockedStackBounds);
        } catch (RemoteException ex) {
            // If the system process isn't there we're doomed anyway.
        }
     
	  
        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);

        mLockscreenUserManager.setUpWithPresenter(this, mEntryManager);
		//初始化switches 的值
        mCommandQueue.disable(switches[0], switches[6], false /* animate */);
		//systemui 颜色和可见性
        setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
                fullscreenStackBounds, dockedStackBounds);
        topAppWindowChanged(switches[2] != 0);
        // StatusBarManagerService has a back up of IME token and it's restored here.
        //输入法的值
        setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);

        // Set up the initial icon state
        int N = iconSlots.size();
        for (int i=0; i < N; i++) {
            mCommandQueue.setIcon(iconSlots.get(i), icons.get(i));
        }

        // Set up the initial notification state.
        mNotificationListener.setUpWithPresenter(this, mEntryManager);

 
        if (DEBUG) {
            Log.d(TAG, String.format(
                    "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
                   icons.size(),
                   switches[0],
                   switches[1],
                   switches[2],
                   switches[3]
                   ));
        }

        setHeadsUpUser(mLockscreenUserManager.getCurrentUserId());

        IntentFilter internalFilter = new IntentFilter();
        internalFilter.addAction(BANNER_ACTION_CANCEL);
        internalFilter.addAction(BANNER_ACTION_SETUP);
        mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
                null);
				
		//yuanqi add start
	    IntentFilter wifiStatefilter = new IntentFilter();
	    wifiStatefilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
	    mContext.registerReceiver(mWifiStateReceiver, wifiStatefilter);
	    //yuanqi add end
				
				

        IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
                Context.VR_SERVICE));
        try {
            vrManager.registerListener(mVrStateCallbacks);
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed to register VR mode state listener: " + e);
        }

        IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
                ServiceManager.getService(Context.WALLPAPER_SERVICE));
        try {
            wallpaperManager.setInAmbientMode(false /* ambientMode */, false /* animated */);
        } catch (RemoteException e) {
            // Just pass, nothing critical.
        }

        // end old BaseStatusBar.start().

        // Lastly, call to the icon policy to install/update all the icons.
        //设置icon的图标策略类
        mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
		//设置icon的信号图标策略类
        mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController);

        mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
        mUnlockMethodCache.addListener(this);
		//开启锁屏的相关服务
        startKeyguard();

        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
        putComponent(DozeHost.class, mDozeServiceHost);

        mScreenPinningRequest = new ScreenPinningRequest(mContext);
        mFalsingManager = FalsingManager.getInstance(mContext);

        Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);

        Dependency.get(ConfigurationController.class).addCallback(this);
        observerProvision();
    }

上述代码比较长,也进一步验证了StatusBar在整个SystemUI的重要性

主要做了以下几件事:

    1.获取各种服务为后续工作做准备。

   2.建立farmework的联系,把自己注册到StatusBarService中以供其他app使用,这也就是为什么我们能在APP层来控制导航栏和状态栏可见的关键

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

  mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders, fullscreenStackBounds, dockedStackBounds);

  3. 创建StatusBar :createAndAddWindows() ,并且做一些初始化值。

   2.createAndAddWindows

 public void createAndAddWindows() {
        addStatusBarWindow();
    }

    private void addStatusBarWindow() {
        makeStatusBarView();
        mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
        mRemoteInputManager.setUpWithPresenter(this, mEntryManager, this,
                new RemoteInputController.Delegate() {
                    public void setRemoteInputActive(NotificationData.Entry entry,
                            boolean remoteInputActive) {
                        mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
                        entry.row.notifyHeightChanged(true /* needsAnimation */);
                        updateFooter();
                    }
                    public void lockScrollTo(NotificationData.Entry entry) {
                        mStackScroller.lockScrollTo(entry.row);
                    }
                    public void requestDisallowLongPressAndDismiss() {
                        mStackScroller.requestDisallowLongPress();
                        mStackScroller.requestDisallowDismiss();
                    }
                });
        mRemoteInputManager.getController().addCallback(mStatusBarWindowManager);
        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());//把状态栏添加到window上面。
    }

createAndAddWindows其实没有做什么事,只是调用了addStatusBarWindow,而addStatusBarWindow又调用了makeStatusBarView,所以我们猜测makeStatusBarView是做具体事情的方法

3.makeStatusBarView

 //创建状态栏
    protected void makeStatusBarView() {
      //1.初始化资源文件:导航栏高度 状态栏高度 通知面板位置和高度等
        final Context context = mContext;
        updateDisplaySize(); // populates mDisplayMetrics
        updateResources();
        updateTheme();
      //加载layout文件super_status_bar,mStatusBarWindow
        inflateStatusBarWindow(context);
	  if(StatusBar.SYSTEMUI_START_DEBUG)Log.i(StatusBar.TAG_XIAO," makeStatusBarView  mStatusBarWindow getWidth"+mStatusBarWindow.getWidth()
	  	+",getHeight:"+mStatusBarWindow.getHeight());
	  
        mStatusBarWindow.setService(this);
        mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());//设置触摸监听,如果子类没有销毁touch,父类使用
		

        // 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);
        mGutsManager.setUpWithPresenter(this, mEntryManager, mStackScroller, mCheckSaveListener,
                key -> {
                    try {
                        mBarService.onNotificationSettingsViewed(key);
                    } catch (RemoteException e) {
                        // if we're here we're dead
                    }
                });
        mNotificationLogger.setUpWithEntryManager(mEntryManager, mStackScroller);
        mNotificationPanel.setStatusBar(this);
        mNotificationPanel.setGroupManager(mGroupManager);
        mAboveShelfObserver = new AboveShelfObserver(mStackScroller);
        mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
                R.id.notification_container_parent));
        mKeyguardStatusBar = mStatusBarWindow.findViewById(R.id.keyguard_header);//锁屏界面显示

        mNotificationIconAreaController = SystemUIFactory.getInstance()//短信icon控制类
                .createNotificationIconAreaController(context, this);
        inflateShelf();
        mNotificationIconAreaController.setupShelf(mNotificationShelf);
        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
        FragmentHostManager.get(mStatusBarWindow)
                .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
           if(StatusBar.SYSTEMUI_START_DEBUG)Log.i(StatusBar.TAG_XIAO,"makeStatusBarView addTagListener fragment:"+fragment+",tag:"+tag);     
                    CollapsedStatusBarFragment statusBarFragment =
                            (CollapsedStatusBarFragment) fragment;
                    statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);//加载短信通知的icon
                    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();
                    /// M: add for plmn display feature @{
                    attachPlmnPlugin();
                    ///@}
                }).getFragmentManager()
                .beginTransaction()
                .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
                        CollapsedStatusBarFragment.TAG)
                .commit();
        mIconController = Dependency.get(StatusBarIconController.class);

        mHeadsUpManager = new HeadsUpManagerPhone(context, mStatusBarWindow, mGroupManager, this,
                mVisualStabilityManager);
        Dependency.get(ConfigurationController.class).addCallback(mHeadsUpManager);
        mHeadsUpManager.addListener(this);
        mHeadsUpManager.addListener(mNotificationPanel);
        mHeadsUpManager.addListener(mGroupManager);
        mHeadsUpManager.addListener(mVisualStabilityManager);
        mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
        mGroupManager.setHeadsUpManager(mHeadsUpManager);
        putComponent(HeadsUpManager.class, mHeadsUpManager);

        mEntryManager.setUpWithPresenter(this, mStackScroller, this, mHeadsUpManager);
        mViewHierarchyManager.setUpWithPresenter(this, mEntryManager, mStackScroller);

        if (MULTIUSER_DEBUG) {
            mNotificationPanelDebugText = mNotificationPanel.findViewById(R.id.header_debug_info);
            mNotificationPanelDebugText.setVisibility(View.VISIBLE);
        }

        try {
			//创建导航栏
            boolean showNav = mWindowManagerService.hasNavigationBar();
            if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
            if (showNav) {
                createNavigationBar();
            }
        } catch (RemoteException ex) {
            // no window manager? good luck with that
        }
        mScreenPinningNotify = new ScreenPinningNotify(mContext);
        mStackScroller.setLongPressListener(mEntryManager.getNotificationLongClicker());
        mStackScroller.setStatusBar(this);
        mStackScroller.setGroupManager(mGroupManager);
        mStackScroller.setHeadsUpManager(mHeadsUpManager);
        mGroupManager.setOnGroupChangeListener(mStackScroller);
        mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);

        inflateEmptyShadeView();
        inflateFooterView();

        mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);//paint绘制模式
        mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front);
        mBackdropBack = mBackdrop.findViewById(R.id.backdrop_back);

        if (ENABLE_LOCKSCREEN_WALLPAPER) {
            mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
        }
     //layout :keyguard_bottom_area
        mKeyguardIndicationController =
                SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
                        mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
                        mNotificationPanel.getLockIcon());
        mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);


        mAmbientIndicationContainer = mStatusBarWindow.findViewById(
                R.id.ambient_indication_container);

        // set the initial view visibility
        setAreThereNotifications();

        // TODO: Find better place for this callback.
        mBatteryController.addCallback(new BatteryStateChangeCallback() {
            @Override
            public void onPowerSaveChanged(boolean isPowerSave) {
                mHandler.post(mCheckBarModes);
                if (mDozeServiceHost != null) {
                    mDozeServiceHost.firePowerSaveChanged(isPowerSave);
                }
            }

            @Override
            public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
                // noop
            }
        });

        mLightBarController = Dependency.get(LightBarController.class);
        if (mNavigationBar != null) {
            mNavigationBar.setLightBarController(mLightBarController);
        }

        ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind);
        ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front);
        mScrimController = SystemUIFactory.getInstance().createScrimController(
                scrimBehind, scrimInFront, mLockscreenWallpaper,
                (state, alpha, color) -> mLightBarController.setScrimState(state, alpha, color),
                scrimsVisible -> {
                    if (mStatusBarWindowManager != null) {
                        mStatusBarWindowManager.setScrimsVisibility(scrimsVisible);
                    }
                }, DozeParameters.getInstance(mContext),
                mContext.getSystemService(AlarmManager.class));
        if (mScrimSrcModeEnabled) {
            Runnable runnable = () -> {
                boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
                mScrimController.setDrawBehindAsSrc(asSrc);
                mStackScroller.setDrawBackgroundAsSrc(asSrc);
            };
            mBackdrop.setOnVisibilityChangedRunnable(runnable);
            runnable.run();
        }
        mStackScroller.setScrimController(mScrimController);
        mDozeScrimController = new DozeScrimController(mScrimController, context,
                DozeParameters.getInstance(context));

        // Other icons
        mVolumeComponent = getComponent(VolumeComponent.class);

        /// M: Support "Operator plugin - Customize Carrier Label for PLMN" @{
        SIMHelper.setContext(context);
        mStatusBarPlmnPlugin = OpSystemUICustomizationFactoryBase.getOpFactory(context)
                .makeStatusBarPlmn(context);
        if (supportCustomizeCarrierLabel()) {
            mCustomizeCarrierLabel = mStatusBarPlmnPlugin.customizeCarrierLabel(
                    mNotificationPanel, null);
        }
        /// M: Support "Operator plugin - Customize Carrier Label for PLMN" @}

        mNotificationPanel.setUserSetupComplete(mUserSetup);
        if (UserManager.get(mContext).isUserSwitcherEnabled()) {
            createUserSwitcher();
        }

        // Set up the quick settings tile panel
        //面板
        View container = mStatusBarWindow.findViewById(R.id.qs_frame);
        if (container != null) {
            FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
            ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame,
                    Dependency.get(ExtensionController.class)
                            .newExtension(QS.class)
                            .withPlugin(QS.class)
                            .withFeature(PackageManager.FEATURE_AUTOMOTIVE, CarQSFragment::new)
                            .withDefault(QSFragment::new)
                            .build());
            final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
                    mIconController);
            mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow,
                    (visible) -> {
                        mBrightnessMirrorVisible = visible;
                        updateScrimController();
                    });
            fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
                QS qs = (QS) f;
                if (qs instanceof QSFragment) {
                    ((QSFragment) qs).setHost(qsh);
                    mQSPanel = ((QSFragment) qs).getQsPanel();
                    mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
                    mKeyguardStatusBar.setQSPanel(mQSPanel);
                }
            });
        }

        mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch);
        if (mReportRejectedTouch != null) {
            updateReportRejectedTouchVisibility();
            mReportRejectedTouch.setOnClickListener(v -> {
                Uri session = mFalsingManager.reportRejectedTouch();
                if (session == null) { return; }

                StringWriter message = new StringWriter();
                message.write("Build info: ");
                message.write(SystemProperties.get("ro.build.description"));
                message.write("\nSerial number: ");
                message.write(SystemProperties.get("ro.serialno"));
                message.write("\n");

                PrintWriter falsingPw = new PrintWriter(message);
                FalsingLog.dump(falsingPw);
                falsingPw.flush();

                startActivityDismissingKeyguard(Intent.createChooser(new Intent(Intent.ACTION_SEND)
                                .setType("*/*")
                                .putExtra(Intent.EXTRA_SUBJECT, "Rejected touch report")
                                .putExtra(Intent.EXTRA_STREAM, session)
                                .putExtra(Intent.EXTRA_TEXT, message.toString()),
                        "Share rejected touch report")
                                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
                        true /* onlyProvisioned */, true /* dismissShade */);
            });
        }

        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        if (!pm.isScreenOn()) {
            mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
        }
        mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                "GestureWakeLock");
        mVibrator = mContext.getSystemService(Vibrator.class);
        int[] pattern = mContext.getResources().getIntArray(
                R.array.config_cameraLaunchGestureVibePattern);
        mCameraLaunchGestureVibePattern = new long[pattern.length];
        for (int i = 0; i < pattern.length; i++) {
            mCameraLaunchGestureVibePattern[i] = pattern[i];
        }

        // receive broadcasts
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);

        IntentFilter demoFilter = new IntentFilter();
        if (DEBUG_MEDIA_FAKE_ARTWORK) {
            demoFilter.addAction(ACTION_FAKE_ARTWORK);
        }
        demoFilter.addAction(ACTION_DEMO);
        context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
                android.Manifest.permission.DUMP, null);

        // listen for USER_SETUP_COMPLETE setting (per-user)
        mDeviceProvisionedController.addCallback(mUserSetupObserver);
        mUserSetupObserver.onUserSetupChanged();

        // disable profiling bars, since they overlap and clutter the output on app windows
        ThreadedRenderer.overrideProperty("disableProfileBars", "true");

        // Private API call to make the shadows look better for Recents
        ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
    }

上述代码块比较长,里面所包含的信息也比较多,除了状态栏的创建还有下拉菜单的创建。我们现在先讲状态栏的创建。

 1.初始化资源文件,获取状态栏高度,加载statusbar设备树super_status_bar :inflateStatusBarWindow(context),这个设备树的根View是StatusBarWindowView,StatusBarWindowView继承FrameLayout。

2.添加CollapsedStatusBarFragment,这个CollapsedStatusBarFragment就是作为加载状态栏的Fragment

 FragmentHostManager.get(mStatusBarWindow)
                .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {      
                    CollapsedStatusBarFragment statusBarFragment =
                            (CollapsedStatusBarFragment) fragment;
                    statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);//加载短信通知的icon
                    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();
                    /// M: add for plmn display feature @{
                    attachPlmnPlugin();
                    ///@}
                }).getFragmentManager()
                .beginTransaction()
                .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
                        CollapsedStatusBarFragment.TAG)
                .commit();

4.CollapsedStatusBarFragment

     到CollapsedStatusBarFragment才算状态栏的开始,那么我们思考一下,状态图标是是怎样被加载到状态栏上,数据又如何获取的,搞明白这两个问题,状态栏的流程基本也就清楚了

我们先来看看CollapsedStatusBarFragment做了什么东西。熟悉Fragment的都清楚Fragment的加载流程onCreateView会加载layout,因此我们在oncreate中找到如下代码

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            Bundle savedInstanceState) {
        return inflater.inflate(R.layout.status_bar, container, false);
    }

 

status_bar.xml的文件

<com.android.systemui.statusbar.phone.PhoneStatusBarView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
    android:layout_width="match_parent"
    android:layout_height="@dimen/status_bar_height"
    android:id="@+id/status_bar"
    android:background="@drawable/system_bar_background"
    android:orientation="vertical"
    android:focusable="false"
    android:descendantFocusability="afterDescendants"
    android:accessibilityPaneTitle="@string/status_bar"
    >

    <ImageView
        android:id="@+id/notification_lights_out"
        android:layout_width="@dimen/status_bar_icon_size"
        android:layout_height="match_parent"
        android:paddingStart="@dimen/status_bar_padding_start"
        android:paddingBottom="2dip"
        android:src="@drawable/ic_sysbar_lights_out_dot_small"
        android:scaleType="center"
        android:visibility="gone"
        />

    <LinearLayout android:id="@+id/status_bar_contents"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingStart="@dimen/status_bar_padding_start"
        android:paddingEnd="@dimen/status_bar_padding_end"
        android:orientation="horizontal"
        >
        <ViewStub
            android:id="@+id/operator_name"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            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 -->
            <LinearLayout
                android:id="@+id/status_bar_left_side"
                android:layout_height="match_parent"
                android:layout_width="match_parent"
                android:clipChildren="false"
            >
                <com.android.systemui.statusbar.policy.Clock
                    android:id="@+id/clock"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:textAppearance="@style/TextAppearance.StatusBar.Clock"
                    android:singleLine="true"
                    android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
                    android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
                    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_width="wrap_content"
        android:layout_height="match_parent"
        android:layout="@layout/emergency_cryptkeeper_text"
    />

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

上面的layout还是蛮多内容,但是我们只看三点:

1.根View :StatusBarWindowView,这个是一个继承FrameLayout的View。所以能比较初步的知道这个子View的界面的加载流程

2.@+id/status_bar_contents 这个LinearLayout,里面包含了@+id/status_bar_left_side  ,从名字来看就知道是状态栏左边部分。这个状态栏左边部分包含了时钟@+id/clock和短信通知@+id/notification_icon_area,这个我们在开始的是有说过。

3.@+id/system_icon_area这个也是一个LinearLayout包含了@layout/system_icons,这部分就是状态栏右边部分,里面包含了电池图标和系统状态图标

<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"/>

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

   从上面的代码我们能猜测出来,不管是系统状态图标还是短信通知图标都是动态加载,那我们就需要了解它是如何加载的,数据是如何获取的?

 

5.@+id/notification_icon_area 左边短信通知的添加流程

我们先来看看短信通知是的view结构加载过程。

 public void initNotificationIconArea(NotificationIconAreaController
            notificationIconAreaController) {
        ViewGroup notificationIconArea = mStatusBar.findViewById(R.id.notification_icon_area);//短信通知icon
        mNotificationIconAreaInner =
                notificationIconAreaController.getNotificationInnerAreaView();
		//移除自己,再添加自己
        if (mNotificationIconAreaInner.getParent() != null) {
            ((ViewGroup) mNotificationIconAreaInner.getParent())
                    .removeView(mNotificationIconAreaInner);
        }
        notificationIconArea.addView(mNotificationIconAreaInner);
        // Default to showing until we know otherwise.
        showNotificationIconArea(false);
    }

如果熟悉View的添加流程很容易看懂上面代码的含义,先移除notificationIconArea上面的子view,然后再添加mNotificationIconAreaInner。

我们需要搞清的是NotificationIconAreaController这个类是做什么的?

   mNotificationIconAreaInner又是一个什么样的view?以及initNotificationIconArea这个方法在哪里被调用。

initNotificationIconArea是在StatusBar中添加CollapsedStatusBarFragment 中被调用:statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);

NotificationIconAreaController:这个类主要是用于短信icon的控制类。

mNotificationIconAreaInner是通过加载notification_icon_area而生成的view如下代码:

protected View inflateIconArea(LayoutInflater inflater) {
        return inflater.inflate(R.layout.notification_icon_area, null);
    }

layout.notification_icon_area 如下代码

<com.android.keyguard.AlphaOptimizedLinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/notification_icon_area_inner"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false">
    <com.android.systemui.statusbar.phone.NotificationIconContainer
        android:id="@+id/notificationIcons"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentStart="true"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:clipChildren="false"/>
</com.android.keyguard.AlphaOptimizedLinearLayout>

看到这边好像我们还没看到短信icon被添加的具体代码,先不急,我们先看看数据是如何获取的。

NotificationListener这个类监听notification,至于为什么这个类能监听到短信变化。是因为它继承了NotificationListenerService

每次系统短信变化的时候会回调onNotificationPosted

  public void onNotificationPosted(final StatusBarNotification sbn,
            final RankingMap rankingMap) {
        if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);	
        if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
            mPresenter.getHandler().post(() -> {
                processForRemoteInput(sbn.getNotification(), mContext);
                String key = sbn.getKey();
                mEntryManager.removeKeyKeptForRemoteInput(key);
                boolean isUpdate =
                        mEntryManager.getNotificationData().get(key) != null;
                // In case we don't allow child notifications, we ignore children of
                // notifications that have a summary, since` we're not going to show them
                // anyway. This is true also when the summary is canceled,
                // because children are automatically canceled by NoMan in that case.
                if (!ENABLE_CHILD_NOTIFICATIONS
                        && mPresenter.getGroupManager().isChildInGroupWithSummary(sbn)) {
                    if (DEBUG) {
                        Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
                    }

                    // Remove existing notification to avoid stale data.
                    if (isUpdate) {
                        if (DEBUG) Log.d(TAG, "onNotificationPosted, removeNotification: " + sbn);
                        mEntryManager.removeNotification(key, rankingMap);
                    } else {
                        if (DEBUG) Log.d(TAG, "onNotificationPosted, updateRanking: " + sbn);
                        mEntryManager.getNotificationData()
                                .updateRanking(rankingMap);
                    }
                    return;
                }
							
                if (isUpdate) {
                    mEntryManager.updateNotification(sbn, rankingMap);
                } else {
                    mEntryManager.addNotification(sbn, rankingMap);
                }
            });
        }
    }

短信icon第一次添加都systemui会走NotificationEntryManager.addNotification

 public void addNotification(StatusBarNotification notification,
            NotificationListenerService.RankingMap ranking) {
        try {			
            addNotificationInternal(notification, ranking);
			
        } catch (InflationException e) {
            handleInflationException(notification, e);
        }
    }
  private void addNotificationInternal(StatusBarNotification notification,
            NotificationListenerService.RankingMap ranking) throws InflationException {
        String key = notification.getKey();
        if (CHATTY) Log.d(TAG, "addNotification key=" + key);

        mNotificationData.updateRanking(ranking);
 if(StatusBar.SYSTEMUI_START_DEBUG)Log.i(StatusBar.TAG_XIAO,"NotificationEntryManager addNotificationInternal   StatusBarNotification:"+ notification.toString());			
        NotificationData.Entry shadeEntry = createNotificationViews(notification);
        boolean isHeadsUped = shouldPeek(shadeEntry);
        if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
            if (shouldSuppressFullScreenIntent(shadeEntry)) {
                if (CHATTY) {
                    Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + key);
                }
            } else if (mNotificationData.getImportance(key)
                    < NotificationManager.IMPORTANCE_HIGH) {
                if (CHATTY) {
                    Log.d(TAG, "No Fullscreen intent: not important enough: "
                            + key);
                }
            } else {
                // Stop screensaver if the notification has a fullscreen intent.
                // (like an incoming phone call)
                SystemServicesProxy.getInstance(mContext).awakenDreamsAsync();

                // not immersive & a fullscreen alert should be shown
                if (CHATTY)
                    Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
                try {
                    EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
                            key);
                    notification.getNotification().fullScreenIntent.send();
                    shadeEntry.notifyFullScreenIntentLaunched();
                    mMetricsLogger.count("note_fullscreen", 1);
                } catch (PendingIntent.CanceledException e) {
                }
            }
        }
        abortExistingInflation(key);

        mForegroundServiceController.addNotification(notification,
                mNotificationData.getImportance(key));

        mPendingNotifications.put(key, shadeEntry);
        mGroupManager.onPendingEntryAdded(shadeEntry);
    }
 protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn)
            throws InflationException {
        if (CHATTY) {
            Log.d(TAG, "createNotificationViews(notification=" + sbn);
        }
 	
        NotificationData.Entry entry = new NotificationData.Entry(sbn);
        Dependency.get(LeakDetector.class).trackInstance(entry);
        entry.createIcons(mContext, sbn);
        // Construct the expanded view.
        //创建下来短信通知信息
        inflateViews(entry, mListContainer.getViewParentForNotification(entry));
        return entry;
    }

 从上面的三个方法来看主要工作是:1.StatusBarNotification 里面的信息转换成NotificationData.Entry,并且创建通知icon的显示View。这个View是StatusBarIconView继承imageView。

                                                          2.绑定一些监听,比如移除监听。

                                                          3.把新添加的信息保持在mPendingNotifications,这个集合保持了所有显示的通知icon

 

NotificationEntryManager.updateNotification

  public void updateNotification(StatusBarNotification notification,
            NotificationListenerService.RankingMap ranking) {
        try {
            updateNotificationInternal(notification, ranking);
        } catch (InflationException e) {
            handleInflationException(notification, e);
        }
    }

 updateNotificationInternal里面内容很多,我们就不细看,看跟View显示有关的内容:updateNotifications

  public void updateNotifications() {
        mNotificationData.filterAndSort();

        mPresenter.updateNotificationViews();
    }

mPresenter是NotificationPresenter的实例,NotificationPresenter是一个接口,那边我们就需要找到它的实现类是在哪里,它的实现类是StatusBar。

StatusBar.updateNotificationViews

 public void updateNotificationViews() {
        // The function updateRowStates depends on both of these being non-null, so check them here.
        // We may be called before they are set from DeviceProvisionedController's callback.
        if (mStackScroller == null || mScrimController == null) return;

        // Do not modify the notifications during collapse.
        if (isCollapsing()) {
            addPostCollapseAction(this::updateNotificationViews);
            return;
        }

        mViewHierarchyManager.updateNotificationViews();

        updateSpeedBumpIndex();
        updateFooter();
        updateEmptyShadeView();

        updateQsExpansionEnabled();

        // Let's also update the icons
        mNotificationIconAreaController.updateNotificationIcons();
    }

mNotificationIconAreaController这个实例就是我们前面介绍的icon的管理了。

NotificationIconAreaController.updateNotificationIcons

 public void updateNotificationIcons() {

        updateStatusBarIcons();
        updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
                NotificationShelf.SHOW_AMBIENT_ICONS, false /* hideDismissed */,
                false /* hideRepliedMessages */);

        applyNotificationIconsTint();
    }
public void updateStatusBarIcons() {
        updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
                false /* showAmbient */, true /* hideDismissed */, true /* hideRepliedMessages */);
    }
  private void updateIconsForLayout(Function<NotificationData.Entry, StatusBarIconView> function,
            NotificationIconContainer hostLayout, boolean showAmbient, boolean hideDismissed,
            boolean hideRepliedMessages) {
        ArrayList<StatusBarIconView> toShow = new ArrayList<>(
                mNotificationScrollLayout.getChildCount());
		//if(StatusBar.SYSTEMUI_START_DEBUG)Log.i(StatusBar.TAG_XIAO,"NotificationIconAreaController updateIconsForLayout hostLayout.getChildCount():"+hostLayout.getChildCount()+", mNotificationScrollLayout.getChildCount():"+ mNotificationScrollLayout.getChildCount());

        // Filter out ambient notifications and notification children.
        for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) {
            View view = mNotificationScrollLayout.getChildAt(i);
            if (view instanceof ExpandableNotificationRow) {
                NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry();
			//	if(StatusBar.SYSTEMUI_START_DEBUG)Log.i(StatusBar.TAG_XIAO,"NotificationIconAreaController updateIconsForLayout ent key:"+ent.key+" notification:"+ent.notification);
                if (shouldShowNotificationIcon(ent, showAmbient, hideDismissed,
                        hideRepliedMessages)) {
                    toShow.add(function.apply(ent));
                }
            }
        }

        // In case we are changing the suppression of a group, the replacement shouldn't flicker
        // and it should just be replaced instead. We therefore look for notifications that were
        // just replaced by the child or vice-versa to suppress this.

        ArrayMap<String, ArrayList<StatusBarIcon>> replacingIcons = new ArrayMap<>();
        ArrayList<View> toRemove = new ArrayList<>();
		
        for (int i = 0; i < hostLayout.getChildCount(); i++) {
            View child = hostLayout.getChildAt(i);
            if (!(child instanceof StatusBarIconView)) {
                continue;
            }
            if (!toShow.contains(child)) {
                boolean iconWasReplaced = false;
                StatusBarIconView removedIcon = (StatusBarIconView) child;
                String removedGroupKey = removedIcon.getNotification().getGroupKey();
                for (int j = 0; j < toShow.size(); j++) {
                    StatusBarIconView candidate = toShow.get(j);
                    if (candidate.getSourceIcon().sameAs((removedIcon.getSourceIcon()))
                            && candidate.getNotification().getGroupKey().equals(removedGroupKey)) {
                        if (!iconWasReplaced) {
                            iconWasReplaced = true;
                        } else {
                            iconWasReplaced = false;
                            break;
                        }
                    }
                }
                if (iconWasReplaced) {
                    ArrayList<StatusBarIcon> statusBarIcons = replacingIcons.get(removedGroupKey);
                    if (statusBarIcons == null) {
                        statusBarIcons = new ArrayList<>();
                        replacingIcons.put(removedGroupKey, statusBarIcons);
                    }
                    statusBarIcons.add(removedIcon.getStatusBarIcon());
                }
                toRemove.add(removedIcon);
            }
        }
        // removing all duplicates
        ArrayList<String> duplicates = new ArrayList<>();
        for (String key : replacingIcons.keySet()) {
            ArrayList<StatusBarIcon> statusBarIcons = replacingIcons.get(key);
            if (statusBarIcons.size() != 1) {
                duplicates.add(key);
            }
        }
        replacingIcons.removeAll(duplicates);
        hostLayout.setReplacingIcons(replacingIcons);

        final int toRemoveCount = toRemove.size();
        for (int i = 0; i < toRemoveCount; i++) {
            hostLayout.removeView(toRemove.get(i));
        }

        final FrameLayout.LayoutParams params = generateIconLayoutParams();
        for (int i = 0; i < toShow.size(); i++) {
            StatusBarIconView v = toShow.get(i);
            // The view might still be transiently added if it was just removed and added again
            hostLayout.removeTransientView(v);
            if (v.getParent() == null) {
                if (hideDismissed) {
                    v.setOnDismissListener(mUpdateStatusBarIcons);
                }
                hostLayout.addView(v, i, params);
            }
        }

        hostLayout.setChangingViewPositions(true);
        // Re-sort notification icons
        final int childCount = hostLayout.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View actual = hostLayout.getChildAt(i);
            StatusBarIconView expected = toShow.get(i);
            if (actual == expected) {
                continue;
            }
            hostLayout.removeView(expected);
            hostLayout.addView(expected, i);
        }
        hostLayout.setChangingViewPositions(false);
        hostLayout.setReplacingIcons(null);
    }

  从上面的代码不难看出updateIconsForLayout含税会把StatusBarIconView添加到NotificationIconContainer这个ViewGroup中,而NotificationIconContainer依据前面的分析是挂载在左边短信通知区域。到现在整个的通知信息加载流程算梳理完成。

 

6.@+id/system_icon_area系统icon的加载

  CollapsedStatusBarFragment.onViewCreated

 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mStatusBar = (PhoneStatusBarView) view;
        if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) {
            mStatusBar.go(savedInstanceState.getInt(EXTRA_PANEL_STATE));
        }
		//layout:system_icons  view:StatusIconContainer 是LinearLayout
		//DarkIconManager是一个对icon管理类。管理StatusBarIconView
        mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
        mDarkIconManager.setShouldLog(true);
        Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
        mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);//系统icon父类LinearLayout
        mClockView = mStatusBar.findViewById(R.id.clock);//时间icon
        showSystemIconArea(false);
        showClock(false);
        initEmergencyCryptkeeperText();
        initOperatorName();
    }

上述代码中我们需要比较关注的代码是:

mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons))

Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);

R.id.statusIcons这个其实是在system_icons.xml里面的StatusIconContainer,这个View是一个LinearLayout。

DarkIconManager是StatusBarIconController的一个内部类,DarkIconManager extends IconManager。IconManager这个类里面做的事情是创建StatusBarIconView,部分代码如下

  protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
                StatusBarIconHolder holder) {
            switch (holder.getType()) {
                case TYPE_ICON:
                    return addIcon(index, slot, blocked, holder.getIcon());

                case TYPE_WIFI:
                    return addSignalIcon(index, slot, holder.getWifiState());

                case TYPE_MOBILE:
                    return addMobileIcon(index, slot, holder.getMobileState());
            }

            return null;
        }

        @VisibleForTesting
        protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
                StatusBarIcon icon) {
            StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
            view.set(icon);
            mGroup.addView(view, index, onCreateLayoutParams());
            return view;
        }

上述代码来看也只是把StatusIconContainer保存到IconManager里面,到时候把子View的添加到StatusIconContainer。

是什么时候把子view添加到StatusIconContainer呢?

在StatusBar中有这两行代码

  mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
        //设置icon的信号图标策略类
    mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController);

从名字我们大概能猜到PhoneStatusBarPolicy是除了信号的状态Icon的所有系统Icon。而信号的icon就由StatusBarSignalPolicy来做初始化添加。

PhoneStatusBarPolicy

  //eMBMS status
        mIconController.setIcon(mSlotEmbms, R.drawable.stat_sys_embms, null);
        mIconController.setIconVisibility(mSlotEmbms, false);


        // Alarm clock
        mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);
        mIconController.setIconVisibility(mSlotAlarmClock, false);

        // zen
        mIconController.setIcon(mSlotZen, R.drawable.stat_sys_zen_important, null);
        mIconController.setIconVisibility(mSlotZen, false);

        // volume
        mIconController.setIcon(mSlotVolume, R.drawable.stat_sys_ringer_vibrate, null);
        mIconController.setIconVisibility(mSlotVolume, false);
        updateVolumeZen();

        // cast
        mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null);
        mIconController.setIconVisibility(mSlotCast, false);

        // hotspot
        mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
                mContext.getString(R.string.accessibility_status_bar_hotspot));
        mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled());

        // managed profile
        mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status,
                mContext.getString(R.string.accessibility_managed_profile));
        mIconController.setIconVisibility(mSlotManagedProfile, mManagedProfileIconVisible);

        // data saver
        mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver,
                context.getString(R.string.accessibility_data_saver_on));
        mIconController.setIconVisibility(mSlotDataSaver, false);

StatusBarIconControllerImpl

 public void setIcon(String slot, int resourceId, CharSequence contentDescription) {
    
        int index = getSlotIndex(slot);
        StatusBarIconHolder holder = getIcon(index, 0);
	if(StatusBar.SYSTEMUI_START_DEBUG)Log.i(StatusBar.TAG_XIAO,"StatusBarIconControllerImpl setIcon slot:"+slot+",index:"+index+",holder:"+holder);	
        if (holder == null) {
            StatusBarIcon icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
                    Icon.createWithResource(
                            mContext, resourceId), 0, 0, contentDescription);
            holder = StatusBarIconHolder.fromIcon(icon);
            setIcon(index, holder);
        } else {
            holder.getIcon().icon = Icon.createWithResource(mContext, resourceId);
            holder.getIcon().contentDescription = contentDescription;
            handleSet(index, holder);
        }
		
    }
 public void setIcon(int index, @NonNull StatusBarIconHolder holder) {
        boolean isNew = getIcon(index, holder.getTag()) == null;
        super.setIcon(index, holder);

        if (isNew) {
            addSystemIcon(index, holder);
        } else {
            handleSet(index, holder);
        }
    }
private void addSystemIcon(int index, StatusBarIconHolder holder) {
        String slot = getSlotName(index);
        int viewIndex = getViewIndex(index, holder.getTag());
        boolean blocked = mIconBlacklist.contains(slot);

        mIconLogger.onIconVisibility(getSlotName(index), holder.isVisible());
        mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, blocked, holder));
    }
  protected void onIconAdded(int index, String slot, boolean blocked,
                StatusBarIconHolder holder) {
            StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
            mDarkIconDispatcher.addDarkReceiver((DarkReceiver) view);
        }
 protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
                StatusBarIconHolder holder) {
            switch (holder.getType()) {
                case TYPE_ICON:
                    return addIcon(index, slot, blocked, holder.getIcon());

                case TYPE_WIFI:
                    return addSignalIcon(index, slot, holder.getWifiState());

                case TYPE_MOBILE:
                    return addMobileIcon(index, slot, holder.getMobileState());
            }

            return null;
        }

    @VisibleForTesting
  protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
                StatusBarIcon icon) {
            StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
            view.set(icon);
            mGroup.addView(view, index, onCreateLayoutParams());
            return view;
        }

从上面的代码不难看出最后会调用addIcon,创建一个StatusBarIconView 添加到mGroup,而mGroup就是我们在所提到的R.id.statusIcons,也就是StatusIconContainer。到现在系统icon就添加到状态栏右边了。

状态栏流程的研究到此为止

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android SystemUI之StatusBar,状态栏(二) 的相关文章

  • 在 Android 上将视频设置为壁纸

    我想知道如何将视频设置为壁纸 否则不可能 我可以将图像设置为壁纸 并且可以构建动态壁纸 但无法将视频设置为壁纸 所以有人知道我该怎么做吗 提前致谢 我认为唯一可以做到的方法是将其合并到 动态壁纸 中 缺点是正如其他人提到的那样 这会严重影响
  • Android:动态更改Listview中的图像

    我有一个由以下 xml 定义的列表视图 我需要切换图像当用户单击任何行时 在运行时会出现在列表中 我怎样才能实现这个目标 非常感谢任何帮助 谢谢 list item xml
  • 如何增加 Gradle 守护进程的最大堆大小?

    签署 apk 时 我收到以下消息 To run dex in process the Gradle daemon needs a larger heap It currently has 1024 MB For faster builds
  • 强制关闭导致HTTP实体可能不为空

    这里是发送数据 Http 的完整代码 asynctask private class MyAsyncTaskPupuk extends AsyncTask
  • android studio更新到3.0后任务执行失败

    当我更新 Android Studio 3 0 时 出现错误 unable to merge with dex 然后我添加了mutiDexEnabled true并且还添加了com android support multidex 1 0
  • 意图过滤器到底是什么?

    我读过很多关于意图过滤器的文章 但我真的无法理解它们到底是做什么的 那么 如果有人可以用一个清晰 的例子向我解释意图过滤器的作用到底是什么 thanks 我认为这是有据可查的here http developer android com g
  • Android/java:从 ProGuard 过渡/迁移到 R8?

    我想知道如何从ProGuard to R8 我是否应该从 Gradle 文件中删除与 Proguard 相关的行并添加android enableR8 true线代替 Thanks Proguard 由 GuardSquare 开发和维护
  • Firebase 云消息传递 - 如何验证令牌?

    我正在使用 Firebase Cloud Messaging FCM 并且每次在客户设备上生成新令牌时 都会根据下面的缩写代码 我将此新令牌发送到我的服务器数据库 云 并将其保存在其中 以便能够发送未来推送通知使用 CFM API 从服务器
  • 按钮上方带有文本的单选按钮

    我是 Android 新手 我需要在我的活动中添加单选按钮 但我需要将文本放在项目符号按钮的顶部 请提供任何帮助 我发现了以下内容 尽管我不明白 drawable in 选择器和 style Tab 样式是什么 顶部带有文本的单选按钮 ht
  • 如何修复运行 Android 模拟器时出现 GPU Driver Issue 错误

    我的 Android 模拟器几周前运行良好 但现在出现错误 当我运行代码时 GPU 驱动程序问题错误对话框与模拟器一起弹出 当我单击 确定 时 Android 模拟器不会按预期运行应用程序 错误如下 Your GPU driver info
  • Android Studio 停留在构建 gradle 项目信息上

    我正在使用 Android Studio 2 3 每当我尝试创建一个新项目或打开某个项目时 它都会卡在此时 正在构建 Gradle 项目信息 请建议我一些解决方案 它可能正在下载 Gradle zip 文件 e g Users user g
  • 通过覆盖滑动调整图像大小不会调整图像大小

    我在用着Glide下载并显示图像 但是 当我尝试调整图像大小时 它不会这样做 我得到随机大小 或者可能是图像的实际大小 这是我用于通过 Glide 加载的代码 Glide with context load file getUrl asBi
  • Android TabLayout:均匀分布

    我正在查看 Google IO 中使用的 Google 类 称为 SlidingTabLayout 在该类中 有一个名为 setDistributeEvenly 的方法 它允许所有这些选项卡在屏幕上均匀分布 每个选项卡具有相同的大小 中心对
  • 无法在 Android 中使用自定义数组适配器进行搜索?

    我无法从以下位置搜索listview 我尝试了各种方法 但它对我不起作用 没有错误 我有其他方式进行搜索 但我想让这种方式成为可能 这是代码 public class MainActivity extends Activity implem
  • toArray 与预先确定大小的数组

    使用时ar toArray new String ar size 安卓工作室3 2 1警告预先确定大小的数组并建议空数组 有两种方式将集合转换为数组 使用 预先确定大小的数组 如 c toArray new String c size 或使
  • 特定铃声 firebase 通知 xamarin.android

    How i can force the push notification to run ringtone instead of default notification sound is there any way to ovveride
  • 调用属于Fragment的Activity的函数

    我正在与多个Fragments在 Android 下 我对如何从嵌入式应用程序发送和接收数据感到困惑 为了简单的解释 我有一个ListFragment and a MapFragment使用解释的方法here https stackover
  • 测试应用内结算:“发布者无法购买此商品”

    我的应用程序似乎已准备好在我的设备上进行应用内购买程序的 现实生活 测试 但是 我在 Play 商店中收到 发布商无法购买此商品 的错误消息 现在 我应该如何测试这个 我不想通过仅用于测试的虚拟帐户重新安装手机来丢失手机的配置 在开发者控制
  • Android 报告“Error=Unable to find Instrumentation info for: ComponentInfo {}”

    stackoverflow 上有很多关于这个问题的主题 问题 例如错误 无法找到以下仪器信息 ComponentInfo https stackoverflow com q 21294945 513413 和其他网站 但使我的问题与其他网站
  • 活动构建变体没有测试工件

    我基于 调试 构建变体创建了一个名为 bitrise 的新构建类型 使用 debug 构建变体时 经过检测的 androidTests 构建并运行良好 但是当我切换到新的 bitrise 构建变体时 出现以下错误 Process finis

随机推荐

  • MISRA C_2012规则翻译、解读、示例

    目录 一 MISRA C 2012介绍 二 MISRA C 2012每条规则翻译 解读 示例 Rule 1系列 标准C环境准则 Rule 1 1 程序不应包含任何违反标准C语法和约束的内容 也不应超过实现的转换限制 Rule 1 2 不应使
  • 表结构设计的基本思路

    首先在开启一个项目时 至关重要的第一步就是设计表结构 很多小伙伴在初入职场的时候找不清如何下手只是感觉很乱 那么今天我提供几个基本的思路 切入点 找到一个主表 比如你要设计一个某某产品的的管理系统 那么ok这张产品表就是我们的主表 它作为主
  • 调试的艺术——Debug技巧总结

    调试的艺术 Debug技巧总结 本文从写好的wiki里粘出来的 格式稍乱不影响阅读 用Q 编号代表问题 A 编号代表答案 用这种方式组织 如无特别说明 这些技巧都是针对Visual Studio 2003的 汇编级的问题我作为一个逻辑程序只
  • React的ref获取dom元素

    react 声名式开发 可以和其他框架并存 组件化 单向数据流 即父组件可以改变子组件的数据 但是子组件一定不能直接改变父组件的数据 必须调用父组件的方法来改变父组件的数据 视图层框架 函数式编程 Props State与render函数
  • Driftnet学习笔记

    Driftnet学习笔记 工具介绍 driftnet是一款简单而使用的图片捕获工具 可以很方便的在网络数据包中抓取图片 这次用到这个工具的原因是与 ettercap 相配合 抓去被害人浏览的图片 此篇应与 ettercap ARP欺骗相互配
  • 基于SSM的网上购物商城管理系统

    项目背景 随着科技的飞速发展 计算机已经广泛的应用于各行各业当中 而且日趋普及 在各个领域内 计算机的应用已经十分广泛 各种智能设备都与计算机紧密结合在一起 主要应用于两个方面 一是以设备为主 另一种是软件的建设 以提高网上购物商城的形象
  • TP-LINK-TL-WR703N(原装)制作打印服务器过程记录整理

    目录 1 前言 2 路由器介绍 3 刷入Breed 4 通过breed刷入openwrt 4 1 进入Breed控制台 4 2 刷入openwt 4 3 openwrt设置中文的问题 5 openwrt安装打印的相关package并配置 6
  • 解决一次window下装包错误, “Can‘t find Python executable “python“, you can set the PYTHON env variable.“

    最近在写项目时遇到一个兼容性问题 需要在window上调试 由于多年不用window 在装环境时遇到一些问题 记录一下 在window系统上使用npm install 报错信息如下 1 安装cnpm 并添加镜像 npm install g
  • sublime设置右键在浏览器打开

    用sublime编辑html文件 右键此文件 自带一个在浏览器中打开 但是这个是在IE里打开 如何在chrome里打开呢 1 这里插入一下安装 view in browser 官方版的说明 前提是得先安装package control插件
  • Matlab基础

    Matlab基础 对matlab的字体大小进行调整 计算基础 程式语言与函数 绘图基础 对matlab的字体大小进行调整 首先打开matlab软件 进入matlab页面 点击预设 进入预设后 点击字体 gt 自定义 然后就能设置字体大小了
  • 【技巧】学术Poster的制作要点,详细!

    转载请注明出处 小锋学长生活大爆炸 xfxuezhang cn 内容零零散散均收集自网上 有点杂忘了引用 内容技巧 https posts careerengine us p 5dac3e628c131b0541dd9171 展示内容包括
  • windows上使用QT creator运行cuda程序的pro配置

    在Windows上用qt写界面 需要用到cuda windows上qt配置cuda花了很长时间 现在分享出来 windows上Qt Creator配置cuda与linux上大同小异 QT core TEMPLATE app CONFIG c
  • html引入elementui使用表格组件表头和内容都挤在一列问题

    在单html文件中CDN引入vue 引入elementUI后使用table表格组件时发现表头和内容都挤在一列 代码写的没问题 可是样式出了问题 elementui的css文件也引入了 其实是这里需要结尾标签 如下图 上面的写法在vue文件中
  • Kubernetes(K8S)单机版部署

    1 虚拟机部署Kubernetes K8S 生骨大头菜的博客 CSDN博客 首先按照这里部署好k8s服务 但是只需要部署一台master服务器就可以 2 默认k8s的master节点是不能跑pod的业务 需要执行以下命令解除限制 将mast
  • 手表电池过放后不能充电

    作者 AirCity 2020 3 1 Aircity007 sina com 本文所有权归作者Aircity所有 1 问题描述 有一批机器 放在工厂半年后 才开始出货 拆箱抽检 发现部分机器已经不能开机 电池完全没电 这些机器中 有一些机
  • HiveSQL一天一个小技巧:如何统计当前时间点状态情况【辅助变量+累计变换思路】

    0 需求描述 1 问题分析 目标 需要求出每个时间段 有客人在住的房间数量 如果只考虑一人一房 我们可以借助于同时在线人数统计的思路 入住时间加辅助标记记为1 离店时间加辅助标记记为 1 并按照时间进行顺序排序 求当前累计值 具体SQL如下
  • mysql知识系列:报错right syntax to use near IDENTIFIED BY

    总结 新版的的mysql版本将创建账户和赋予权限的方式分开 需要先创建账户 再赋予权限 参考 https blog csdn net vin 1991216 article details 82632710
  • 校园网服务器系统需求分析,校园网的网络系统集成建设需求分析的主要工作

    下面以某校园网的网络系统集成建设为例 具体介绍在校园网建设中需求分析的主要工作 一 了解用户的基本情况 1 学校目前有教学楼4座 宿舍楼2座 图书馆1座 食堂1座 计算机中心1处 综合楼1座 人员约6000人 2 该校园网主要应用于学校内部
  • Windows下安装mysql-5.7.34的方法

    1 下载mysql 5 7 34 从mysql官网下载mysql 5 7 34 winx64 zip并解压到合适的位置 以D server mysql5 7 34 x64为例 2 创建配置文件my ini 创建文件D server mysq
  • Android SystemUI之StatusBar,状态栏(二)

    Android SystemUI系列 1 Android SystemUI之启动流程 一 2 Android SystemUI之StatusBar 状态栏 二 3 Android SystemUI之下拉菜单 通知栏 快捷面板 三 4 And