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

Commit 7b2419c7 authored by mattsziklay's avatar mattsziklay
Browse files

Add WindowManagerWrapper class to window decor classes.

The ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR flag currently breaks several
tests due to the app handle using the flag and requiring MONITOR_INPUT
permission due to being a spy window.

This CL changes the method of retrieval of the system WindowManager
service by using a wrapper of the system WindowManager rather than
fetching it directly when needed. This allows us to provide a mock for
tests so we can avoid running into the above permission issue.

Bug: 361411076
Test: atest DesktopModeWindowDecorationTests, HandleMenuTest,
AdditionalSystemViewContainerTest, manual
Flag: EXEMPT bugfix

Change-Id: I3a45a46fe980f409cb8392a2a508ca3c7fb26c89
parent 897a3525
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    private final Choreographer mChoreographer;
    private final SyncTransactionQueue mSyncQueue;
    private final SplitScreenController mSplitScreenController;
    private final WindowManagerWrapper mWindowManagerWrapper;

    private WindowDecorationViewHolder mWindowDecorViewHolder;
    private View.OnClickListener mOnCaptionButtonClickListener;
@@ -188,7 +189,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                taskInfo, taskSurface, handler, bgExecutor, choreographer, syncQueue,
                rootTaskDisplayAreaOrganizer, genericLinksParser, SurfaceControl.Builder::new,
                SurfaceControl.Transaction::new,  WindowContainerTransaction::new,
                SurfaceControl::new, new SurfaceControlViewHostFactory() {},
                SurfaceControl::new, new WindowManagerWrapper(
                        context.getSystemService(WindowManager.class)),
                new SurfaceControlViewHostFactory() {},
                DefaultMaximizeMenuFactory.INSTANCE, DefaultHandleMenuFactory.INSTANCE,
                multiInstanceHelper);
    }
@@ -211,6 +214,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
            Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
            Supplier<SurfaceControl> surfaceControlSupplier,
            WindowManagerWrapper windowManagerWrapper,
            SurfaceControlViewHostFactory surfaceControlViewHostFactory,
            MaximizeMenuFactory maximizeMenuFactory,
            HandleMenuFactory handleMenuFactory,
@@ -229,6 +233,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        mMaximizeMenuFactory = maximizeMenuFactory;
        mHandleMenuFactory = handleMenuFactory;
        mMultiInstanceHelper = multiInstanceHelper;
        mWindowManagerWrapper = windowManagerWrapper;
    }

    /**
@@ -574,7 +579,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            return new AppHandleViewHolder(
                    mResult.mRootView,
                    mOnCaptionTouchListener,
                    mOnCaptionButtonClickListener
                    mOnCaptionButtonClickListener,
                    mWindowManagerWrapper
            );
        } else if (mRelayoutParams.mLayoutResId
                == R.layout.desktop_mode_app_header) {
@@ -988,6 +994,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        updateGenericLink();
        mHandleMenu = mHandleMenuFactory.create(
                this,
                mWindowManagerWrapper,
                mRelayoutParams.mLayoutResId,
                mAppIconBitmap,
                mAppName,
+5 −1
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ import com.android.wm.shell.windowdecor.extension.isPinned
 */
class HandleMenu(
    private val parentDecor: DesktopModeWindowDecoration,
    private val windowManagerWrapper: WindowManagerWrapper,
    private val layoutResId: Int,
    private val appIconBitmap: Bitmap?,
    private val appName: CharSequence?,
@@ -178,7 +179,7 @@ class HandleMenu(
        handleMenuViewContainer =
            if (!taskInfo.isFreeform && Flags.enableAdditionalWindowsAboveStatusBar()) {
                AdditionalSystemViewContainer(
                    context = context,
                    windowManagerWrapper = windowManagerWrapper,
                    taskId = taskInfo.taskId,
                    x = x,
                    y = y,
@@ -635,6 +636,7 @@ class HandleMenu(
interface HandleMenuFactory {
    fun create(
        parentDecor: DesktopModeWindowDecoration,
        windowManagerWrapper: WindowManagerWrapper,
        layoutResId: Int,
        appIconBitmap: Bitmap?,
        appName: CharSequence?,
@@ -652,6 +654,7 @@ interface HandleMenuFactory {
object DefaultHandleMenuFactory : HandleMenuFactory {
    override fun create(
        parentDecor: DesktopModeWindowDecoration,
        windowManagerWrapper: WindowManagerWrapper,
        layoutResId: Int,
        appIconBitmap: Bitmap?,
        appName: CharSequence?,
@@ -665,6 +668,7 @@ object DefaultHandleMenuFactory : HandleMenuFactory {
    ): HandleMenu {
        return HandleMenu(
            parentDecor,
            windowManagerWrapper,
            layoutResId,
            appIconBitmap,
            appName,
+41 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.windowdecor

import android.view.View
import android.view.WindowManager

/**
 * A wrapper for [WindowManager] to make view manipulation operations related to window
 * decors more testable.
 */
class WindowManagerWrapper (
    private val windowManager: WindowManager
){

    fun addView(v: View, lp: WindowManager.LayoutParams) {
        windowManager.addView(v, lp)
    }

    fun removeViewImmediate(v: View) {
        windowManager.removeViewImmediate(v)
    }

    fun updateViewLayout(v: View, lp: WindowManager.LayoutParams) {
        windowManager.updateViewLayout(v, lp)
    }
}
 No newline at end of file
+26 −19
Original line number Diff line number Diff line
@@ -24,13 +24,14 @@ import android.view.LayoutInflater
import android.view.SurfaceControl
import android.view.View
import android.view.WindowManager
import com.android.wm.shell.windowdecor.WindowManagerWrapper

/**
 * An [AdditionalViewContainer] that uses the system [WindowManager] instance. Intended
 * for view containers that should be above the status bar layer.
 */
class AdditionalSystemViewContainer(
    context: Context,
    private val windowManagerWrapper: WindowManagerWrapper,
    taskId: Int,
    x: Int,
    y: Int,
@@ -39,9 +40,20 @@ class AdditionalSystemViewContainer(
    flags: Int,
    override val view: View
) : AdditionalViewContainer() {
    val lp: WindowManager.LayoutParams = WindowManager.LayoutParams(
        width, height, x, y,
        WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
        flags,
        PixelFormat.TRANSPARENT
    ).apply {
        title = "Additional view container of Task=$taskId"
        gravity = Gravity.LEFT or Gravity.TOP
        setTrustedOverlay()
    }

    constructor(
        context: Context,
        windowManagerWrapper: WindowManagerWrapper,
        taskId: Int,
        x: Int,
        y: Int,
@@ -50,7 +62,7 @@ class AdditionalSystemViewContainer(
        flags: Int,
        @LayoutRes layoutId: Int
    ) : this(
        context = context,
        windowManagerWrapper = windowManagerWrapper,
        taskId = taskId,
        x = x,
        y = y,
@@ -61,9 +73,16 @@ class AdditionalSystemViewContainer(
    )

    constructor(
        context: Context, taskId: Int, x: Int, y: Int, width: Int, height: Int, flags: Int
        context: Context,
        windowManagerWrapper: WindowManagerWrapper,
        taskId: Int,
        x: Int,
        y: Int,
        width: Int,
        height: Int,
        flags: Int
    ) : this(
        context = context,
        windowManagerWrapper = windowManagerWrapper,
        taskId = taskId,
        x = x,
        y = y,
@@ -73,24 +92,12 @@ class AdditionalSystemViewContainer(
        view = View(context)
    )

    val windowManager: WindowManager? = context.getSystemService(WindowManager::class.java)

    init {
        val lp = WindowManager.LayoutParams(
            width, height, x, y,
            WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
            flags,
            PixelFormat.TRANSPARENT
        ).apply {
            title = "Additional view container of Task=$taskId"
            gravity = Gravity.LEFT or Gravity.TOP
            setTrustedOverlay()
        }
        windowManager?.addView(view, lp)
        windowManagerWrapper.addView(view, lp)
    }

    override fun releaseView() {
        windowManager?.removeViewImmediate(view)
        windowManagerWrapper.removeViewImmediate(view)
    }

    override fun setPosition(t: SurfaceControl.Transaction, x: Float, y: Float) {
@@ -98,6 +105,6 @@ class AdditionalSystemViewContainer(
            this.x = x.toInt()
            this.y = y.toInt()
        }
        windowManager?.updateViewLayout(view, lp)
        windowManagerWrapper.updateViewLayout(view, lp)
    }
}
+9 −7
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.widget.ImageButton
import com.android.window.flags.Flags
import com.android.wm.shell.R
import com.android.wm.shell.shared.animation.Interpolators
import com.android.wm.shell.windowdecor.WindowManagerWrapper
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer

/**
@@ -41,14 +42,14 @@ import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystem
internal class AppHandleViewHolder(
    rootView: View,
    onCaptionTouchListener: View.OnTouchListener,
    onCaptionButtonClickListener: OnClickListener
    onCaptionButtonClickListener: OnClickListener,
    private val windowManagerWrapper: WindowManagerWrapper
) : WindowDecorationViewHolder(rootView) {

    companion object {
        private const val CAPTION_HANDLE_ANIMATION_DURATION: Long = 100
    }
    private lateinit var taskInfo: RunningTaskInfo
    private val windowManager = context.getSystemService(WindowManager::class.java)
    private val captionView: View = rootView.requireViewById(R.id.desktop_mode_caption)
    private val captionHandle: ImageButton = rootView.requireViewById(R.id.caption_handle)
    private val inputManager = context.getSystemService(InputManager::class.java)
@@ -96,11 +97,12 @@ internal class AppHandleViewHolder(
                                          handleWidth: Int,
                                          handleHeight: Int) {
        if (!Flags.enableAdditionalWindowsAboveStatusBar()) return
        statusBarInputLayer = AdditionalSystemViewContainer(context, taskInfo.taskId,
            handlePosition.x, handlePosition.y, handleWidth, handleHeight,
        statusBarInputLayer = AdditionalSystemViewContainer(context, windowManagerWrapper,
            taskInfo.taskId, handlePosition.x, handlePosition.y, handleWidth, handleHeight,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
        val view = statusBarInputLayer?.view
        val lp = view?.layoutParams as WindowManager.LayoutParams
        val view = statusBarInputLayer?.view ?: error("Unable to find statusBarInputLayer View")
        val lp = statusBarInputLayer?.lp ?: error("Unable to find statusBarInputLayer" +
                "LayoutParams")
        lp.title = "Handle Input Layer of task " + taskInfo.taskId
        lp.setTrustedOverlay()
        // Make this window a spy window to enable it to pilfer pointers from the system-wide
@@ -120,7 +122,7 @@ internal class AppHandleViewHolder(
            captionHandle.dispatchTouchEvent(event)
            true
        }
        windowManager.updateViewLayout(view, lp)
        windowManagerWrapper.updateViewLayout(view, lp)
    }

    private fun updateStatusBarInputLayer(globalPosition: Point) {
Loading