Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f952b7d5 authored by Maryam Dehaini's avatar Maryam Dehaini Committed by Android (Google) Code Review
Browse files

Merge changes from topic "WindowDecor2" into main

* changes:
  [8/N] WindowDecor refactor: Move WindowDecor#addWindow to HandleMenu
  [7/N] WindowDecor refactor: Create App-to-Web repository
parents 10c23d42 05cd0081
Loading
Loading
Loading
Loading
+150 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.wm.shell.apptoweb

import android.app.ActivityManager.RunningTaskInfo
import android.app.assist.AssistContent
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.util.IndentingPrintWriter
import androidx.core.net.toUri
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
import java.io.PrintWriter
import kotlin.coroutines.suspendCoroutine

/**
 * App-to-Web has the following features: transferring an app session to the web and transferring
 * a web session to the relevant app. To transfer an app session to the web, we utilize
 * three different [Uri]s:
 * 1. webUri: The web URI provided by the app using [AssistContent]
 * 2. capturedLink: The link used to open the app if app was opened by clicking on a link
 * 3. genericLink: The system provided link for the app
 * In order to create the [Intent] to transfer the user from app to the web, the [Uri]s listed above
 * are checked in the given order and the first non-null link is used. When transferring from the
 * web to an app, the [Uri] must be provided by the browser application through [AssistContent].
 *
 * This Repository encapsulates the data stored for the App-to-Web feature for a single task and
 * creates the intents used to open switch between an app or browser session.
 */
class AppToWebRepository(
    private val userContext: Context,
    private val taskId: Int,
    private val assistContentRequester: AssistContentRequester,
    private val genericLinksParser: AppToWebGenericLinksParser,
) {
    private var capturedLink: CapturedLink? = null

    /** Sets the captured link if a new link is provided. */
    fun setCapturedLink(link: Uri, timeStamp: Long) {
        if (capturedLink?.timeStamp == timeStamp) return
        capturedLink = CapturedLink(link, timeStamp)
    }

    /**
     * Checks if [capturedLink] is available (non-null and has not been used) to use for switching
     * to browser session.
     */
    fun isCapturedLinkAvailable(): Boolean {
        val link = capturedLink ?: return false
        return !link.used
    }

    /** Sets the captured link as used. */
    fun onCapturedLinkUsed() {
        capturedLink?.setUsed()
    }

    /**
     * Retrieves the latest webUri and genericLink. If the task requesting the intent
     * [isBrowserApp], intent is created to switch to application if link was provided by browser
     * app and a relevant application exists to host the app. Otherwise, returns intent to switch
     * to browser if webUri, capturedLink, or genericLink is available.
     *
     * Note that the capturedLink should be updated separately using [setCapturedLink]
     *
     */
    suspend fun getAppToWebIntent(taskInfo: RunningTaskInfo, isBrowserApp: Boolean): Intent? {
        ProtoLog.d(
            WM_SHELL_DESKTOP_MODE,
            "AppToWebRepository: Updating browser links for task $taskId"
        )
        val assistContent = assistContentRequester.requestAssistContent(taskInfo.taskId)
        val webUri = assistContent?.getSessionWebUri()
        return if (isBrowserApp) {
            getAppIntent(webUri)
        } else {
            getBrowserIntent(webUri, getGenericLink(taskInfo))
        }
    }

    private suspend fun AssistContentRequester.requestAssistContent(taskId: Int): AssistContent? =
        suspendCoroutine { continuation ->
            requestAssistContent(taskId) { continuation.resumeWith(Result.success(it)) }
        }

    /** Returns the browser link associated with the given application if available. */
    private fun getBrowserIntent(webUri: Uri?, genericLink: Uri?): Intent? {
        val browserLink = webUri ?: if (isCapturedLinkAvailable()) {
            capturedLink?.uri
        } else {
            genericLink
        } ?: return null
        return getBrowserIntent(browserLink, userContext.packageManager, userContext.userId)
    }

    private fun getAppIntent(webUri: Uri?): Intent? {
        webUri ?: return null
        return getAppIntent(
            uri = webUri,
            packageManager = userContext.packageManager,
            userId = userContext.userId
        )
    }


    private fun getGenericLink(taskInfo: RunningTaskInfo): Uri? {
        ProtoLog.d(
            WM_SHELL_DESKTOP_MODE,
            "AppToWebRepository: Updating generic link for task %d",
            taskId
        )
        val baseActivity = taskInfo.baseActivity ?: return null
        return genericLinksParser.getGenericLink(baseActivity.packageName)?.toUri()
    }

    /** Dumps the repository's current state. */
    fun dump(originalWriter: PrintWriter, prefix: String) {
        val pw = IndentingPrintWriter(originalWriter, " ", prefix)
        pw.println("AppToWebRepository for task#$taskId")
        pw.increaseIndent()
        pw.println("CapturedLink=$capturedLink")
    }

    /** Encapsulates data associated with a captured link. */
    private data class CapturedLink(val uri: Uri, val timeStamp: Long) {

        /** Signifies if captured link has already been used, making it invalid. */
        var used = false

        /** Sets the captured link as used. */
        fun setUsed() {
            used = true
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ class AssistContentRequester(
    private val callBackExecutor: Executor,
    private val systemInteractionExecutor: Executor
) {
    interface Callback {
    fun interface Callback {
        // Called when the [AssistContent] of the requested task is available.
        fun onAssistContentAvailable(assistContent: AssistContent?)
    }
+3 −3
Original line number Diff line number Diff line
@@ -193,7 +193,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    private final AppHandleViewHolder.Factory mAppHandleViewHolderFactory;
    private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
    private final MaximizeMenuFactory mMaximizeMenuFactory;
    private final HandleMenuFactory mHandleMenuFactory;
    private final HandleMenu.HandleMenuFactory mHandleMenuFactory;
    private final AppToWebGenericLinksParser mGenericLinksParser;
    private final AssistContentRequester mAssistContentRequester;
    private final DesktopModeCompatPolicy mDesktopModeCompatPolicy;
@@ -268,7 +268,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                new SurfaceControlViewHostFactory() {},
                windowDecorViewHostSupplier,
                DefaultMaximizeMenuFactory.INSTANCE,
                DefaultHandleMenuFactory.INSTANCE, multiInstanceHelper,
                HandleMenu.HandleMenuFactory.INSTANCE, multiInstanceHelper,
                windowDecorCaptionRepository, desktopModeEventLogger,
                desktopModeUiEventLogger, desktopModeCompatPolicy,
                desktopState, desktopConfig, windowDecorationActions);
@@ -305,7 +305,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            SurfaceControlViewHostFactory surfaceControlViewHostFactory,
            @NonNull WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier,
            MaximizeMenuFactory maximizeMenuFactory,
            HandleMenuFactory handleMenuFactory,
            HandleMenu.HandleMenuFactory handleMenuFactory,
            MultiInstanceHelper multiInstanceHelper,
            WindowDecorCaptionRepository windowDecorCaptionRepository,
            DesktopModeEventLogger desktopModeEventLogger,
+187 −71
Original line number Diff line number Diff line
@@ -25,10 +25,12 @@ import android.content.Intent
import android.content.res.ColorStateList
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.PixelFormat
import android.graphics.Point
import android.graphics.PointF
import android.graphics.Rect
import android.os.Bundle
import android.view.Display
import android.view.Display.DEFAULT_DISPLAY
import android.view.LayoutInflater
import android.view.MotionEvent
@@ -38,11 +40,13 @@ import android.view.View
import android.view.View.OnClickListener
import android.view.ViewGroup
import android.view.WindowInsets.Type.systemBars
import android.view.WindowManager
import android.view.WindowManager.LayoutParams
import android.view.WindowlessWindowManager
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.Space
import android.window.DesktopExperienceFlags
import android.window.DesktopModeFlags
import android.window.SurfaceSyncGroup
import androidx.annotation.StringRes
@@ -64,8 +68,10 @@ import com.android.wm.shell.shared.bubbles.ContextUtils.isRtl
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON
import com.android.wm.shell.shared.split.SplitScreenConstants
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.windowdecor.WindowDecoration2.SurfaceControlViewHostFactory
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer
import com.android.wm.shell.windowdecor.common.DecorThemeUtil
import com.android.wm.shell.windowdecor.common.DrawableInsets
import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader
@@ -77,7 +83,6 @@ import com.android.wm.shell.windowdecor.extension.isPinned
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainCoroutineDispatcher
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -91,10 +96,14 @@ import kotlinx.coroutines.withContext
 * Windowing Options(Proto 2 only): Buttons to change windowing modes.
 * Additional Options: Miscellaneous functions including screenshot and closing task.
 */
class HandleMenu(
class HandleMenu private constructor(
    @ShellMainThread private val mainDispatcher: CoroutineDispatcher,
    @ShellBackgroundThread private val bgScope: CoroutineScope,
    private val parentDecor: DesktopModeWindowDecoration,
    private val context: Context,
    private val taskInfo: RunningTaskInfo,
    private val parentSurface: SurfaceControl,
    private val display: Display,
    private val parentDecor: DesktopModeWindowDecoration?,
    private val windowManagerWrapper: WindowManagerWrapper,
    private val windowDecorationActions: WindowDecorationActions,
    private val taskResourceLoader: WindowDecorTaskResourceLoader,
@@ -112,11 +121,11 @@ class HandleMenu(
    private val captionWidth: Int,
    private val captionHeight: Int,
    captionX: Int,
    captionY: Int
    captionY: Int,
    private val surfaceControlBuilderSupplier: () -> SurfaceControl.Builder,
    private val surfaceControlTransactionSupplier: () -> SurfaceControl.Transaction,
    private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory,
) {
    private val context: Context = parentDecor.mDecorWindowContext
    private val taskInfo: RunningTaskInfo = parentDecor.mTaskInfo

    private val isViewAboveStatusBar: Boolean
        get() = (DesktopModeFlags.ENABLE_HANDLE_INPUT_FIX.isTrue() && !taskInfo.isFreeform)

@@ -237,6 +246,7 @@ class HandleMenu(
        }
        val x = handleMenuPosition.x.toInt()
        val y = handleMenuPosition.y.toInt()
        val lpFlags = LayoutParams.FLAG_NOT_FOCUSABLE or LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
        handleMenuViewContainer =
            if ((!taskInfo.isFreeform && DesktopModeFlags.ENABLE_HANDLE_INPUT_FIX.isTrue())
                || forceShowSystemBars
@@ -248,8 +258,7 @@ class HandleMenu(
                    y = y,
                    width = menuWidth,
                    height = menuHeight,
                    flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                            WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                    flags = lpFlags,
                    view = handleMenuView.rootView,
                    forciblyShownTypes = if (forceShowSystemBars) {
                        systemBars()
@@ -259,8 +268,13 @@ class HandleMenu(
                    ignoreCutouts = Flags.showAppHandleLargeScreens()
                            || BubbleAnythingFlagHelper.enableBubbleToFullscreen()
                )
            } else if (DesktopExperienceFlags.ENABLE_WINDOW_DECORATION_REFACTOR.isTrue) {
                createAdditionalViewHostViewContainer(
                    handleMenuView.rootView, t, x, y, menuWidth, menuHeight, lpFlags
                )
            } else {
                parentDecor.addWindow(
                val decor = checkNotNull(parentDecor) { "Expected non-null parent decoration" }
                decor.addWindow(
                    handleMenuView.rootView, "Handle Menu", t, ssg, x, y, menuWidth, menuHeight
                )
            }
@@ -268,6 +282,55 @@ class HandleMenu(
        this.handleMenuView = handleMenuView
    }

    /** Creates and returns an [AdditionalViewHostViewContainer] for the handle menu. */
    private fun createAdditionalViewHostViewContainer(
        v: View,
        t: SurfaceControl.Transaction,
        xPos: Int,
        yPos: Int,
        width: Int,
        height: Int,
        flags: Int,
    ): AdditionalViewHostViewContainer {
        val builder = surfaceControlBuilderSupplier()
        val windowSurfaceControl = builder
            .setName("Handle menu of Task=" + taskInfo.taskId)
            .setContainerLayer()
            .setParent(parentSurface)
            .setCallsite("HandleMenu.createAdditionalViewHostViewContainer")
            .build()
        t.setPosition(windowSurfaceControl, xPos.toFloat(), yPos.toFloat())
            .setWindowCrop(windowSurfaceControl, width, height)
            .show(windowSurfaceControl)
        val lp = LayoutParams(
            width,
            height,
            LayoutParams.TYPE_APPLICATION,
            flags,
            PixelFormat.TRANSPARENT
        ).apply {
            title = "Handle menu of task=" + taskInfo.taskId
            setTrustedOverlay()
        }
        val windowManager = WindowlessWindowManager(
            taskInfo.configuration,
            windowSurfaceControl,
            /* hostInputTransferToken= */ null
        )
        val viewHost = surfaceControlViewHostFactory.create(
            context,
            display,
            windowManager
        ).apply {
            setView(v, lp)
        }
        return AdditionalViewHostViewContainer(
            windowSurfaceControl,
            viewHost,
            surfaceControlTransactionSupplier,
        )
    }

    /**
     * Updates handle menu's position variables to reflect its next position.
     */
@@ -429,7 +492,8 @@ class HandleMenu(
        }
        if (!shouldShowRestartButton) {
            menuHeight -= loadDimensionPixelSize(
                R.dimen.desktop_mode_handle_menu_restart_button_height)
                R.dimen.desktop_mode_handle_menu_restart_button_height
            )
        }
        if (!shouldShowMoreActionsPill) {
            menuHeight -= pillTopMargin
@@ -753,7 +817,7 @@ class HandleMenu(
            appIconView.setImageBitmap(icon)
        }

        /** Animates the menu openInAppOrBrowserg. */
        /** Animates the menu opening. */
        fun animateOpenMenu() {
            if (taskInfo.isFullscreen || taskInfo.isMultiWindow) {
                animator.animateCaptionHandleExpandToOpen()
@@ -929,7 +993,8 @@ class HandleMenu(
                            topRadius, topRadius, topRadius, topRadius,
                            bottomRadius, bottomRadius, bottomRadius, bottomRadius
                        ),
                        drawableInsets = DrawableInsets())
                        drawableInsets = DrawableInsets()
                    )
                }
            }
            // The restart button is nested to show an error icon on the right. Update the
@@ -956,7 +1021,8 @@ class HandleMenu(
                background = createBackgroundDrawable(
                    color = style.textColor,
                    cornerRadius = handleMenuCornerRadius,
                    drawableInsets = DrawableInsets())
                    drawableInsets = DrawableInsets()
                )
                textView.apply {
                    text = btnText
                    setTextColor(style.textColor)
@@ -971,7 +1037,8 @@ class HandleMenu(
                background = createBackgroundDrawable(
                    color = style.textColor,
                    cornerRadius = iconButtonRippleRadius,
                    drawableInsets = iconButtonDrawableInsetEnd)
                    drawableInsets = iconButtonDrawableInsetEnd
                )
            }
        }

@@ -1003,14 +1070,17 @@ class HandleMenu(
        fun shouldShowRestartButton(taskInfo: RunningTaskInfo): Boolean =
            taskInfo.appCompatTaskInfo.isRestartMenuEnabledForDisplayMove
    }
}

/** A factory interface to create a [HandleMenu]. */
interface HandleMenuFactory {
    /** Factory to create a new [HandleMenu].  */
    object HandleMenuFactory {
        @JvmOverloads
        fun create(
        @ShellMainThread mainDispatcher: MainCoroutineDispatcher,
            @ShellMainThread mainDispatcher: CoroutineDispatcher,
            @ShellBackgroundThread bgScope: CoroutineScope,
        parentDecor: DesktopModeWindowDecoration,
            context: Context,
            taskInfo: RunningTaskInfo,
            parentSurface: SurfaceControl,
            display: Display,
            windowManagerWrapper: WindowManagerWrapper,
            windowDecorationActions: WindowDecorationActions,
            taskResourceLoader: WindowDecorTaskResourceLoader,
@@ -1029,13 +1099,47 @@ interface HandleMenuFactory {
            captionHeight: Int,
            captionX: Int,
            captionY: Int,
    ): HandleMenu
}
            surfaceControlBuilderSupplier: () -> SurfaceControl.Builder =
                { SurfaceControl.Builder() },
            surfaceControlTransactionSupplier: () -> SurfaceControl.Transaction =
                { SurfaceControl.Transaction() },
            surfaceControlViewHostFactory: SurfaceControlViewHostFactory =
                object : SurfaceControlViewHostFactory {},
        ): HandleMenu = HandleMenu(
            mainDispatcher,
            bgScope,
            context,
            taskInfo,
            parentSurface,
            display,
            parentDecor = null,
            windowManagerWrapper,
            windowDecorationActions,
            taskResourceLoader,
            layoutResId,
            splitScreenController,
            shouldShowWindowingPill,
            shouldShowNewWindowButton,
            shouldShowManageWindowsButton,
            shouldShowChangeAspectRatioButton,
            shouldShowDesktopModeButton,
            shouldShowRestartButton,
            isBrowserApp,
            openInAppOrBrowserIntent,
            desktopModeUiEventLogger,
            captionWidth,
            captionHeight,
            captionX,
            captionY,
            surfaceControlBuilderSupplier,
            surfaceControlTransactionSupplier,
            surfaceControlViewHostFactory,
        )

/** A [HandleMenuFactory] implementation that creates a [HandleMenu].  */
object DefaultHandleMenuFactory : HandleMenuFactory {
    override fun create(
        @ShellMainThread mainDispatcher: MainCoroutineDispatcher,
        @Deprecated("Handle menu should no longer have reference to window decoration")
        @JvmOverloads
        fun create(
            @ShellMainThread mainDispatcher: CoroutineDispatcher,
            @ShellBackgroundThread bgScope: CoroutineScope,
            parentDecor: DesktopModeWindowDecoration,
            windowManagerWrapper: WindowManagerWrapper,
@@ -1056,10 +1160,19 @@ object DefaultHandleMenuFactory : HandleMenuFactory {
            captionHeight: Int,
            captionX: Int,
            captionY: Int,
    ): HandleMenu {
        return HandleMenu(
            surfaceControlBuilderSupplier: () -> SurfaceControl.Builder =
                { SurfaceControl.Builder() },
            surfaceControlTransactionSupplier: () -> SurfaceControl.Transaction =
                { SurfaceControl.Transaction() },
            surfaceControlViewHostFactory: SurfaceControlViewHostFactory =
                object : SurfaceControlViewHostFactory {}
        ): HandleMenu = HandleMenu(
            mainDispatcher,
            bgScope,
            parentDecor.mDecorWindowContext,
            parentDecor.mTaskInfo,
            parentDecor.mDecorationContainerSurface,
            parentDecor.mDisplay,
            parentDecor,
            windowManagerWrapper,
            windowDecorationActions,
@@ -1079,6 +1192,9 @@ object DefaultHandleMenuFactory : HandleMenuFactory {
            captionHeight,
            captionX,
            captionY,
            surfaceControlBuilderSupplier,
            surfaceControlTransactionSupplier,
            surfaceControlViewHostFactory,
        )
    }
}
+0 −69
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.Rect
import android.graphics.Region
import android.gui.BorderSettings
@@ -40,14 +39,11 @@ import android.window.DesktopExperienceFlags
import android.window.TaskConstants
import android.window.WindowContainerTransaction
import com.android.app.tracing.traceSection
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.BoxShadowHelper
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_WINDOW_DECORATION
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer
import com.android.wm.shell.windowdecor.caption.CaptionController
import com.android.wm.shell.windowdecor.extension.getDimensionPixelSize
import com.android.wm.shell.windowdecor.extension.isVisible
@@ -469,71 +465,6 @@ abstract class WindowDecoration2<T>(
        surfaceControlSupplier: () -> SurfaceControl
    ) = surfaceControlSupplier().apply { copyFrom(sc, TAG) }

    /**
     * Create a window associated with this WindowDecoration.
     * Note that subclass must dispose of this when the task is hidden/closed.
     *
     * @param v            View to attach to the window
     * @param t            the transaction to apply
     * @param xPos         x position of new window
     * @param yPos         y position of new window
     * @param width        width of new window
     * @param height       height of new window
     * @return the [AdditionalViewHostViewContainer] that was added.
     */
    fun addWindow(
        v: View,
        namePrefix: String,
        t: SurfaceControl.Transaction,
        xPos: Int,
        yPos: Int,
        width: Int,
        height: Int
    ): AdditionalViewHostViewContainer? {
        if (display == null) {
            ProtoLog.e(WM_SHELL_WINDOW_DECORATION, "Attempting to add window to null display")
            return null
        }
        val builder = surfaceControlBuilderSupplier()
        val windowSurfaceControl = builder
            .setName(namePrefix + " of Task=" + taskInfo.taskId)
            .setContainerLayer()
            .setParent(checkNotNull(decorationContainerSurface) {
                "expected non-null decoration container surface control"
            })
            .setCallsite("WindowDecoration2.addWindow")
            .build()
        t.setPosition(windowSurfaceControl, xPos.toFloat(), yPos.toFloat())
            .setWindowCrop(windowSurfaceControl, width, height)
            .show(windowSurfaceControl)
        val lp = LayoutParams(
            width,
            height,
            LayoutParams.TYPE_APPLICATION,
            LayoutParams.FLAG_NOT_FOCUSABLE or LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSPARENT
        ).apply {
            title = "Additional window of Task=" + taskInfo.taskId
            setTrustedOverlay()
        }
        val windowManager = WindowlessWindowManager(
            taskInfo.configuration,
            windowSurfaceControl, /* hostInputTransferToken = */ null
        )
        val viewHost = surfaceControlViewHostFactory.create(
            decorWindowContext,
            checkNotNull(display) { "expected non-null display" },
            windowManager
        ).apply {
            setView(v, lp)
        }
        return AdditionalViewHostViewContainer(
            windowSurfaceControl,
            viewHost,
            surfaceControlTransactionSupplier,
        )
    }

    /**  Holds the data required to update the window decorations. */
    data class RelayoutParams(
        val runningTaskInfo: RunningTaskInfo,
Loading