当前位置:   article > 正文

Android12 源码分析 SystemUI 学习(3) --- Notification(1/2)_android 12源码

android 12源码

前言:如果说StatusBar是代码最多最重要的一个,那Notification是使用最多,最广泛的一个。这节主要讲通知栏相关的服务和组件控制器是如何构建的。

NotificationBar的创建过程

SystemUI学习篇(2)中,已经了解过StatusBar的启动过程等。其中也提到了,通知栏,导航栏以及锁屏界面都在StatusBar里有相关的启动操作。

关于NotificationBar初始化

  • StatusBar中有一个启动过程 start() -> createAndAddWindows() -> makeStatusBarView() -> inflateStatusBarWindow(),在inflateStatusBarWindow()方法中就涉及到了通知栏的一些视图的创建。
  • 在inflateStatusBarWindow()中完成一些变量数据初始化后,回到makeStatusBarView()执行一些设置服务、视图填充和Controller绑定操作。然后继续在createAndAddWindows()中执行NotificationShadeWindowController的attach()方法,以及start()方法中的setUpPresenter()。

部分与通知栏相关代码:

public class StatusBar extends SystemUI implements /*代码省略*/ {

    @Override
    public void start() {
    	//...代码省略...	
    	createAndAddWindows(result);
    	//...代码省略...
        // Set up the initial notification state. This needs to happen before CommandQueue.disable()
        setUpPresenter();
    }

    public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
        makeStatusBarView(result);//调用后续方法初始化
        mNotificationShadeWindowController.attach();//初始化完成后执行
        //...代码省略...
    }

   protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
       //...代码省略...
       inflateStatusBarWindow();
       
       mNotificationShadeWindowViewController.setService(this, mNotificationShadeWindowController);
       mNotificationShadeWindowView.setOnTouchListener(getStatusBarWindowTouchListener());
       mWallpaperController.setRootView(mNotificationShadeWindowView);
       
       // 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.
       NotificationListContainer notifListContainer =
               mStackScrollerController.getNotificationListContainer();
       mNotificationLogger.setUpWithContainer(notifListContainer);

       mNotificationIconAreaController.setupShelf(mNotificationShelfController);
       mPanelExpansionStateManager.addExpansionListener(mWakeUpCoordinator);

       mUserSwitcherController.init(mNotificationShadeWindowView);
       //...代码省略...
       mStatusBarWindowController.getFragmentHostManager()
                .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                    //...代码省略
                    // Ensure we re-propagate panel expansion values to the panel controller and
                    // any listeners it may have, such as PanelBar. This will also ensure we
                    // re-display the notification panel if necessary (for example, if
                    // a heads-up notification was being displayed and should continue being
                    // displayed).
                    mNotificationPanelViewController.updatePanelExpansionAndVisibility();
                })
            	./*代码省略*/
        //...代码省略...
        mNotificationPanelViewController.initDependencies(
                this,
                this::makeExpandedInvisible,
                mNotificationShelfController);
   	}
       
    private void inflateStatusBarWindow() {
        mStatusBarComponent = mStatusBarComponentFactory.create();
        mFragmentService.addFragmentInstantiationProvider(mStatusBarComponent);

        mNotificationShadeWindowView = mStatusBarComponent.getNotificationShadeWindowView();
        mNotificationShadeWindowViewController = mStatusBarComponent
                .getNotificationShadeWindowViewController();
        mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
        mNotificationShadeWindowViewController.setupExpandedStatusBar();
        mNotificationPanelViewController = mStatusBarComponent.getNotificationPanelViewController();
        //...代码省略...
     }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

代码虽然多,但是方法名都有对应相应方法的作用。NotificationShadeWindowView通知栏的阴影块背景视图、NotificationPanelView通知面板视图,用来填充各个通知。

    private void setUpPresenter() {
        // Set up the initial notification state.
        mActivityLaunchAnimator.setCallback(mKeyguardHandler);
        mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider(
                mNotificationShadeWindowViewController,
                mStackScrollerController.getNotificationListContainer(),
                mHeadsUpManager
        );//动画相关

        // TODO: inject this.
        mPresenter = new StatusBarNotificationPresenter(
                mContext,
                mNotificationPanelViewController,
                mHeadsUpManager,
                mNotificationShadeWindowView,
                mStackScrollerController,
                mDozeScrimController,
                mScrimController,
                mNotificationShadeWindowController,
                mDynamicPrivacyController,
                mKeyguardStateController,
                mKeyguardIndicationController,
                mFeatureFlags,
                this /* statusBar */,
                mShadeController,
                mLockscreenShadeTransitionController,
                mCommandQueue,
                mViewHierarchyManager,
                mLockscreenUserManager,
                mStatusBarStateController,
                mNotifShadeEventSource,
                mEntryManager,
                mMediaManager,
                mGutsManager,
                mKeyguardUpdateMonitor,
                mLockscreenGestureLogger,
                mInitController,
                mNotificationInterruptStateProvider,
                mRemoteInputManager,
                mConfigurationController);

        mNotificationShelfController.setOnActivatedListener(mPresenter);
        mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController);

        mNotificationActivityStarter =
                mStatusBarNotificationActivityStarterBuilder
                        .setStatusBar(this)
                        .setActivityLaunchAnimator(mActivityLaunchAnimator)
                        .setNotificationAnimatorControllerProvider(mNotificationAnimationProvider)
                        .setNotificationPresenter(mPresenter)
                        .setNotificationPanelViewController(mNotificationPanelViewController)
                        .build();
        mStackScrollerController.setNotificationActivityStarter(mNotificationActivityStarter);
        mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);

        mNotificationsController.initialize(
                this,
                mBubblesOptional,
                mPresenter,
                mStackScrollerController.getNotificationListContainer(),
                mNotificationActivityStarter,
                mPresenter);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

这个方法作用就是完成NotificationsController的initialize()方法。

NotificationShelf是通知栏主体框架。

执行完这些后,Notification相关的View的Controller都被启动起来,在Controller里有各个视图填充相应Framelayout的逻辑。这一块的代码多且杂,就不做深究。下节就分析一下,app或者系统发送通知后,SystemUI是如何将通知显示,以及重要级是如何区分的。即通知的实现过程

Notification的关键API

NotificationChannels

什么是 NotificationChannel ?在 Android 8.0 以及之后使用通知时必须指定 NotificationChannel,并且在指定NotificationChannel时需要设置通知的重要程度等级,以便用户可以在设置里根据个人喜好操作不同的NotificationChannel

源码路径: frameworks/base/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java

public class NotificationChannels extends SystemUI {
    // ...
    // 代码省略

    public static void createAll(Context context) {
        final NotificationManager nm = context.getSystemService(NotificationManager.class);
        final NotificationChannel batteryChannel = new NotificationChannel(BATTERY,
                context.getString(R.string.notification_channel_battery),
                NotificationManager.IMPORTANCE_MAX);
        final String soundPath = Settings.Global.getString(context.getContentResolver(),
                Settings.Global.LOW_BATTERY_SOUND);
        batteryChannel.setSound(Uri.parse("file://" + soundPath), new AudioAttributes.Builder()
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
                .build());
        batteryChannel.setBlockable(true);

        final NotificationChannel alerts = new NotificationChannel(
                ALERTS,
                context.getString(R.string.notification_channel_alerts),
                NotificationManager.IMPORTANCE_HIGH);

        final NotificationChannel general = new NotificationChannel(
                GENERAL,
                context.getString(R.string.notification_channel_general),
                NotificationManager.IMPORTANCE_MIN);

        final NotificationChannel storage = new NotificationChannel(
                STORAGE,
                context.getString(R.string.notification_channel_storage),
                isTv(context)
                        ? NotificationManager.IMPORTANCE_DEFAULT
                        : NotificationManager.IMPORTANCE_LOW);

        final NotificationChannel hint = new NotificationChannel(
                HINTS,
                context.getString(R.string.notification_channel_hints),
                NotificationManager.IMPORTANCE_DEFAULT);
        // No need to bypass DND.

        nm.createNotificationChannels(Arrays.asList(
                alerts,
                general,
                storage,
                createScreenshotChannel(
                        context.getString(R.string.notification_channel_screenshot)),
                batteryChannel,
                hint
        ));

        if (isTv(context)) {
            // TV specific notification channel for TV PIP controls.
            // Importance should be {@link NotificationManager#IMPORTANCE_MAX} to have the highest
            // priority, so it can be shown in all times.
            nm.createNotificationChannel(new NotificationChannel(
                    TVPIP,
                    context.getString(R.string.notification_channel_tv_pip),
                    NotificationManager.IMPORTANCE_MAX));
        }
    }

    /**
     * Set up screenshot channel, respecting any previously committed user settings on legacy
     * channel.
     * @return
     */
    @VisibleForTesting static NotificationChannel createScreenshotChannel(
            String name) {
        NotificationChannel screenshotChannel = new NotificationChannel(SCREENSHOTS_HEADSUP,
                name, NotificationManager.IMPORTANCE_HIGH); // pop on screen

        screenshotChannel.setSound(null, // silent
                new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build());
        screenshotChannel.setBlockable(true);

        return screenshotChannel;
    }

    @Override
    public void start() {
        createAll(mContext);
    }

    private static boolean isTv(Context context) {
        PackageManager packageManager = context.getPackageManager();
        return packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88

NotificationChannels 扩展自 SystemUI 并重写了 start 方法,它执行了 createAll 方法,创建了通知通道有 batteryChannel(电池)、alerts(提醒)、storage(存储空间)、screenshot(屏幕截图)、hint (提示)、general(常规消息)。
此外,如果是 TV 设备的话还会创建画中画通知通道。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/120587
推荐阅读
相关标签
  

闽ICP备14008679号