diff options
| author | Adrian Roos <roosa@google.com> | 2018-08-24 16:29:06 +0200 |
|---|---|---|
| committer | Adrian Roos <roosa@google.com> | 2018-10-30 19:09:03 +0100 |
| commit | 60f59298c77dc0a662a2523fcbd5c866ed648518 (patch) | |
| tree | cec09ce20f0ac2ffe2c484e62f50b2ced54a426d /core/java/android/view/WindowInsets.java | |
| parent | b57bfe04b435ca44d5f9c07fa8e7c7d2b0abd5d4 (diff) | |
WindowInsets: reimplement WindowInsets on top of Insets
Bug: 111829774
Test: atest WindowInsetsTest
Change-Id: Ic01c6cd46981af2e457c740c35b17c8cc9c8d25a
Diffstat (limited to 'core/java/android/view/WindowInsets.java')
| -rw-r--r-- | core/java/android/view/WindowInsets.java | 268 |
1 files changed, 147 insertions, 121 deletions
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index 0a0ef985e80f..411be5b45488 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -17,8 +17,10 @@ package android.view; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; +import android.graphics.Insets; import android.graphics.Rect; import com.android.internal.util.Preconditions; @@ -43,26 +45,24 @@ import java.util.Objects; */ public final class WindowInsets { - private Rect mSystemWindowInsets; - private Rect mWindowDecorInsets; - private Rect mStableInsets; - private Rect mTempRect; - private boolean mIsRound; - private DisplayCutout mDisplayCutout; + @NonNull private final Insets mSystemWindowInsets; + @NonNull private final Insets mWindowDecorInsets; + @NonNull private final Insets mStableInsets; + @Nullable private Rect mTempRect; + private final boolean mIsRound; + @Nullable private final DisplayCutout mDisplayCutout; /** * In multi-window we force show the navigation bar. Because we don't want that the surface size * changes in this mode, we instead have a flag whether the navigation bar size should always * be consumed, so the app is treated like there is no virtual navigation bar at all. */ - private boolean mAlwaysConsumeNavBar; + private final boolean mAlwaysConsumeNavBar; - private boolean mSystemWindowInsetsConsumed = false; - private boolean mWindowDecorInsetsConsumed = false; - private boolean mStableInsetsConsumed = false; - private boolean mDisplayCutoutConsumed = false; - - private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0); + private final boolean mSystemWindowInsetsConsumed; + private final boolean mWindowDecorInsetsConsumed; + private final boolean mStableInsetsConsumed; + private final boolean mDisplayCutoutConsumed; /** * Since new insets may be added in the future that existing apps couldn't @@ -74,21 +74,27 @@ public final class WindowInsets { public static final WindowInsets CONSUMED; static { - CONSUMED = new WindowInsets(null, null, null, false, false, null); + CONSUMED = new WindowInsets((Insets) null, null, null, false, false, null); } /** @hide */ public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets, boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) { + this(Insets.of(systemWindowInsets), Insets.of(windowDecorInsets), Insets.of(stableInsets), + isRound, alwaysConsumeNavBar, displayCutout); + } + + private WindowInsets(Insets systemWindowInsets, Insets windowDecorInsets, + Insets stableInsets, boolean isRound, boolean alwaysConsumeNavBar, + DisplayCutout displayCutout) { mSystemWindowInsetsConsumed = systemWindowInsets == null; - mSystemWindowInsets = mSystemWindowInsetsConsumed - ? EMPTY_RECT : new Rect(systemWindowInsets); + mSystemWindowInsets = mSystemWindowInsetsConsumed ? Insets.NONE : systemWindowInsets; mWindowDecorInsetsConsumed = windowDecorInsets == null; - mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : new Rect(windowDecorInsets); + mWindowDecorInsets = mWindowDecorInsetsConsumed ? Insets.NONE : windowDecorInsets; mStableInsetsConsumed = stableInsets == null; - mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : new Rect(stableInsets); + mStableInsets = mStableInsetsConsumed ? Insets.NONE : stableInsets; mIsRound = isRound; mAlwaysConsumeNavBar = alwaysConsumeNavBar; @@ -104,16 +110,21 @@ public final class WindowInsets { * @param src Source to copy insets from */ public WindowInsets(WindowInsets src) { - mSystemWindowInsets = src.mSystemWindowInsets; - mWindowDecorInsets = src.mWindowDecorInsets; - mStableInsets = src.mStableInsets; - mSystemWindowInsetsConsumed = src.mSystemWindowInsetsConsumed; - mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed; - mStableInsetsConsumed = src.mStableInsetsConsumed; - mIsRound = src.mIsRound; - mAlwaysConsumeNavBar = src.mAlwaysConsumeNavBar; - mDisplayCutout = src.mDisplayCutout; - mDisplayCutoutConsumed = src.mDisplayCutoutConsumed; + this(src.mSystemWindowInsetsConsumed ? null : src.mSystemWindowInsets, + src.mWindowDecorInsetsConsumed ? null : src.mWindowDecorInsets, + src.mStableInsetsConsumed ? null : src.mStableInsets, + src.mIsRound, src.mAlwaysConsumeNavBar, + displayCutoutCopyConstructorArgument(src)); + } + + private static DisplayCutout displayCutoutCopyConstructorArgument(WindowInsets w) { + if (w.mDisplayCutoutConsumed) { + return null; + } else if (w.mDisplayCutout == null) { + return DisplayCutout.NO_CUTOUT; + } else { + return w.mDisplayCutout; + } } /** @hide */ @@ -126,14 +137,17 @@ public final class WindowInsets { * Used to provide a safe copy of the system window insets to pass through * to the existing fitSystemWindows method and other similar internals. * @hide + * + * @deprecated use {@link #getSystemWindowInsets()} instead. */ - @UnsupportedAppUsage - public Rect getSystemWindowInsets() { + @Deprecated + public Rect getSystemWindowInsetsAsRect() { if (mTempRect == null) { mTempRect = new Rect(); } if (mSystemWindowInsets != null) { - mTempRect.set(mSystemWindowInsets); + mTempRect.set(mSystemWindowInsets.left, mSystemWindowInsets.top, + mSystemWindowInsets.right, mSystemWindowInsets.bottom); } else { // If there were no system window insets, this is just empty. mTempRect.setEmpty(); @@ -142,6 +156,20 @@ public final class WindowInsets { } /** + * Returns the system window insets in pixels. + * + * <p>The system window inset represents the area of a full-screen window that is + * partially or fully obscured by the status bar, navigation bar, IME or other system windows. + * </p> + * + * @return The system window insets + */ + @NonNull + public Insets getSystemWindowInsets() { + return mSystemWindowInsets; + } + + /** * Returns the left system window inset in pixels. * * <p>The system window inset represents the area of a full-screen window that is @@ -305,10 +333,11 @@ public final class WindowInsets { * @return A modified copy of this WindowInsets */ public WindowInsets consumeDisplayCutout() { - final WindowInsets result = new WindowInsets(this); - result.mDisplayCutout = null; - result.mDisplayCutoutConsumed = true; - return result; + return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets, + mWindowDecorInsetsConsumed ? null : mWindowDecorInsets, + mStableInsetsConsumed ? null : mStableInsets, + mIsRound, mAlwaysConsumeNavBar, + null /* displayCutout */); } @@ -350,100 +379,90 @@ public final class WindowInsets { * @return A modified copy of this WindowInsets */ public WindowInsets consumeSystemWindowInsets() { - final WindowInsets result = new WindowInsets(this); - result.mSystemWindowInsets = EMPTY_RECT; - result.mSystemWindowInsetsConsumed = true; - return result; - } - - /** - * Returns a copy of this WindowInsets with selected system window insets fully consumed. - * - * @param left true to consume the left system window inset - * @param top true to consume the top system window inset - * @param right true to consume the right system window inset - * @param bottom true to consume the bottom system window inset - * @return A modified copy of this WindowInsets - * @hide pending API - */ - public WindowInsets consumeSystemWindowInsets(boolean left, boolean top, - boolean right, boolean bottom) { - if (left || top || right || bottom) { - final WindowInsets result = new WindowInsets(this); - result.mSystemWindowInsets = new Rect( - left ? 0 : mSystemWindowInsets.left, - top ? 0 : mSystemWindowInsets.top, - right ? 0 : mSystemWindowInsets.right, - bottom ? 0 : mSystemWindowInsets.bottom); - return result; - } - return this; + return new WindowInsets(null /* systemWindowInsets */, + mWindowDecorInsetsConsumed ? null : mWindowDecorInsets, + mStableInsetsConsumed ? null : mStableInsets, + mIsRound, mAlwaysConsumeNavBar, + displayCutoutCopyConstructorArgument(this)); } /** * Returns a copy of this WindowInsets with selected system window insets replaced * with new values. * + * <p>Note: If the system window insets are already consumed, this method will return them + * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to + * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of + * whether they were consumed, and this method returns invalid non-zero consumed insets. + * * @param left New left inset in pixels * @param top New top inset in pixels * @param right New right inset in pixels * @param bottom New bottom inset in pixels * @return A modified copy of this WindowInsets */ - public WindowInsets replaceSystemWindowInsets(int left, int top, - int right, int bottom) { - final WindowInsets result = new WindowInsets(this); - result.mSystemWindowInsets = new Rect(left, top, right, bottom); - return result; + public WindowInsets replaceSystemWindowInsets(int left, int top, int right, int bottom) { + // TODO(roosa): deprecate in follow-up CL, once we have a builder for WindowInsets. + + // Compat edge case: what should this do if the insets have already been consumed? + // On platforms prior to Q, the behavior was to override the insets with non-zero values, + // but leave them consumed, which is invalid (consumed insets must be zero). + // The behavior is now keeping them consumed and discarding the new insets. + if (mSystemWindowInsetsConsumed) { + return this; + } + + return new WindowInsets(Insets.of(left, top, right, bottom), + mWindowDecorInsetsConsumed ? null : mWindowDecorInsets, + mStableInsetsConsumed ? null : mStableInsets, + mIsRound, mAlwaysConsumeNavBar, + displayCutoutCopyConstructorArgument(this)); } /** * Returns a copy of this WindowInsets with selected system window insets replaced * with new values. * + * <p>Note: If the system window insets are already consumed, this method will return them + * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to + * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of + * whether they were consumed, and this method returns invalid non-zero consumed insets. + * * @param systemWindowInsets New system window insets. Each field is the inset in pixels * for that edge * @return A modified copy of this WindowInsets */ public WindowInsets replaceSystemWindowInsets(Rect systemWindowInsets) { - final WindowInsets result = new WindowInsets(this); - result.mSystemWindowInsets = new Rect(systemWindowInsets); - return result; + // TODO(roosa): deprecate in follow-up CL, once we have a builder for WindowInsets. + return replaceSystemWindowInsets(systemWindowInsets.left, systemWindowInsets.top, + systemWindowInsets.right, systemWindowInsets.bottom); } /** * @hide */ public WindowInsets consumeWindowDecorInsets() { - final WindowInsets result = new WindowInsets(this); - result.mWindowDecorInsets.set(0, 0, 0, 0); - result.mWindowDecorInsetsConsumed = true; - return result; - } - - /** - * @hide - */ - public WindowInsets consumeWindowDecorInsets(boolean left, boolean top, - boolean right, boolean bottom) { - if (left || top || right || bottom) { - final WindowInsets result = new WindowInsets(this); - result.mWindowDecorInsets = new Rect(left ? 0 : mWindowDecorInsets.left, - top ? 0 : mWindowDecorInsets.top, - right ? 0 : mWindowDecorInsets.right, - bottom ? 0 : mWindowDecorInsets.bottom); - return result; - } - return this; + return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets, + null /* windowDecorInsets */, + mStableInsetsConsumed ? null : mStableInsets, + mIsRound, mAlwaysConsumeNavBar, + displayCutoutCopyConstructorArgument(this)); } /** - * @hide + * Returns the stable insets in pixels. + * + * <p>The stable inset represents the area of a full-screen window that <b>may</b> be + * partially or fully obscured by the system UI elements. This value does not change + * based on the visibility state of those elements; for example, if the status bar is + * normally shown, but temporarily hidden, the stable inset will still provide the inset + * associated with the status bar being shown.</p> + * + * @return The stable insets */ - public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) { - final WindowInsets result = new WindowInsets(this); - result.mWindowDecorInsets = new Rect(left, top, right, bottom); - return result; + @NonNull + public Insets getStableInsets() { + return mStableInsets; } /** @@ -528,10 +547,11 @@ public final class WindowInsets { * @return A modified copy of this WindowInsets */ public WindowInsets consumeStableInsets() { - final WindowInsets result = new WindowInsets(this); - result.mStableInsets = EMPTY_RECT; - result.mStableInsetsConsumed = true; - return result; + return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets, + mWindowDecorInsetsConsumed ? null : mWindowDecorInsets, + null /* stableInsets */, + mIsRound, mAlwaysConsumeNavBar, + displayCutoutCopyConstructorArgument(this)); } /** @@ -555,8 +575,10 @@ public final class WindowInsets { * Returns a copy of this instance inset in the given directions. * * @see #inset(int, int, int, int) + * @deprecated use {@link #inset(Insets)} * @hide */ + @Deprecated public WindowInsets inset(Rect r) { return inset(r.left, r.top, r.right, r.bottom); } @@ -564,6 +586,16 @@ public final class WindowInsets { /** * Returns a copy of this instance inset in the given directions. * + * @see #inset(int, int, int, int) + * @hide + */ + public WindowInsets inset(Insets insets) { + return inset(insets.left, insets.top, insets.right, insets.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. * @@ -587,25 +619,19 @@ public final class WindowInsets { 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; + return new WindowInsets( + mSystemWindowInsetsConsumed ? null : + insetInsets(mSystemWindowInsets, left, top, right, bottom), + mWindowDecorInsetsConsumed ? null : + insetInsets(mWindowDecorInsets, left, top, right, bottom), + mStableInsetsConsumed ? null : + insetInsets(mStableInsets, left, top, right, bottom), + mIsRound, mAlwaysConsumeNavBar, + mDisplayCutoutConsumed + ? null : + mDisplayCutout == null + ? DisplayCutout.NO_CUTOUT + : mDisplayCutout.inset(left, top, right, bottom)); } @Override @@ -632,7 +658,7 @@ public final class WindowInsets { mWindowDecorInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed); } - private static Rect insetInsets(Rect insets, int left, int top, int right, int bottom) { + private static Insets insetInsets(Insets 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); @@ -640,7 +666,7 @@ public final class WindowInsets { if (newLeft == left && newTop == top && newRight == right && newBottom == bottom) { return insets; } - return new Rect(newLeft, newTop, newRight, newBottom); + return Insets.of(newLeft, newTop, newRight, newBottom); } /** |
