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函数更新上面的修改

相关推荐
阿巴斯甜17 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker18 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952719 小时前
Andorid Google 登录接入文档
android
黄林晴20 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android