diff options
| author | TreeHugger Robot <treehugger-gerrit@google.com> | 2018-05-18 22:12:30 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-05-18 22:12:30 +0000 |
| commit | 177ee3d7a128fe0ea997efad9fb2e537c04890d9 (patch) | |
| tree | 0867383140cb4197a4f45c600e3c8cb105e6efa5 /core/java | |
| parent | 9335f1e3637af9c2b146ab1ff2cf60349d538e0d (diff) | |
| parent | f7b7426d81c5365473d00362cf158aa5ae35cee3 (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.java | 42 | ||||
| -rw-r--r-- | core/java/android/view/WindowInsets.java | 117 | ||||
| -rw-r--r-- | core/java/com/android/internal/policy/DecorView.java | 19 | ||||
| -rw-r--r-- | core/java/com/android/internal/widget/ActionBarOverlayLayout.java | 36 |
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); |
