Android SystemUI之StatusBar,状态栏(二)

您所在的位置:网站首页 状态栏位于哪里 Android SystemUI之StatusBar,状态栏(二)

Android SystemUI之StatusBar,状态栏(二)

2024-07-15 17:18:52| 来源: 网络整理| 查看: 265

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 binders = new ArrayList(); ArrayList iconSlots = new ArrayList();//图标名称 ArrayList 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的文件

上面的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,这部分就是状态栏右边部分,里面包含了电池图标和系统状态图标

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

 

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 如下代码

看到这边好像我们还没看到短信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 function, NotificationIconContainer hostLayout, boolean showAmbient, boolean hideDismissed, boolean hideRepliedMessages) { ArrayList 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 replacingIcons = new ArrayMap(); ArrayList 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 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 duplicates = new ArrayList(); for (String key : replacingIcons.keySet()) { ArrayList 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就添加到状态栏右边了。

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



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭