summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorTreeHugger Robot <treehugger-gerrit@google.com>2018-05-18 22:12:30 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2018-05-18 22:12:30 +0000
commit177ee3d7a128fe0ea997efad9fb2e537c04890d9 (patch)
tree0867383140cb4197a4f45c600e3c8cb105e6efa5 /core/java
parent9335f1e3637af9c2b146ab1ff2cf60349d538e0d (diff)
parentf7b7426d81c5365473d00362cf158aa5ae35cee3 (diff)
Merge "Display Cutout: Fix ActionBarOverlayLayout to properly dispatch cutout" into pi-dev
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/view/View.java42
-rw-r--r--core/java/android/view/WindowInsets.java117
-rw-r--r--core/java/com/android/internal/policy/DecorView.java19
-rw-r--r--core/java/com/android/internal/widget/ActionBarOverlayLayout.java36
4 files changed, 165 insertions, 49 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 049d34f7c15d..172e248d3d3f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9838,26 +9838,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* @hide Compute the insets that should be consumed by this view and the ones
* that should propagate to those under it.
+ *
+ * Note: This is used by appcompat's ActionBarOverlayLayout through reflection.
+ *
+ * @param inoutInsets the insets given to this view
+ * @param outLocalInsets the insets that should be applied to this view
+ * @deprecated use {@link #computeSystemWindowInsets}
+ * @return
*/
+ @Deprecated
protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) {
- if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
- || mAttachInfo == null
- || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0
- && !mAttachInfo.mOverscanRequested)) {
- outLocalInsets.set(inoutInsets);
- inoutInsets.set(0, 0, 0, 0);
- return true;
- } else {
- // The application wants to take care of fitting system window for
- // the content... however we still need to take care of any overscan here.
- final Rect overscan = mAttachInfo.mOverscanInsets;
- outLocalInsets.set(overscan);
- inoutInsets.left -= overscan.left;
- inoutInsets.top -= overscan.top;
- inoutInsets.right -= overscan.right;
- inoutInsets.bottom -= overscan.bottom;
- return false;
- }
+ WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets),
+ outLocalInsets);
+ inoutInsets.set(innerInsets.getSystemWindowInsets());
+ return innerInsets.isSystemWindowInsetsConsumed();
}
/**
@@ -9873,12 +9867,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) {
if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
|| mAttachInfo == null
- || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) {
+ || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0
+ && !mAttachInfo.mOverscanRequested)) {
outLocalInsets.set(in.getSystemWindowInsets());
- return in.consumeSystemWindowInsets();
+ return in.consumeSystemWindowInsets().inset(outLocalInsets);
} else {
- outLocalInsets.set(0, 0, 0, 0);
- return in;
+ // The application wants to take care of fitting system window for
+ // the content... however we still need to take care of any overscan here.
+ final Rect overscan = mAttachInfo.mOverscanInsets;
+ outLocalInsets.set(overscan);
+ return in.inset(outLocalInsets);
}
}
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index e5cbe96b9173..fbd8141ae27a 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -20,6 +20,10 @@ package android.view;
import android.annotation.Nullable;
import android.graphics.Rect;
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
/**
* Describes a set of insets for window content.
*
@@ -27,6 +31,12 @@ import android.graphics.Rect;
* To adjust insets, use one of the supplied clone methods to obtain a new WindowInsets instance
* with the adjusted properties.</p>
*
+ * <p>Note: Before {@link android.os.Build.VERSION_CODES#P P}, WindowInsets instances were only
+ * immutable during a single layout pass (i.e. would return the same values between
+ * {@link View#onApplyWindowInsets} and {@link View#onLayout}, but could return other values
+ * otherwise). Starting with {@link android.os.Build.VERSION_CODES#P P}, WindowInsets are
+ * always immutable and implement equality.
+ *
* @see View.OnApplyWindowInsetsListener
* @see View#onApplyWindowInsets(WindowInsets)
*/
@@ -69,13 +79,14 @@ public final class WindowInsets {
public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets,
boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
mSystemWindowInsetsConsumed = systemWindowInsets == null;
- mSystemWindowInsets = mSystemWindowInsetsConsumed ? EMPTY_RECT : systemWindowInsets;
+ mSystemWindowInsets = mSystemWindowInsetsConsumed
+ ? EMPTY_RECT : new Rect(systemWindowInsets);
mWindowDecorInsetsConsumed = windowDecorInsets == null;
- mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : windowDecorInsets;
+ mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : new Rect(windowDecorInsets);
mStableInsetsConsumed = stableInsets == null;
- mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : stableInsets;
+ mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : new Rect(stableInsets);
mIsRound = isRound;
mAlwaysConsumeNavBar = alwaysConsumeNavBar;
@@ -535,4 +546,104 @@ public final class WindowInsets {
+ (isRound() ? " round" : "")
+ "}";
}
+
+ /**
+ * Returns a copy of this instance inset in the given directions.
+ *
+ * @see #inset(int, int, int, int)
+ * @hide
+ */
+ public WindowInsets inset(Rect r) {
+ return inset(r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * Returns a copy of this instance inset in the given directions.
+ *
+ * This is intended for dispatching insets to areas of the window that are smaller than the
+ * current area.
+ *
+ * <p>Example:
+ * <pre>
+ * childView.dispatchApplyWindowInsets(insets.inset(
+ * childMarginLeft, childMarginTop, childMarginBottom, childMarginRight));
+ * </pre>
+ *
+ * @param left the amount of insets to remove from the left. Must be non-negative.
+ * @param top the amount of insets to remove from the top. Must be non-negative.
+ * @param right the amount of insets to remove from the right. Must be non-negative.
+ * @param bottom the amount of insets to remove from the bottom. Must be non-negative.
+ *
+ * @return the inset insets
+ *
+ * @hide pending API
+ */
+ public WindowInsets inset(int left, int top, int right, int bottom) {
+ Preconditions.checkArgumentNonnegative(left);
+ Preconditions.checkArgumentNonnegative(top);
+ Preconditions.checkArgumentNonnegative(right);
+ Preconditions.checkArgumentNonnegative(bottom);
+
+ WindowInsets result = new WindowInsets(this);
+ if (!result.mSystemWindowInsetsConsumed) {
+ result.mSystemWindowInsets =
+ insetInsets(result.mSystemWindowInsets, left, top, right, bottom);
+ }
+ if (!result.mWindowDecorInsetsConsumed) {
+ result.mWindowDecorInsets =
+ insetInsets(result.mWindowDecorInsets, left, top, right, bottom);
+ }
+ if (!result.mStableInsetsConsumed) {
+ result.mStableInsets = insetInsets(result.mStableInsets, left, top, right, bottom);
+ }
+ if (mDisplayCutout != null) {
+ result.mDisplayCutout = result.mDisplayCutout.inset(left, top, right, bottom);
+ if (result.mDisplayCutout.isEmpty()) {
+ result.mDisplayCutout = null;
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof WindowInsets)) return false;
+ WindowInsets that = (WindowInsets) o;
+ return mIsRound == that.mIsRound
+ && mAlwaysConsumeNavBar == that.mAlwaysConsumeNavBar
+ && mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed
+ && mWindowDecorInsetsConsumed == that.mWindowDecorInsetsConsumed
+ && mStableInsetsConsumed == that.mStableInsetsConsumed
+ && mDisplayCutoutConsumed == that.mDisplayCutoutConsumed
+ && Objects.equals(mSystemWindowInsets, that.mSystemWindowInsets)
+ && Objects.equals(mWindowDecorInsets, that.mWindowDecorInsets)
+ && Objects.equals(mStableInsets, that.mStableInsets)
+ && Objects.equals(mDisplayCutout, that.mDisplayCutout);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSystemWindowInsets, mWindowDecorInsets, mStableInsets, mIsRound,
+ mDisplayCutout, mAlwaysConsumeNavBar, mSystemWindowInsetsConsumed,
+ mWindowDecorInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed);
+ }
+
+ private static Rect insetInsets(Rect insets, int left, int top, int right, int bottom) {
+ int newLeft = Math.max(0, insets.left - left);
+ int newTop = Math.max(0, insets.top - top);
+ int newRight = Math.max(0, insets.right - right);
+ int newBottom = Math.max(0, insets.bottom - bottom);
+ if (newLeft == left && newTop == top && newRight == right && newBottom == bottom) {
+ return insets;
+ }
+ return new Rect(newLeft, newTop, newRight, newBottom);
+ }
+
+ /**
+ * @return whether system window insets have been consumed.
+ */
+ boolean isSystemWindowInsetsConsumed() {
+ return mSystemWindowInsetsConsumed;
+ }
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 2db573918e8a..465957d7cfd0 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -983,14 +983,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
if (attrs.height == WindowManager.LayoutParams.WRAP_CONTENT) {
mFloatingInsets.top = insets.getSystemWindowInsetTop();
mFloatingInsets.bottom = insets.getSystemWindowInsetBottom();
- insets = insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), 0,
- insets.getSystemWindowInsetRight(), 0);
+ insets = insets.inset(0, insets.getSystemWindowInsetTop(),
+ 0, insets.getSystemWindowInsetBottom());
}
if (mWindow.getAttributes().width == WindowManager.LayoutParams.WRAP_CONTENT) {
mFloatingInsets.left = insets.getSystemWindowInsetTop();
mFloatingInsets.right = insets.getSystemWindowInsetBottom();
- insets = insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(),
- 0, insets.getSystemWindowInsetBottom());
+ insets = insets.inset(insets.getSystemWindowInsetLeft(), 0,
+ insets.getSystemWindowInsetRight(), 0);
}
}
mFrameOffsets.set(insets.getSystemWindowInsets());
@@ -1158,11 +1158,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
}
if (insets != null) {
- insets = insets.replaceSystemWindowInsets(
- insets.getSystemWindowInsetLeft() - consumedLeft,
- insets.getSystemWindowInsetTop() - consumedTop,
- insets.getSystemWindowInsetRight() - consumedRight,
- insets.getSystemWindowInsetBottom() - consumedBottom);
+ insets = insets.inset(consumedLeft, consumedTop, consumedRight, consumedBottom);
}
}
@@ -1383,8 +1379,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
// screen_simple_overlay_action_mode.xml).
final boolean nonOverlay = (mWindow.getLocalFeaturesPrivate()
& (1 << Window.FEATURE_ACTION_MODE_OVERLAY)) == 0;
- insets = insets.consumeSystemWindowInsets(
- false, nonOverlay && showStatusGuard /* top */, false, false);
+ if (nonOverlay && showStatusGuard) {
+ insets = insets.inset(0, insets.getSystemWindowInsetTop(), 0, 0);
+ }
} else {
// reset top margin
if (mlp.topMargin != 0) {
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 5d7fa6a742be..4a1c95532ba0 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -75,10 +75,10 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
private final Rect mBaseContentInsets = new Rect();
private final Rect mLastBaseContentInsets = new Rect();
private final Rect mContentInsets = new Rect();
- private final Rect mBaseInnerInsets = new Rect();
- private final Rect mLastBaseInnerInsets = new Rect();
- private final Rect mInnerInsets = new Rect();
- private final Rect mLastInnerInsets = new Rect();
+ private WindowInsets mBaseInnerInsets = WindowInsets.CONSUMED;
+ private WindowInsets mLastBaseInnerInsets = WindowInsets.CONSUMED;
+ private WindowInsets mInnerInsets = WindowInsets.CONSUMED;
+ private WindowInsets mLastInnerInsets = WindowInsets.CONSUMED;
private ActionBarVisibilityCallback mActionBarVisibilityCallback;
@@ -322,11 +322,14 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
changed |= applyInsets(mActionBarBottom, systemInsets, true, false, true, true);
}
- mBaseInnerInsets.set(systemInsets);
- computeFitSystemWindows(mBaseInnerInsets, mBaseContentInsets);
+ // Cannot use the result of computeSystemWindowInsets, because that consumes the
+ // systemWindowInsets. Instead, we do the insetting by the local insets ourselves.
+ computeSystemWindowInsets(insets, mBaseContentInsets);
+ mBaseInnerInsets = insets.inset(mBaseContentInsets);
+
if (!mLastBaseInnerInsets.equals(mBaseInnerInsets)) {
changed = true;
- mLastBaseContentInsets.set(mBaseContentInsets);
+ mLastBaseInnerInsets = mBaseInnerInsets;
}
if (!mLastBaseContentInsets.equals(mBaseContentInsets)) {
changed = true;
@@ -430,22 +433,29 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
// will still be covered by the action bar if they have requested it to
// overlay.
mContentInsets.set(mBaseContentInsets);
- mInnerInsets.set(mBaseInnerInsets);
+ mInnerInsets = mBaseInnerInsets;
if (!mOverlayMode && !stable) {
mContentInsets.top += topInset;
mContentInsets.bottom += bottomInset;
+ // Content view has been shrunk, shrink all insets to match.
+ mInnerInsets = mInnerInsets.inset(0 /* left */, topInset, 0 /* right */, bottomInset);
} else {
- mInnerInsets.top += topInset;
- mInnerInsets.bottom += bottomInset;
+ // Add ActionBar to system window inset, but leave other insets untouched.
+ mInnerInsets = mInnerInsets.replaceSystemWindowInsets(
+ mInnerInsets.getSystemWindowInsetLeft(),
+ mInnerInsets.getSystemWindowInsetTop() + topInset,
+ mInnerInsets.getSystemWindowInsetRight(),
+ mInnerInsets.getSystemWindowInsetBottom() + bottomInset
+ );
}
applyInsets(mContent, mContentInsets, true, true, true, true);
if (!mLastInnerInsets.equals(mInnerInsets)) {
// If the inner insets have changed, we need to dispatch this down to
- // the app's fitSystemWindows(). We do this before measuring the content
+ // the app's onApplyWindowInsets(). We do this before measuring the content
// view to keep the same semantics as the normal fitSystemWindows() call.
- mLastInnerInsets.set(mInnerInsets);
- mContent.dispatchApplyWindowInsets(new WindowInsets(mInnerInsets));
+ mLastInnerInsets = mInnerInsets;
+ mContent.dispatchApplyWindowInsets(mInnerInsets);
}
measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0);