From 11dfd279a33e126d2df847656bf73fd92df79218 Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Mon, 25 Mar 2019 19:21:26 +0100 Subject: WindowInsets: populate system gesture and tappable element insets Also fixes an infinite recursion when invoking TestableContext.(un)registerComponentCallbacks(). Test: atest WindowInsetsPolicyTest Bug: 126511573 Change-Id: I5c9f40054493a83746bce6124d72412e8eb8a0d1 --- core/java/android/view/InsetsState.java | 79 +++++++++++++++++----- core/java/android/view/ViewRootImpl.java | 14 ++-- core/java/android/view/WindowInsets.java | 7 -- core/res/res/values/config.xml | 6 ++ core/res/res/values/symbols.xml | 2 + packages/SystemUI/res/values/dimens.xml | 2 - .../systemui/shared/system/QuickStepContract.java | 18 +++++ .../phone/NavigationPrototypeController.java | 27 ++++++-- .../statusbar/phone/QuickStepController.java | 8 +-- .../res/values/config.xml | 9 ++- .../java/com/android/server/wm/DisplayPolicy.java | 51 +++++++++++++- .../src/android/testing/TestableContext.java | 4 +- 12 files changed, 173 insertions(+), 54 deletions(-) diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 13b0cc038fce..b76f2a175346 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -17,7 +17,10 @@ package android.view; import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; +import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; +import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES; import static android.view.WindowInsets.Type.SIZE; +import static android.view.WindowInsets.Type.SYSTEM_GESTURES; import static android.view.WindowInsets.Type.indexOf; import android.annotation.IntDef; @@ -55,6 +58,12 @@ public class InsetsState implements Parcelable { TYPE_SIDE_BAR_1, TYPE_SIDE_BAR_2, TYPE_SIDE_BAR_3, + TYPE_TOP_GESTURES, + TYPE_BOTTOM_GESTURES, + TYPE_LEFT_GESTURES, + TYPE_RIGHT_GESTURES, + TYPE_TOP_TAPPABLE_ELEMENT, + TYPE_BOTTOM_TAPPABLE_ELEMENT, TYPE_IME }) public @interface InternalInsetType {} @@ -73,8 +82,16 @@ public class InsetsState implements Parcelable { public static final int TYPE_SIDE_BAR_2 = 2; public static final int TYPE_SIDE_BAR_3 = 3; + public static final int TYPE_TOP_GESTURES = 4; + public static final int TYPE_BOTTOM_GESTURES = 5; + public static final int TYPE_LEFT_GESTURES = 6; + public static final int TYPE_RIGHT_GESTURES = 7; + public static final int TYPE_TOP_TAPPABLE_ELEMENT = 8; + public static final int TYPE_BOTTOM_TAPPABLE_ELEMENT = 9; + /** Input method window. */ - public static final int TYPE_IME = 4; + public static final int TYPE_IME = 10; + static final int LAST_TYPE = TYPE_IME; // Derived types @@ -137,17 +154,6 @@ public class InsetsState implements Parcelable { && legacyContentInsets != null && legacyStableInsets != null) { WindowInsets.assignCompatInsets(typeInsetsMap, legacyContentInsets); WindowInsets.assignCompatInsets(typeMaxInsetsMap, legacyStableInsets); - - // TODO: set system gesture insets based on actual system gesture area. - typeInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets); - typeInsetsMap[Type.indexOf(Type.mandatorySystemGestures())] = - Insets.of(legacyContentInsets); - typeInsetsMap[Type.indexOf(Type.tappableElement())] = Insets.of(legacyContentInsets); - - typeMaxInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyStableInsets); - typeMaxInsetsMap[Type.indexOf(Type.mandatorySystemGestures())] = - Insets.of(legacyStableInsets); - typeMaxInsetsMap[Type.indexOf(Type.tappableElement())] = Insets.of(legacyStableInsets); } for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) { InsetsSource source = mSources.get(type); @@ -159,7 +165,9 @@ public class InsetsState implements Parcelable { && (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR); boolean skipIme = source.getType() == TYPE_IME && (legacySoftInputMode & LayoutParams.SOFT_INPUT_ADJUST_RESIZE) == 0; - if (skipSystemBars || skipIme) { + boolean skipLegacyTypes = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE + && (toPublicType(type) & Type.compatSystemInsets()) != 0; + if (skipSystemBars || skipIme || skipLegacyTypes) { typeVisibilityMap[indexOf(toPublicType(type))] = source.isVisible(); continue; } @@ -183,7 +191,25 @@ public class InsetsState implements Parcelable { @Nullable boolean[] typeVisibilityMap) { Insets insets = source.calculateInsets(relativeFrame, ignoreVisibility); - int index = indexOf(toPublicType(source.getType())); + int type = toPublicType(source.getType()); + processSourceAsPublicType(source, typeInsetsMap, typeSideMap, typeVisibilityMap, + insets, type); + + if (type == MANDATORY_SYSTEM_GESTURES) { + // Mandatory system gestures are also system gestures. + // TODO: find a way to express this more generally. One option would be to define + // Type.systemGestureInsets() as NORMAL | MANDATORY, but then we lose the + // ability to set systemGestureInsets() independently from + // mandatorySystemGestureInsets() in the Builder. + processSourceAsPublicType(source, typeInsetsMap, typeSideMap, typeVisibilityMap, + insets, SYSTEM_GESTURES); + } + } + + private void processSourceAsPublicType(InsetsSource source, Insets[] typeInsetsMap, + @InsetSide @Nullable SparseIntArray typeSideMap, + @Nullable boolean[] typeVisibilityMap, Insets insets, int type) { + int index = indexOf(type); Insets existing = typeInsetsMap[index]; if (existing == null) { typeInsetsMap[index] = insets; @@ -300,6 +326,15 @@ public class InsetsState implements Parcelable { return Type.SIDE_BARS; case TYPE_IME: return Type.IME; + case TYPE_TOP_GESTURES: + case TYPE_BOTTOM_GESTURES: + return Type.MANDATORY_SYSTEM_GESTURES; + case TYPE_LEFT_GESTURES: + case TYPE_RIGHT_GESTURES: + return Type.SYSTEM_GESTURES; + case TYPE_TOP_TAPPABLE_ELEMENT: + case TYPE_BOTTOM_TAPPABLE_ELEMENT: + return Type.TAPPABLE_ELEMENT; default: throw new IllegalArgumentException("Unknown type: " + type); } @@ -336,10 +371,20 @@ public class InsetsState implements Parcelable { return "TYPE_SIDE_BAR_2"; case TYPE_SIDE_BAR_3: return "TYPE_SIDE_BAR_3"; - case TYPE_IME: - return "TYPE_IME"; + case TYPE_TOP_GESTURES: + return "TYPE_TOP_GESTURES"; + case TYPE_BOTTOM_GESTURES: + return "TYPE_BOTTOM_GESTURES"; + case TYPE_LEFT_GESTURES: + return "TYPE_LEFT_GESTURES"; + case TYPE_RIGHT_GESTURES: + return "TYPE_RIGHT_GESTURES"; + case TYPE_TOP_TAPPABLE_ELEMENT: + return "TYPE_TOP_TAPPABLE_ELEMENT"; + case TYPE_BOTTOM_TAPPABLE_ELEMENT: + return "TYPE_BOTTOM_TAPPABLE_ELEMENT"; default: - return "TYPE_UNKNOWN"; + return "TYPE_UNKNOWN_" + type; } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 49166ade34ce..ce1b5f829dba 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1916,16 +1916,10 @@ public final class ViewRootImpl implements ViewParent, } contentInsets = ensureInsetsNonNegative(contentInsets, "content"); stableInsets = ensureInsetsNonNegative(stableInsets, "stable"); - if (sNewInsetsMode != NEW_INSETS_MODE_NONE) { - mLastWindowInsets = mInsetsController.calculateInsets( - mContext.getResources().getConfiguration().isScreenRound(), - mAttachInfo.mAlwaysConsumeSystemBars, displayCutout, - contentInsets, stableInsets, mWindowAttributes.softInputMode); - } else { - mLastWindowInsets = new WindowInsets(contentInsets, stableInsets, - mContext.getResources().getConfiguration().isScreenRound(), - mAttachInfo.mAlwaysConsumeSystemBars, displayCutout); - } + mLastWindowInsets = mInsetsController.calculateInsets( + mContext.getResources().getConfiguration().isScreenRound(), + mAttachInfo.mAlwaysConsumeSystemBars, displayCutout, + contentInsets, stableInsets, mWindowAttributes.softInputMode); } return mLastWindowInsets; } diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index ffa769a424a9..2d292ef7b25c 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -29,9 +29,6 @@ import static android.view.WindowInsets.Type.TOP_BAR; import static android.view.WindowInsets.Type.all; import static android.view.WindowInsets.Type.compatSystemInsets; import static android.view.WindowInsets.Type.indexOf; -import static android.view.WindowInsets.Type.mandatorySystemGestures; -import static android.view.WindowInsets.Type.systemGestures; -import static android.view.WindowInsets.Type.tappableElement; import android.annotation.IntDef; import android.annotation.IntRange; @@ -225,10 +222,6 @@ public final class WindowInsets { } Insets[] typeInsetMap = new Insets[SIZE]; assignCompatInsets(typeInsetMap, insets); - // TODO: set system gesture insets based on actual system gesture area. - typeInsetMap[indexOf(systemGestures())] = Insets.of(insets); - typeInsetMap[indexOf(mandatorySystemGestures())] = Insets.of(insets); - typeInsetMap[indexOf(tappableElement())] = Insets.of(insets); return typeInsetMap; } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 213945355f87..345987718aaa 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3241,6 +3241,12 @@ Only applies if the device display is not square. --> true + + false + + + 0dp + 16x16 diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 874bde18d4a1..544c40c24202 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2845,6 +2845,8 @@ + + diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 116ccd239361..6eb279affc4f 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -23,8 +23,6 @@ @*android:dimen/navigation_bar_height 48dp - - 48dp 500dp false - \ No newline at end of file + + + true + + + 48dp + + diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index cb069fa7c02a..d47b8a1c95b9 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -26,6 +26,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.res.Configuration.UI_MODE_TYPE_CAR; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.view.InsetsState.TYPE_TOP_BAR; +import static android.view.InsetsState.TYPE_TOP_GESTURES; +import static android.view.InsetsState.TYPE_TOP_TAPPABLE_ELEMENT; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION; @@ -40,6 +42,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN; 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_NOT_TOUCHABLE; 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; @@ -152,6 +155,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ScreenShapeHelper; import com.android.internal.util.ScreenshotHelper; +import com.android.internal.util.function.TriConsumer; import com.android.internal.widget.PointerLocationView; import com.android.server.LocalServices; import com.android.server.UiThread; @@ -215,6 +219,12 @@ public class DisplayPolicy { private final Object mServiceAcquireLock = new Object(); private StatusBarManagerInternal mStatusBarManagerInternal; + @Px + private int mBottomGestureAdditionalInset; + @Px + private int mSideGestureInset; + private boolean mNavigationBarLetsThroughTaps; + private StatusBarManagerInternal getStatusBarManagerInternal() { synchronized (mServiceAcquireLock) { if (mStatusBarManagerInternal == null) { @@ -857,11 +867,14 @@ public class DisplayPolicy { if (mDisplayContent.isDefaultDisplay) { mService.mPolicy.setKeyguardCandidateLw(win); } - mDisplayContent.setInsetProvider(TYPE_TOP_BAR, win, + final TriConsumer frameProvider = (displayFrames, windowState, rect) -> { rect.top = 0; rect.bottom = getStatusBarHeight(displayFrames); - }); + }; + mDisplayContent.setInsetProvider(TYPE_TOP_BAR, win, frameProvider); + mDisplayContent.setInsetProvider(TYPE_TOP_GESTURES, win, frameProvider); + mDisplayContent.setInsetProvider(TYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider); break; case TYPE_NAVIGATION_BAR: mContext.enforceCallingOrSelfPermission( @@ -878,6 +891,31 @@ public class DisplayPolicy { mNavBarVisibilityListener, true); mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR, win, null /* frameProvider */); + mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_GESTURES, win, + (displayFrames, windowState, inOutFrame) -> { + inOutFrame.top -= mBottomGestureAdditionalInset; + }); + mDisplayContent.setInsetProvider(InsetsState.TYPE_LEFT_GESTURES, win, + (displayFrames, windowState, inOutFrame) -> { + inOutFrame.left = 0; + inOutFrame.top = 0; + inOutFrame.bottom = displayFrames.mDisplayHeight; + inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset; + }); + mDisplayContent.setInsetProvider(InsetsState.TYPE_RIGHT_GESTURES, win, + (displayFrames, windowState, inOutFrame) -> { + inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset; + inOutFrame.top = 0; + inOutFrame.bottom = displayFrames.mDisplayHeight; + inOutFrame.right = displayFrames.mDisplayWidth; + }); + mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_TAPPABLE_ELEMENT, win, + (displayFrames, windowState, inOutFrame) -> { + if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0 + || mNavigationBarLetsThroughTaps) { + inOutFrame.setEmpty(); + } + }); if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar); break; case TYPE_NAVIGATION_BAR_PANEL: @@ -2607,11 +2645,20 @@ public class DisplayPolicy { } mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode); + mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset); + mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough); // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed mExperiments.onConfigurationChanged(uiContext); // EXPERIMENT END + // EXPERIMENT: TODO(b/113952590): Replace with real code after experiment. + // This should calculate how much above the frame we accept gestures. Currently, + // we extend the frame to capture the gestures, so this is 0. + mBottomGestureAdditionalInset = mExperiments.getNavigationBarFrameHeight() + - mExperiments.getNavigationBarFrameHeight(); + // EXPERIMENT END + updateConfigurationAndScreenSizeDependentBehaviors(); mWindowOutsetBottom = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources()); } diff --git a/tests/testables/src/android/testing/TestableContext.java b/tests/testables/src/android/testing/TestableContext.java index fff9635992d4..e2668bc4281f 100644 --- a/tests/testables/src/android/testing/TestableContext.java +++ b/tests/testables/src/android/testing/TestableContext.java @@ -296,13 +296,13 @@ public class TestableContext extends ContextWrapper implements TestRule { @Override public void registerComponentCallbacks(ComponentCallbacks callback) { if (mComponent != null) mComponent.getLeakInfo(callback).addAllocation(new Throwable()); - super.registerComponentCallbacks(callback); + getBaseContext().registerComponentCallbacks(callback); } @Override public void unregisterComponentCallbacks(ComponentCallbacks callback) { if (mComponent != null) mComponent.getLeakInfo(callback).clearAllocations(); - super.unregisterComponentCallbacks(callback); + getBaseContext().unregisterComponentCallbacks(callback); } public TestablePermissions getTestablePermissions() { -- cgit v1.2.3-59-g8ed1b