Android14 SystemUI NotificationShadeWindowView 加载显示过程

Android14 SystemUI 启动过程中介绍到SystemUI启动最后会调用 CoreStartable 实现类中 start() 方法。通过源码可知NotificationShadeWindowView 的启动类是CentralSurfacesImpl实现了 CoreStartable 接口。

下面先看一下CentralSurfacesImplstart()方法, 这里代码很多,这里分析有关的代码 frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java

scss 复制代码
public void start() {
    // 省略部分代码
    RegisterStatusBarResult result = null;
    try {
        result = mBarService.registerStatusBar(mCommandQueue);
    } catch (RemoteException ex) {
        ex.rethrowFromSystemServer();
    }

    createAndAddWindows(result);
    // 省略部分代码
}

@Override
public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
    makeStatusBarView(result);
    mNotificationShadeWindowController.attach();
    mStatusBarWindowController.attach();
}

protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
    // 省略部分代码
    inflateStatusBarWindow();
    // 省略部分代码
}

private void inflateStatusBarWindow() {
    // 省略部分代码
    mCentralSurfacesComponent = mCentralSurfacesComponentFactory.create();
    mNotificationShadeWindowView = mCentralSurfacesComponent.getNotificationShadeWindowView();
    mNotificationShadeWindowViewController = mCentralSurfacesComponent
            .getNotificationShadeWindowViewController();
    mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
    // 省略部分代码
}

通过上面调用链可以知道最后调用到inflateStatusBarWindow()函数中, 通过mCentralSurfacesComponent.getNotificationShadeWindowView() 获取到NotificationShadeWindowView,看一下dagger中是怎么实现的 frameworks/base/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt

kotlin 复制代码
@Module
abstract class ShadeModule {

    @Binds
    @IntoMap
    @ClassKey(AuthRippleController::class)
    abstract fun bindAuthRippleController(controller: AuthRippleController): CoreStartable

    companion object {
        const val SHADE_HEADER = "large_screen_shade_header"

        @Provides
        @SysUISingleton
        // TODO(b/277762009): Do something similar to
        //  {@link StatusBarWindowModule.InternalWindowView} so that only
        //  {@link NotificationShadeWindowViewController} can inject this view.
        fun providesNotificationShadeWindowView(
            layoutInflater: LayoutInflater,
        ): NotificationShadeWindowView {
            return layoutInflater.inflate(R.layout.super_notification_shade, /* root= */ null)
                as NotificationShadeWindowView?
                ?: throw IllegalStateException(
                    "R.layout.super_notification_shade could not be properly inflated"
                )
        }
    }
    // 省略部分代码
}

然后将获取到的NotificationShadeWindowView交给NotificationShadeWindowControllerImpl 进行控制。在设置完NotificationShadeWindowView后就会执行mNotificationShadeWindowController.attach()函数将View 添加到屏幕上, 看一下具体实现 frameworks/base/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java

scss 复制代码
/**
 * Adds the notification shade view to the window manager.
 */
@Override
public void attach() {
    // Now that the notification shade encompasses the sliding panel and its
    // translucent backdrop, the entire thing is made TRANSLUCENT and is
    // hardware-accelerated.
    mLp = new LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT,
            LayoutParams.TYPE_NOTIFICATION_SHADE,
            LayoutParams.FLAG_NOT_FOCUSABLE
                    | LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                    | LayoutParams.FLAG_SPLIT_TOUCH
                    | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                    | LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
            PixelFormat.TRANSLUCENT);
    mLp.token = new Binder();
    mLp.gravity = Gravity.TOP;
    mLp.setFitInsetsTypes(0 /* types */);
    mLp.setTitle("NotificationShade");
    mLp.packageName = mContext.getPackageName();
    mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
    mLp.privateFlags |= PRIVATE_FLAG_OPTIMIZE_MEASURE;

    // We use BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE here, however, there is special logic in
    // window manager which disables the transient show behavior.
    // TODO: Clean this up once that behavior moves into the Shell.
    mLp.privateFlags |= PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
    mLp.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;

    mWindowManager.addView(mNotificationShadeView, mLp);

    mLpChanged.copyFrom(mLp);
    onThemeChanged();

    // Make the state consistent with KeyguardViewMediator#setupLocked during initialization.
    if (mKeyguardViewMediator.isShowingAndNotOccluded()) {
        setKeyguardShowing(true);
    }
}
@Override
public void setNotificationShadeView(ViewGroup view) {
    mNotificationShadeView = view;
}

上面代码很清晰,把mNotificationShadeView通过mWindowManager添加到屏幕上

下面在看一个在NotificationShadeWindowControllerImpl中比较关键的函数apply函数,

scss 复制代码
private void apply(NotificationShadeWindowState state) {
    logState(state);
    applyKeyguardFlags(state);
    applyFocusableFlag(state);
    applyForceShowNavigationFlag(state);
    adjustScreenOrientation(state);
    applyVisibility(state);
    applyUserActivityTimeout(state);
    applyInputFeatures(state);
    applyFitsSystemWindows(state);
    applyModalFlag(state);
    applyBrightness(state);
    applyHasTopUi(state);
    applyNotTouchable(state);
    applyStatusBarColorSpaceAgnosticFlag(state);
    applyWindowLayoutParams();

    if (mHasTopUi != mHasTopUiChanged) {
        whitelistIpcs(() -> {
            try {
                mActivityManager.setHasTopUi(mHasTopUiChanged);
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to call setHasTopUi", e);
            }
            mHasTopUi = mHasTopUiChanged;
        });
    }
    notifyStateChangedCallbacks();
}

这个函数在很多场景都会触发,更新一显示相关状态。哪里会调用这里不详细介绍,都在这个类中。以setKeyguardShowing函数为例介绍一下。

typescript 复制代码
@Override
public void setKeyguardShowing(boolean showing) {
    mCurrentState.keyguardShowing = showing;
    apply(mCurrentState);
}

到这里调用逻辑就更加清晰了, 当锁屏显示时,调用setKeyguardShowing函数, 在setKeyguardShowing中修改 mCurrentState.keyguardShowing状态, 最后调用apply函数更新View的参数, 在apply函数中调用的函数通过state变量来更改NotificationShadeWindowView 的参数。mCurrentStateNotificationShadeWindowState, 是NotificationShadeWindowControllerImpl中维护的一个内部的状态管理变量。

最后介绍两个相关函数:

ini 复制代码
private void adjustScreenOrientation(NotificationShadeWindowState state) {
    Log.d(TAG, "adjustScreenOrientation: tree:" + Log.getStackTraceString(new Throwable()));
    if (state.bouncerShowing || state.isKeyguardShowingAndNotOccluded() || state.dozing) {
        if (mKeyguardStateController.isKeyguardScreenRotationAllowed()) {
            mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
        } else {
            mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
        }
    } else {
        mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
    }
}

这个是控制显示方向的,在这里可以设置NotificationShadeWindowView显示方向,比如:需要锁屏在任何场景下都是横屏显示,只需要修改一下这个地方的配置就可以

scss 复制代码
private void applyWindowLayoutParams() {
    if (mDeferWindowLayoutParams == 0 && mLp != null && mLp.copyFrom(mLpChanged) != 0) {
        mLogger.logApplyingWindowLayoutParams(mLp);
        Trace.beginSection("updateViewLayout");
        mWindowManager.updateViewLayout(mNotificationShadeView, mLp);
        Trace.endSection();
    }
}

最后通过applyWindowLayoutParams函数更新上面的修改

相关推荐
龙之叶23 分钟前
Android 12:在 ActivityStarter 层拦截分享、搜索与 HTTP 外链
android·chrome·http
牛奔35 分钟前
Android 开发通用解决方案:使用 ADB 彻底卸载已安装 App(解决版本降级安装失败问题)
android·adb
tryqaaa_1 小时前
学习日志(三)【php语法学习,iscc校赛wp】
android·网络协议·学习·安全·web安全·web
plainGeekDev2 小时前
Kotlin协程面试题:suspend原理都说不清,协程你真会用?
android·面试·kotlin
Kapaseker2 小时前
Android 官方开始拥抱 WebView
android
ujainu小2 小时前
CANN hixl:大模型 PD 分离场景的零拷贝通信库
android·java·缓存
专注VB编程开发20年3 小时前
b4a用VB语言开发安卓APP-图片缩放库ZoomImageView讲解-双指缩放 + 单指拖动核心源码
android·java·前端
恋猫de小郭3 小时前
Dart 大更新,新增语法糖和各种能力,真的难得了
android·前端·flutter
EQ-雪梨蛋花汤4 小时前
【Sceneform-EQR】让Android 原生 3D开发更容易
android·3d
三少爷的鞋4 小时前
Android 架构指南之Data 层不要再暴露 start/stop 了:用 Flow 接管生命周期
android