Android U 自由窗口(浮窗)——操作栏相关

分析思路

本地通过dump activity containers,View树以及window等方式均未找到自由窗口状态栏相关代码,最终通过winscope dumpsys SF找到相关线索。

winscope

通过winscope查看View结构

关键代码

代码路径:frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java

java 复制代码
    void relayout(RelayoutParams params, SurfaceControl.Transaction startT,
            SurfaceControl.Transaction finishT, WindowContainerTransaction wct, T rootView,
            RelayoutResult<T> outResult) {
        ......

        // DecorationContainerSurface
        if (mDecorationContainerSurface == null) {
            final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
            mDecorationContainerSurface = builder
                    .setName("Decor container of Task=" + mTaskInfo.taskId)
                    .setContainerLayer()
                    .setParent(mTaskSurface)
                    .build();

            startT.setTrustedOverlay(mDecorationContainerSurface, true)
                    .setLayer(mDecorationContainerSurface,
                            TaskConstants.TASK_CHILD_LAYER_WINDOW_DECORATIONS);
        }

        startT.setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight)
                .show(mDecorationContainerSurface);

        // CaptionContainerSurface, CaptionWindowManager
        if (mCaptionContainerSurface == null) {
            final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
            mCaptionContainerSurface = builder
                    .setName("Caption container of Task=" + mTaskInfo.taskId)
                    .setContainerLayer()
                    .setParent(mDecorationContainerSurface)
                    .build();
        }

        final int captionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId);
        final int captionWidth = taskBounds.width();
        startT.setWindowCrop(mCaptionContainerSurface, captionWidth, captionHeight)
                .show(mCaptionContainerSurface);

        if (ViewRootImpl.CAPTION_ON_SHELL) {
            outResult.mRootView.setTaskFocusState(mTaskInfo.isFocused);

            // Caption insets
            mCaptionInsetsRect.set(taskBounds);
            mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight + params.mCaptionY;
            wct.addInsetsSource(mTaskInfo.token,
                    mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect);
        } else {
            startT.hide(mCaptionContainerSurface);
        }

        // Task surface itself
        float shadowRadius = loadDimension(resources, params.mShadowRadiusId);
        int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor();
        mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
        mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
        mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
        final Point taskPosition = mTaskInfo.positionInParent;
        startT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight)
                .setShadowRadius(mTaskSurface, shadowRadius)
                .setColor(mTaskSurface, mTmpColor)
                .show(mTaskSurface);
        finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y)
                .setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight);
        if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
            startT.setCornerRadius(mTaskSurface, params.mCornerRadius);
            finishT.setCornerRadius(mTaskSurface, params.mCornerRadius);
        }

        if (mCaptionWindowManager == null) {
            // Put caption under a container surface because ViewRootImpl sets the destination frame
            // of windowless window layers and BLASTBufferQueue#update() doesn't support offset.
            mCaptionWindowManager = new WindowlessWindowManager(
                    mTaskInfo.getConfiguration(), mCaptionContainerSurface,
                    null /* hostInputToken */);
        }

        Slog.i("WindowDecoration","mViewHost:"+(mViewHost == null ? "null":mViewHost.toString()),new Exception());
        // Caption view
        mCaptionWindowManager.setConfiguration(taskConfig);
        final WindowManager.LayoutParams lp =
                new WindowManager.LayoutParams(captionWidth, captionHeight,
                        WindowManager.LayoutParams.TYPE_APPLICATION,
                        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
        lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
        lp.setTrustedOverlay();
        if (mViewHost == null) {
            mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
                    mCaptionWindowManager);
            if (params.mApplyStartTransactionOnDraw) {
                mViewHost.getRootSurfaceControl().applyTransactionOnDraw(startT);
            }
            mViewHost.setView(outResult.mRootView, lp);
        } else {
            if (params.mApplyStartTransactionOnDraw) {
                mViewHost.getRootSurfaceControl().applyTransactionOnDraw(startT);
            }
            mViewHost.relayout(lp);
        }
    }

从代码中可以看出"Caption of Task"是一个SurfaceControlViewHost对象,且其在Shell相关代码路径下,说该View是属于SystemUI进程。

如代码中所示,添加log打印堆栈。

堆栈跟踪

这里的流程我们同样以从多任务启动自由窗口为例

java 复制代码
WindowDecoration: mViewHost:null
WindowDecoration: java.lang.Exception
WindowDecoration: 	at com.android.wm.shell.windowdecor.WindowDecoration.relayout(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:282)
WindowDecoration: 	at com.android.wm.shell.windowdecor.CaptionWindowDecoration.relayout(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:120)
WindowDecoration: 	at com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel.createWindowDecoration(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:196)
WindowDecoration: 	at com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel.onTaskChanging(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:128)
WindowDecoration: 	at com.android.wm.shell.freeform.FreeformTaskTransitionObserver.onToFrontTransitionReady(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:147)
WindowDecoration: 	at com.android.wm.shell.freeform.FreeformTaskTransitionObserver.onTransitionReady(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:104)
WindowDecoration: 	at com.android.wm.shell.transition.Transitions.dispatchReady(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:707)
WindowDecoration: 	at com.android.wm.shell.transition.Transitions.onTransitionReady(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:669)
WindowDecoration: 	at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl.lambda$onTransitionReady$0(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:1353)
WindowDecoration: 	at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl.$r8$lambda$qsRfWn1ItrZqnFeABBdxU50jPc4(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:0)
WindowDecoration: 	at com.android.wm.shell.transition.Transitions$TransitionPlayerImpl$$ExternalSyntheticLambda0.run(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:0)
WindowDecoration: 	at android.os.Handler.handleCallback(Handler.java:958)
WindowDecoration: 	at android.os.Handler.dispatchMessage(Handler.java:99)
WindowDecoration: 	at android.os.Looper.loopOnce(Looper.java:205)
WindowDecoration: 	at android.os.Looper.loop(Looper.java:294)
WindowDecoration: 	at android.os.HandlerThread.run(HandlerThread.java:67)


WindowDecoration: mViewHost:android.view.SurfaceControlViewHost@12f4198
WindowDecoration: java.lang.Exception
WindowDecoration: 	at com.android.wm.shell.windowdecor.WindowDecoration.relayout(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:282)
WindowDecoration: 	at com.android.wm.shell.windowdecor.CaptionWindowDecoration.relayout(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:120)
WindowDecoration: 	at com.android.wm.shell.windowdecor.CaptionWindowDecoration.relayout(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:96)
WindowDecoration: 	at com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel.onTaskInfoChanged(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:108)
WindowDecoration: 	at com.android.wm.shell.freeform.FreeformTaskListener.onTaskInfoChanged(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:136)
WindowDecoration: 	at com.android.wm.shell.ShellTaskOrganizer.onTaskInfoChanged(go/retraceme fde5aedcaed361d3fa72c4a1576906ef6746f16da54ecf293f5080127ba3c502:527)
WindowDecoration: 	at android.window.TaskOrganizer$1.lambda$onTaskInfoChanged$6(TaskOrganizer.java:340)
WindowDecoration: 	at android.window.TaskOrganizer$1.$r8$lambda$FmJPvZyGqAGeVe9o6dSQkNL3f3g(Unknown Source:0)
WindowDecoration: 	at android.window.TaskOrganizer$1$$ExternalSyntheticLambda3.run(Unknown Source:4)
WindowDecoration: 	at android.os.Handler.handleCallback(Handler.java:958)
WindowDecoration: 	at android.os.Handler.dispatchMessage(Handler.java:99)
WindowDecoration: 	at android.os.Looper.loopOnce(Looper.java:205)
WindowDecoration: 	at android.os.Looper.loop(Looper.java:294)
WindowDecoration: 	at android.os.HandlerThread.run(HandlerThread.java:67)

这里我们主要关注mViewHost:null 的这次即可,不为null,则不会进入创建流程。

从堆栈中可以看出这个方法是从TransitionPlayerImpl.onTransitionReady到WindowDecoration.relayout结束

代码路径:frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java

java 复制代码
    @BinderThread
    private class TransitionPlayerImpl extends ITransitionPlayer.Stub {
        @Override
        public void onTransitionReady(IBinder iBinder, TransitionInfo transitionInfo,
                SurfaceControl.Transaction t, SurfaceControl.Transaction finishT)
                throws RemoteException {
            mMainExecutor.execute(() -> Transitions.this.onTransitionReady(
                    iBinder, transitionInfo, t, finishT));
        }
        ......
    }

这里是通过ITransitionPlayer跨进程通信,找到了mTransitionPlayer,在TransitionController中(system_server侧)

搜索其调用 mTransitionPlayer.onTransitionReady(

发现什么都没有,找下mTransitionPlayer相关的get方法

代码路径:frameworks/base/services/core/java/com/android/server/wm/TransitionController.java

java 复制代码
    @Nullable ITransitionPlayer getTransitionPlayer() {
        return mTransitionPlayer;
    }

再次通过getTransitionPlayer().onTransitionReady查找相应调用

最终我们得出TransitionPlayerImpl.onTransitionReady是通过system_server侧Transition.onTransactionReady中mController.getTransitionPlayer().onTransitionReady而来。

可在此处添加堆栈查看system_server侧调用逻辑。

java 复制代码
Transition: getTransitionPlayer().onTransitionReady
Transition: java.lang.Exception
Transition: 	at com.android.server.wm.Transition.onTransactionReady(Transition.java:1575)
Transition: 	at com.android.server.wm.BLASTSyncEngine$SyncGroup.finishNow(BLASTSyncEngine.java:263)
Transition: 	at com.android.server.wm.BLASTSyncEngine$SyncGroup.tryFinish(BLASTSyncEngine.java:202)
Transition: 	at com.android.server.wm.BLASTSyncEngine$SyncGroup.-$$Nest$mtryFinish(BLASTSyncEngine.java:0)
Transition: 	at com.android.server.wm.BLASTSyncEngine.onSurfacePlacement(BLASTSyncEngine.java:552)
Transition: 	at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:810)
Transition: 	at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:756)
Transition: 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
Transition: 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
Transition: 	at com.android.server.wm.WindowManagerService.relayoutWindow(WindowManagerService.java:2410)
Transition: 	at com.android.server.wm.Session.relayout(Session.java:249)
Transition: 	at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:701)
Transition: 	at com.android.server.wm.Session.onTransact(Session.java:178)
Transition: 	at android.os.Binder.execTransactInternal(Binder.java:1344)
Transition: 	at android.os.Binder.execTransact(Binder.java:1275)

这里走了窗口绘制流程,也就是说Caption view的创建是应用onresume流程之后开始的。

Layout Inspector

在android studio中选择tools->Legacy Layout Inspector,找到systemUI进程

其中可以找到对应的caption

选中后我们可以看到其结构

这个里面我们可以看到这些控件的id。

综上所述,android14中,CaptionWindow是systemUI上单独的进程不在应用本身上。

相关推荐
我是咸鱼不闲呀几秒前
力扣Hot100系列21(Java)——[多维动态规划]总结(不同路径,最小路径和,最长回文子串,最长公共子序列, 编辑距离)
java·leetcode·动态规划
lihao lihao3 分钟前
二分查找
java·数据结构·算法
Albert Edison3 分钟前
【C++11】可变参数模板
java·开发语言·c++
代码栈上的思考6 分钟前
消息队列持久化:文件存储设计与实现全解析
java·前端·算法
sg_knight12 分钟前
设计模式实战:策略模式(Strategy)
java·开发语言·python·设计模式·重构·架构·策略模式
麦麦鸡腿堡13 分钟前
JavaWeb_SpringBootWeb,HTTP协议,Tomcat快速入门
java·开发语言
一然明月17 分钟前
Qt QML 锚定(Anchors)全解析
java·数据库·qt
晓纪同学18 分钟前
EffctiveC++_02第二章
java·jvm·c++
koeda19 分钟前
android17系统兼容
android·安卓