summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorTiger Huang <tigerhuang@google.com>2021-10-27 10:37:03 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2021-10-27 10:37:03 +0000
commit2df7ff30624727bdfba31c180136ce119ac49bb6 (patch)
tree1bc98dfd5fd10fd289e916c20bc856797ebc49ab /core/java
parente2089c7794858c145b92b13747731eb2f4f3a76d (diff)
parent5210f9646fa739e898f8c44ee8274387d1acb699 (diff)
Merge "Move all the window layout logic to WindowLayout"
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/view/ViewRootImpl.java23
-rw-r--r--core/java/android/view/WindowLayout.java145
2 files changed, 155 insertions, 13 deletions
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6b5cc97d875f..4879206d6190 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -57,12 +57,15 @@ import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+import static android.view.WindowLayout.UNSPECIFIED_LENGTH;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED;
@@ -72,6 +75,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_V
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
@@ -90,6 +94,7 @@ import android.annotation.UiContext;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ResourcesManager;
+import android.app.WindowConfiguration;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -515,6 +520,8 @@ public final class ViewRootImpl implements ViewParent,
private final WindowLayout mWindowLayout = new WindowLayout();
+ private ViewRootImpl mParentViewRoot;
+
// This is used to reduce the race between window focus changes being dispatched from
// the window manager and input events coming through the input system.
@GuardedBy("this")
@@ -1053,6 +1060,7 @@ public final class ViewRootImpl implements ViewParent,
if (panelParentView != null) {
mAttachInfo.mPanelParentWindowToken
= panelParentView.getApplicationWindowToken();
+ mParentViewRoot = panelParentView.getViewRootImpl();
}
mAdded = true;
int res; /* = WindowManagerImpl.ADD_OKAY; */
@@ -1113,10 +1121,13 @@ public final class ViewRootImpl implements ViewParent,
final InsetsState state = mInsetsController.getState();
final Rect displayCutoutSafe = mTempRect;
state.getDisplayCutoutSafe(displayCutoutSafe);
+ final WindowConfiguration winConfig = getConfiguration().windowConfiguration;
mWindowLayout.computeWindowFrames(mWindowAttributes, state,
- displayCutoutSafe, getConfiguration().windowConfiguration.getBounds(),
+ displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
+ UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
mInsetsController.getRequestedVisibilities(),
- null /* attachedWindowFrame */, mTmpFrames.frame, mTempRect2);
+ getAttachedWindowFrame(), 1f /* compactScale */,
+ mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame);
setFrame(mTmpFrames.frame);
if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
if (res < WindowManagerGlobal.ADD_OKAY) {
@@ -1227,6 +1238,14 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ private Rect getAttachedWindowFrame() {
+ final int type = mWindowAttributes.type;
+ final boolean layoutAttached = (mParentViewRoot != null
+ && type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW
+ && type != TYPE_APPLICATION_ATTACHED_DIALOG);
+ return layoutAttached ? mParentViewRoot.mWinFrame : null;
+ }
+
/**
* Register any kind of listeners if setView was success.
*/
diff --git a/core/java/android/view/WindowLayout.java b/core/java/android/view/WindowLayout.java
index cdc1977eaad6..7dfc95ef0302 100644
--- a/core/java/android/view/WindowLayout.java
+++ b/core/java/android/view/WindowLayout.java
@@ -19,29 +19,44 @@ package android.view;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
+import android.app.WindowConfiguration;
+import android.app.WindowConfiguration.WindowingMode;
import android.graphics.Insets;
import android.graphics.Rect;
+import android.util.Log;
/**
* Computes window frames.
* @hide
*/
public class WindowLayout {
+ private static final String TAG = WindowLayout.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ public static final int UNSPECIFIED_LENGTH = -1;
+
private final Rect mTempDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
private final Rect mTempRect = new Rect();
public boolean computeWindowFrames(WindowManager.LayoutParams attrs, InsetsState state,
- Rect displayCutoutSafe, Rect windowBounds, InsetsVisibilities requestedVisibilities,
- Rect attachedWindowFrame, Rect outDisplayFrame, Rect outParentFrame) {
+ Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode,
+ int requestedWidth, int requestedHeight, InsetsVisibilities requestedVisibilities,
+ Rect attachedWindowFrame, float compatScale, Rect outDisplayFrame, Rect outParentFrame,
+ Rect outFrame) {
final int type = attrs.type;
final int fl = attrs.flags;
final int pfl = attrs.privateFlags;
@@ -72,18 +87,14 @@ public class WindowLayout {
}
// Compute bounds restricted by display cutout
+ final int cutoutMode = attrs.layoutInDisplayCutoutMode;
final DisplayCutout cutout = state.getDisplayCutout();
- if (cutout.isEmpty()) {
- return false;
- }
- boolean clippedByDisplayCutout = false;
final Rect displayCutoutSafeExceptMaybeBars = mTempDisplayCutoutSafeExceptMaybeBarsRect;
displayCutoutSafeExceptMaybeBars.set(displayCutoutSafe);
-
- // Ensure that windows with a non-ALWAYS display cutout mode are laid out in
- // the cutout safe zone.
- final int cutoutMode = attrs.layoutInDisplayCutoutMode;
- if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
+ boolean clippedByDisplayCutout = false;
+ if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !cutout.isEmpty()) {
+ // Ensure that windows with a non-ALWAYS display cutout mode are laid out in
+ // the cutout safe zone.
final Rect displayFrame = state.getDisplayFrame();
final InsetsSource statusBarSource = state.peekSource(ITYPE_STATUS_BAR);
if (statusBarSource != null && displayCutoutSafe.top > displayFrame.top) {
@@ -147,6 +158,118 @@ public class WindowLayout {
}
outDisplayFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
}
+
+ final boolean noLimits = (attrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0;
+ final boolean inMultiWindowMode = WindowConfiguration.inMultiWindowMode(windowingMode);
+
+ // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
+ // Also, we don't allow windows in multi-window mode to extend out of the screen.
+ if (noLimits && type != TYPE_SYSTEM_ERROR && !inMultiWindowMode) {
+ outDisplayFrame.left = outDisplayFrame.top = -10000;
+ outDisplayFrame.right = outDisplayFrame.bottom = 10000;
+ }
+
+ final boolean hasCompatScale = compatScale != 1f;
+ final int pw = outParentFrame.width();
+ final int ph = outParentFrame.height();
+ int rw = requestedWidth;
+ int rh = requestedHeight;
+ float x, y;
+ int w, h;
+
+ // If the view hierarchy hasn't been measured, the requested width and height would be
+ // UNSPECIFIED_LENGTH. This can happen in the first layout of a window or in the simulated
+ // layout.
+ if (rw == UNSPECIFIED_LENGTH) {
+ rw = attrs.width >= 0 ? attrs.width : pw;
+ }
+ if (rh == UNSPECIFIED_LENGTH) {
+ rh = attrs.height >= 0 ? attrs.height : ph;
+ }
+
+ if ((attrs.flags & FLAG_SCALED) != 0) {
+ if (attrs.width < 0) {
+ w = pw;
+ } else if (hasCompatScale) {
+ w = (int) (attrs.width * compatScale + .5f);
+ } else {
+ w = attrs.width;
+ }
+ if (attrs.height < 0) {
+ h = ph;
+ } else if (hasCompatScale) {
+ h = (int) (attrs.height * compatScale + .5f);
+ } else {
+ h = attrs.height;
+ }
+ } else {
+ if (attrs.width == MATCH_PARENT) {
+ w = pw;
+ } else if (hasCompatScale) {
+ w = (int) (rw * compatScale + .5f);
+ } else {
+ w = rw;
+ }
+ if (attrs.height == MATCH_PARENT) {
+ h = ph;
+ } else if (hasCompatScale) {
+ h = (int) (rh * compatScale + .5f);
+ } else {
+ h = rh;
+ }
+ }
+
+ if (hasCompatScale) {
+ x = attrs.x * compatScale;
+ y = attrs.y * compatScale;
+ } else {
+ x = attrs.x;
+ y = attrs.y;
+ }
+
+ if (inMultiWindowMode
+ && (attrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) == 0) {
+ // Make sure window fits in parent frame since it is in a non-fullscreen task as
+ // required by {@link Gravity#apply} call.
+ w = Math.min(w, pw);
+ h = Math.min(h, ph);
+ }
+
+ // We need to fit it to the display if either
+ // a) The window is in a fullscreen container, or we don't have a task (we assume fullscreen
+ // for the taskless windows)
+ // b) If it's a secondary app window, we also need to fit it to the display unless
+ // FLAG_LAYOUT_NO_LIMITS is set. This is so we place Popups, dialogs, and similar windows on
+ // screen, but SurfaceViews want to be always at a specific location so we don't fit it to
+ // the display.
+ final boolean fitToDisplay = !inMultiWindowMode
+ || ((attrs.type != TYPE_BASE_APPLICATION) && !noLimits);
+
+ // Set mFrame
+ Gravity.apply(attrs.gravity, w, h, outParentFrame,
+ (int) (x + attrs.horizontalMargin * pw),
+ (int) (y + attrs.verticalMargin * ph), outFrame);
+ // Now make sure the window fits in the overall display frame.
+ if (fitToDisplay) {
+ Gravity.applyDisplay(attrs.gravity, outDisplayFrame, outFrame);
+ }
+
+ if (DEBUG) Log.d(TAG, "computeWindowFrames " + attrs.getTitle()
+ + " outFrame=" + outFrame.toShortString()
+ + " outParentFrame=" + outParentFrame.toShortString()
+ + " outDisplayFrame=" + outDisplayFrame.toShortString()
+ + " attachedWindowFrame=" + (attachedWindowFrame != null
+ ? attachedWindowFrame.toShortString()
+ : "null")
+ + " requestedWidth=" + requestedWidth
+ + " requestedHeight=" + requestedHeight
+ + " compatScale=" + compatScale
+ + " windowingMode=" + WindowConfiguration.windowingModeToString(windowingMode)
+ + " displayCutoutSafe=" + displayCutoutSafe
+ + " attrs=" + attrs
+ + " state=" + state
+ + " requestedVisibilities=" + requestedVisibilities);
+
return clippedByDisplayCutout;
}
}