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

Commit 77800551 authored by Graciela Putri's avatar Graciela Putri Committed by Android (Google) Code Review
Browse files

Merge "[3/n] Set appBounds to exclude caption insets" into main

parents 2e352d56 541acbbd
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -18,9 +18,12 @@ package com.android.wm.shell.shared.desktopmode

import android.app.TaskInfo
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED
import android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION
import android.window.DesktopModeFlags
import com.android.internal.R
import java.util.ArrayList
import com.android.window.flags.Flags

/**
 * Class to decide whether to apply app compat policies in desktop mode.
@@ -50,6 +53,21 @@ class DesktopModeCompatPolicy(private val context: Context) {
                || isTransparentTask(isActivityStackTransparent, numActivities))
                && !isTopActivityNoDisplay)

    /**
     * Whether the caption insets should be excluded from configuration for system to handle.
     *
     * The treatment is enabled when all the of the following is true:
     * * Any flags to forcibly consume caption insets are enabled.
     * * Top activity have configuration coupled with insets.
     * * Task is not resizeable.
     */
    fun shouldExcludeCaptionFromAppBounds(taskInfo: TaskInfo): Boolean =
        Flags.excludeCaptionFromAppBounds()
                && isAnyForceConsumptionFlagsEnabled()
                && taskInfo.topActivityInfo?.let {
            isInsetsCoupledWithConfiguration(it) && !taskInfo.isResizeable
        } ?: false

    /**
     * Returns true if all activities in a tasks stack are transparent. If there are no activities
     * will return false.
@@ -67,4 +85,12 @@ class DesktopModeCompatPolicy(private val context: Context) {
     */
    private fun isPartOfDefaultHomePackage(packageName: String?) =
        packageName != null && packageName == defaultHomePackage

    private fun isAnyForceConsumptionFlagsEnabled(): Boolean =
        DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS.isTrue
            || DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue

    private fun isInsetsCoupledWithConfiguration(info: ActivityInfo): Boolean =
        !(info.isChangeEnabled(OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION)
                || info.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED))
}
+35 −6
Original line number Diff line number Diff line
@@ -18,8 +18,10 @@

package com.android.wm.shell.desktopmode

import android.annotation.DimenRes
import android.app.ActivityManager.RunningTaskInfo
import android.app.TaskInfo
import android.content.Context
import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
import android.content.pm.ActivityInfo.isFixedOrientationLandscape
import android.content.pm.ActivityInfo.isFixedOrientationPortrait
@@ -28,6 +30,7 @@ import android.content.res.Configuration.ORIENTATION_PORTRAIT
import android.graphics.Rect
import android.os.SystemProperties
import android.util.Size
import com.android.wm.shell.R
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout

@@ -53,10 +56,12 @@ fun calculateDefaultDesktopTaskBounds(displayLayout: DisplayLayout): Rect {
 * aspect ratio, orientation and resizability to calculate an area this is compatible with the
 * applications previous configuration.
 */
@JvmOverloads
fun calculateInitialBounds(
    displayLayout: DisplayLayout,
    taskInfo: RunningTaskInfo,
    scale: Float = DESKTOP_MODE_INITIAL_BOUNDS_SCALE,
    captionInsets: Int = 0,
): Rect {
    val screenBounds = Rect(0, 0, displayLayout.width(), displayLayout.height())
    val appAspectRatio = calculateAspectRatio(taskInfo)
@@ -92,7 +97,7 @@ fun calculateInitialBounds(
                } else {
                    // If activity is unresizeable, regardless of orientation, calculate maximum
                    // size (within the ideal size) maintaining original aspect ratio.
                    maximizeSizeGivenAspectRatio(taskInfo, idealSize, appAspectRatio)
                    maximizeSizeGivenAspectRatio(taskInfo, idealSize, appAspectRatio, captionInsets)
                }
            }
            ORIENTATION_PORTRAIT -> {
@@ -119,11 +124,17 @@ fun calculateInitialBounds(
                            taskInfo,
                            Size(customPortraitWidthForLandscapeApp, idealSize.height),
                            appAspectRatio,
                            captionInsets,
                        )
                    } else {
                        // For portrait unresizeable activities, calculate maximum size (within the
                        // ideal size) maintaining original aspect ratio.
                        maximizeSizeGivenAspectRatio(taskInfo, idealSize, appAspectRatio)
                        maximizeSizeGivenAspectRatio(
                            taskInfo,
                            idealSize,
                            appAspectRatio,
                            captionInsets,
                        )
                    }
                }
            }
@@ -148,11 +159,16 @@ fun calculateMaximizeBounds(displayLayout: DisplayLayout, taskInfo: RunningTaskI
    } else {
        // if non-resizable then calculate max bounds according to aspect ratio
        val activityAspectRatio = calculateAspectRatio(taskInfo)
        val captionInsets =
            taskInfo.configuration.windowConfiguration.appBounds?.let {
                it.top - taskInfo.configuration.windowConfiguration.bounds.top
            } ?: 0
        val newSize =
            maximizeSizeGivenAspectRatio(
                taskInfo,
                Size(stableBounds.width(), stableBounds.height()),
                activityAspectRatio,
                captionInsets,
            )
        return centerInArea(newSize, stableBounds, stableBounds.left, stableBounds.top)
    }
@@ -166,8 +182,9 @@ fun maximizeSizeGivenAspectRatio(
    taskInfo: RunningTaskInfo,
    targetArea: Size,
    aspectRatio: Float,
    captionInsets: Int = 0,
): Size {
    val targetHeight = targetArea.height
    val targetHeight = targetArea.height - captionInsets
    val targetWidth = targetArea.width
    val finalHeight: Int
    val finalWidth: Int
@@ -191,13 +208,18 @@ fun maximizeSizeGivenAspectRatio(
            finalHeight = (finalWidth / aspectRatio).toInt()
        }
    }
    return Size(finalWidth, finalHeight)
    return Size(finalWidth, finalHeight + captionInsets)
}

/** Calculates the aspect ratio of an activity from its fullscreen bounds. */
fun calculateAspectRatio(taskInfo: RunningTaskInfo): Float {
    if (taskInfo.appCompatTaskInfo.topActivityAppBounds.isEmpty) return 1f
    val appBounds = taskInfo.appCompatTaskInfo.topActivityAppBounds
    val appBounds =
        if (taskInfo.appCompatTaskInfo.topActivityAppBounds.isEmpty) {
            taskInfo.configuration.windowConfiguration.appBounds
                ?: taskInfo.configuration.windowConfiguration.bounds
        } else {
            taskInfo.appCompatTaskInfo.topActivityAppBounds
        }
    return maxOf(appBounds.height(), appBounds.width()) /
        minOf(appBounds.height(), appBounds.width()).toFloat()
}
@@ -233,6 +255,13 @@ fun isTaskBoundsEqual(taskBounds: Rect, stableBounds: Rect): Boolean {
    return taskBounds == stableBounds
}

/** Returns the app header height in desktop mode in pixels. */
fun getAppHeaderHeight(context: Context): Int =
    context.resources.getDimensionPixelSize(getAppHeaderHeightId())

/** Returns the resource id of the app header height in desktop mode. */
@DimenRes fun getAppHeaderHeightId(): Int = R.dimen.desktop_mode_freeform_decor_caption_height

/**
 * Calculates the desired initial bounds for applications in desktop windowing. This is done as a
 * scale of the screen bounds.
+10 −20
Original line number Diff line number Diff line
@@ -41,7 +41,6 @@ import android.os.Handler
import android.os.IBinder
import android.os.SystemProperties
import android.os.UserHandle
import android.util.Size
import android.view.Display.DEFAULT_DISPLAY
import android.view.DragEvent
import android.view.MotionEvent
@@ -1223,7 +1222,6 @@ class DesktopTasksController(
            // and toggle to the stable bounds.
            desktopTilingDecorViewModel.removeTaskIfTiled(taskInfo.displayId, taskInfo.taskId)
            taskRepository.saveBoundsBeforeMaximize(taskInfo.taskId, currentTaskBounds)

            destinationBounds.set(calculateMaximizeBounds(displayLayout, taskInfo))
        }

@@ -1288,23 +1286,6 @@ class DesktopTasksController(
        )
    }

    private fun getMaximizeBounds(taskInfo: RunningTaskInfo, stableBounds: Rect): Rect {
        if (taskInfo.isResizeable) {
            // if resizable then expand to entire stable bounds (full display minus insets)
            return Rect(stableBounds)
        } else {
            // if non-resizable then calculate max bounds according to aspect ratio
            val activityAspectRatio = calculateAspectRatio(taskInfo)
            val newSize =
                maximizeSizeGivenAspectRatio(
                    taskInfo,
                    Size(stableBounds.width(), stableBounds.height()),
                    activityAspectRatio,
                )
            return centerInArea(newSize, stableBounds, stableBounds.left, stableBounds.top)
        }
    }

    private fun isMaximizedToStableBoundsEdges(
        taskInfo: RunningTaskInfo,
        stableBounds: Rect,
@@ -2385,7 +2366,16 @@ class DesktopTasksController(
    ): Rect {
        val bounds =
            if (ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue) {
                calculateInitialBounds(displayLayout, taskInfo)
                // If caption insets should be excluded from app bounds, ensure caption insets
                // are excluded from the ideal initial bounds when scaling non-resizeable apps.
                // Caption insets stay fixed and don't scale with bounds.
                val captionInsets =
                    if (desktopModeCompatPolicy.shouldExcludeCaptionFromAppBounds(taskInfo)) {
                        getAppHeaderHeight(context)
                    } else {
                        0
                    }
                calculateInitialBounds(displayLayout, taskInfo, captionInsets = captionInsets)
            } else {
                calculateDefaultDesktopTaskBounds(displayLayout)
            }
+2 −1
Original line number Diff line number Diff line
@@ -1712,7 +1712,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
                        mWindowDecorViewHostSupplier,
                        mMultiInstanceHelper,
                        mWindowDecorCaptionHandleRepository,
                        mDesktopModeEventLogger);
                        mDesktopModeEventLogger,
                        mDesktopModeCompatPolicy);
        mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);

        final TaskPositioner taskPositioner = mTaskPositionerFactory.create(
+32 −14
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ import com.android.wm.shell.desktopmode.DesktopUserRepositories;
import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.desktopmode.DesktopModeCompatPolicy;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.shared.multiinstance.ManageWindowsViewContainer;
@@ -191,6 +192,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    private final HandleMenuFactory mHandleMenuFactory;
    private final AppToWebGenericLinksParser mGenericLinksParser;
    private final AssistContentRequester mAssistContentRequester;
    private final DesktopModeCompatPolicy mDesktopModeCompatPolicy;

    // Hover state for the maximize menu and button. The menu will remain open as long as either of
    // these is true. See {@link #onMaximizeHoverStateChanged()}.
@@ -232,7 +234,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            @NonNull WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier,
            MultiInstanceHelper multiInstanceHelper,
            WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
            DesktopModeEventLogger desktopModeEventLogger) {
            DesktopModeEventLogger desktopModeEventLogger,
            DesktopModeCompatPolicy desktopModeCompatPolicy) {
        this (context, userContext, displayController, taskResourceLoader, splitScreenController,
                desktopUserRepositories, taskOrganizer, taskInfo, taskSurface, handler,
                mainExecutor, mainDispatcher, bgScope, bgExecutor, choreographer, syncQueue,
@@ -245,7 +248,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                windowDecorViewHostSupplier,
                DefaultMaximizeMenuFactory.INSTANCE,
                DefaultHandleMenuFactory.INSTANCE, multiInstanceHelper,
                windowDecorCaptionHandleRepository, desktopModeEventLogger);
                windowDecorCaptionHandleRepository, desktopModeEventLogger,
                desktopModeCompatPolicy);
    }

    DesktopModeWindowDecoration(
@@ -280,7 +284,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            HandleMenuFactory handleMenuFactory,
            MultiInstanceHelper multiInstanceHelper,
            WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
            DesktopModeEventLogger desktopModeEventLogger) {
            DesktopModeEventLogger desktopModeEventLogger,
            DesktopModeCompatPolicy desktopModeCompatPolicy) {
        super(context, userContext, displayController, taskOrganizer, taskInfo,
                taskSurface, surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
                windowContainerTransactionSupplier, surfaceControlSupplier,
@@ -305,6 +310,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        mDesktopUserRepositories = desktopUserRepositories;
        mTaskResourceLoader = taskResourceLoader;
        mTaskResourceLoader.onWindowDecorCreated(taskInfo);
        mDesktopModeCompatPolicy = desktopModeCompatPolicy;
    }

    /**
@@ -507,7 +513,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                applyStartTransactionOnDraw, shouldSetTaskVisibilityPositionAndCrop,
                mIsStatusBarVisible, mIsKeyguardVisibleAndOccluded, inFullImmersive,
                mDisplayController.getInsetsState(taskInfo.displayId), hasGlobalFocus,
                displayExclusionRegion, mIsRecentsTransitionRunning);
                displayExclusionRegion, mIsRecentsTransitionRunning,
                mDesktopModeCompatPolicy.shouldExcludeCaptionFromAppBounds(taskInfo));

        final WindowDecorLinearLayout oldRootView = mResult.mRootView;
        final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
@@ -891,7 +898,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            @NonNull InsetsState displayInsetsState,
            boolean hasGlobalFocus,
            @NonNull Region displayExclusionRegion,
            boolean shouldIgnoreCornerRadius) {
            boolean shouldIgnoreCornerRadius,
            boolean shouldExcludeCaptionFromAppBounds) {
        final int captionLayoutId = getDesktopModeWindowDecorLayoutId(taskInfo.getWindowingMode());
        final boolean isAppHeader =
                captionLayoutId == R.layout.desktop_mode_app_header;
@@ -951,16 +959,24 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                }
            } else {
                if (ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue()) {
                    // Force-consume the caption bar insets when the app tries to hide the caption.
                    // This improves app compatibility of immersive apps.
                    if (shouldExcludeCaptionFromAppBounds) {
                        relayoutParams.mShouldSetAppBounds = true;
                    } else {
                        // Force-consume the caption bar insets when the app tries to hide the
                        // caption. This improves app compatibility of immersive apps.
                        relayoutParams.mInsetSourceFlags |= FLAG_FORCE_CONSUMING;
                    }
                }
            }
            if (ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS.isTrue()) {
                if (shouldExcludeCaptionFromAppBounds) {
                    relayoutParams.mShouldSetAppBounds = true;
                } else {
                    // Always force-consume the caption bar insets for maximum app compatibility,
                    // including non-immersive apps that just don't handle caption insets properly.
                    relayoutParams.mInsetSourceFlags |= FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
                }
            }
            if (DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue()
                    && inFullImmersiveMode) {
                final Insets systemBarInsets = displayInsetsState.calculateInsets(
@@ -1747,7 +1763,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    private static int getCaptionHeightIdStatic(@WindowingMode int windowingMode) {
        return windowingMode == WINDOWING_MODE_FULLSCREEN
                ? com.android.internal.R.dimen.status_bar_height_default
                : R.dimen.desktop_mode_freeform_decor_caption_height;
                : DesktopModeUtils.getAppHeaderHeightId();
    }

    private int getCaptionHeight(@WindowingMode int windowingMode) {
@@ -1845,7 +1861,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                        windowDecorViewHostSupplier,
                MultiInstanceHelper multiInstanceHelper,
                WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
                DesktopModeEventLogger desktopModeEventLogger) {
                DesktopModeEventLogger desktopModeEventLogger,
                DesktopModeCompatPolicy desktopModeCompatPolicy) {
            return new DesktopModeWindowDecoration(
                    context,
                    userContext,
@@ -1870,7 +1887,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                    windowDecorViewHostSupplier,
                    multiInstanceHelper,
                    windowDecorCaptionHandleRepository,
                    desktopModeEventLogger);
                    desktopModeEventLogger,
                    desktopModeCompatPolicy);
        }
    }

Loading