diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 4676cc4620f09..a4e5b9049e9d9 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -576,6 +576,16 @@ public class ActivityManager { || targetStackId == FREEFORM_WORKSPACE_STACK_ID; } + /** + * Return whether a stackId is a stack containing floating windows. Floating windows + * are laid out differently as they are allowed to extend past the display bounds + * without overscan insets. + */ + public static boolean tasksAreFloating(int stackId) { + return stackId == FREEFORM_WORKSPACE_STACK_ID + || stackId == PINNED_STACK_ID; + } + /** * Returns true if animation specs should be constructed for app transition that moves * the task to the specified stack. diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index c7b559904209c..f097eb242bfa7 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; @@ -685,6 +686,10 @@ class Task implements DimLayer.DimLayerUser { && mStack != null && StackId.isTaskResizeableByDockedStack(mStack.mStackId); } + boolean isFloating() { + return StackId.tasksAreFloating(mStack.mStackId); + } + /** * Whether the task should be treated as if it's docked. Returns true if the task * is currently in docked workspace, or it's side-by-side to a docked task. diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index e8f1b5d8d3269..c1f4021caf4f7 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -635,7 +635,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { final Task task = getTask(); final boolean fullscreenTask = task == null || task.isFullscreen(); - final boolean freeformWorkspace = task != null && task.inFreeformWorkspace(); + final boolean windowsAreFloating = task != null && task.isFloating(); if (fullscreenTask || (isChildWindow() && (mAttrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0)) { @@ -661,10 +661,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { mContainingFrame.top -= mContainingFrame.bottom - cf.bottom; } - if (freeformWorkspace) { - // In free form mode we have only to set the rectangle if it wasn't set already. No - // need to intersect it with the (visible) "content frame" since it is allowed to - // be outside the visible desktop. + if (windowsAreFloating) { + // In floating modes (e.g. freeform, pinned) we have only to set the rectangle + // if it wasn't set already. No need to intersect it with the (visible) + // "content frame" since it is allowed to be outside the visible desktop. if (mContainingFrame.isEmpty()) { mContainingFrame.set(cf); } @@ -720,7 +720,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { // Make sure the content and visible frames are inside of the // final window frame. - if (freeformWorkspace && !mFrame.isEmpty()) { + if (windowsAreFloating && !mFrame.isEmpty()) { // Keep the frame out of the blocked system area, limit it in size to the content area // and make sure that there is always a minimum visible so that the user can drag it // into a usable area.. @@ -772,9 +772,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { Math.min(mStableFrame.bottom, frame.bottom)); } - if (!inFreeformWorkspace()) { - // Freeform windows can be positioned outside of the display frame, but that is not a - // reason to provide them with overscan insets. + if (!windowsAreFloating) { + // Windows from floating tasks (e.g. freeform, pinned) may be positioned outside + // of the display frame, but that is not a reason to provide them with overscan insets. mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0), Math.max(mOverscanFrame.top - frame.top, 0), Math.max(frame.right - mOverscanFrame.right, 0), @@ -2485,7 +2485,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { final int ph = mContainingFrame.height(); final Task task = getTask(); final boolean nonFullscreenTask = task != null && !task.isFullscreen(); - + final boolean fitToDisplay = task != null && + !task.isFloating(); float x, y; int w,h; @@ -2542,7 +2543,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { (int) (y + mAttrs.verticalMargin * ph), mFrame); // Now make sure the window fits in the overall display frame. - Gravity.applyDisplay(mAttrs.gravity, mDisplayFrame, mFrame); + if (fitToDisplay) { + Gravity.applyDisplay(mAttrs.gravity, mDisplayFrame, mFrame); + } } boolean isChildWindow() {