diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 13b0cc038fcea..b76f2a1753463 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 49166ade34ce8..ce1b5f829dba9 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 ffa769a424a99..2d292ef7b25c9 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 213945355f87e..345987718aaae 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 874bde18d4a10..544c40c24202b 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 116ccd2393619..6eb279affc4fe 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 cb069fa7c02aa..d47b8a1c95b92 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 fff9635992d46..e2668bc4281fa 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() {