diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index f00957a14e093..3b58b7249b05e 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1012,4 +1012,7 @@ 0px + + 12dp diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index f5478c732fbc5..65826b9fbbc99 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -582,31 +582,34 @@ public class ScreenDecorations extends SystemUI implements Tunable { resolveSizeAndState(mBoundingRect.height(), heightMeasureSpec, 0)); } - public static void boundsFromDirection(DisplayCutout displayCutout, int gravity, Rect out) { + public static void boundsFromDirection(DisplayCutout displayCutout, int gravity, + Rect out) { + Region bounds = boundsFromDirection(displayCutout, gravity); + out.set(bounds.getBounds()); + bounds.recycle(); + } + + public static Region boundsFromDirection(DisplayCutout displayCutout, int gravity) { Region bounds = displayCutout.getBounds(); switch (gravity) { case Gravity.TOP: bounds.op(0, 0, Integer.MAX_VALUE, displayCutout.getSafeInsetTop(), Region.Op.INTERSECT); - out.set(bounds.getBounds()); break; case Gravity.LEFT: bounds.op(0, 0, displayCutout.getSafeInsetLeft(), Integer.MAX_VALUE, Region.Op.INTERSECT); - out.set(bounds.getBounds()); break; case Gravity.BOTTOM: bounds.op(0, displayCutout.getSafeInsetTop() + 1, Integer.MAX_VALUE, Integer.MAX_VALUE, Region.Op.INTERSECT); - out.set(bounds.getBounds()); break; case Gravity.RIGHT: bounds.op(displayCutout.getSafeInsetLeft() + 1, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, Region.Op.INTERSECT); - out.set(bounds.getBounds()); break; } - bounds.recycle(); + return bounds; } private void localBounds(Rect out) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index fa0a774c249e0..0aad4389ceec5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -21,15 +21,22 @@ import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Rect; +import android.graphics.Region; +import android.graphics.Region.Op; import android.support.v4.util.ArraySet; import android.util.Log; import android.util.Pools; +import android.view.DisplayCutout; +import android.view.Gravity; import android.view.View; import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.InternalInsetsInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dumpable; import com.android.systemui.R; +import com.android.systemui.ScreenDecorations; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.StatusBarState; @@ -41,6 +48,7 @@ import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashSet; +import java.util.List; import java.util.Stack; /** @@ -60,6 +68,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, private int mStatusBarHeight; private int mHeadsUpInset; + private int mDisplayCutoutTouchableRegionSize; private boolean mTrackingHeadsUp; private HashSet mSwipedOutKeys = new HashSet<>(); private HashSet mEntriesToRemoveAfterExpand = new HashSet<>(); @@ -120,6 +129,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, com.android.internal.R.dimen.status_bar_height); mHeadsUpInset = mStatusBarHeight + resources.getDimensionPixelSize( R.dimen.heads_up_status_bar_padding); + mDisplayCutoutTouchableRegionSize = resources.getDimensionPixelSize( + R.dimen.display_cutout_touchable_region_size); } @Override @@ -128,6 +139,11 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, initResources(); } + @Override + public void onOverlayChanged() { + initResources(); + } + /////////////////////////////////////////////////////////////////////////////////////////////// // Public methods: @@ -301,12 +317,32 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); info.touchableRegion.set(minX, 0, maxX, mHeadsUpInset + height); - } else if (mHeadsUpGoingAway || mWaitingOnCollapseWhenGoingAway) { - info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); - info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight); + } else { + setCollapsedTouchableInsets(info); } } + private void setCollapsedTouchableInsets(ViewTreeObserver.InternalInsetsInfo info) { + info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); + info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight); + updateRegionForNotch(info.touchableRegion); + } + + private void updateRegionForNotch(Region region) { + DisplayCutout cutout = mStatusBarWindowView.getRootWindowInsets().getDisplayCutout(); + if (cutout == null) { + return; + } + + // Expand touchable region such that we also catch touches that just start below the notch + // area. + Region bounds = ScreenDecorations.DisplayCutoutView.boundsFromDirection( + cutout, Gravity.TOP); + bounds.translate(0, mDisplayCutoutTouchableRegionSize); + region.op(bounds, Op.UNION); + bounds.recycle(); + } + @Override public void onConfigChanged(Configuration newConfig) { Resources resources = mContext.getResources(); @@ -403,7 +439,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, private void updateTouchableRegionListener() { boolean shouldObserve = hasPinnedHeadsUp() || mHeadsUpGoingAway - || mWaitingOnCollapseWhenGoingAway; + || mWaitingOnCollapseWhenGoingAway + || mStatusBarWindowView.getRootWindowInsets().getDisplayCutout() != null; if (shouldObserve == mIsObserving) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index a79a41b077975..0390f60843d18 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -94,6 +94,12 @@ public class StatusBarWindowView extends FrameLayout { private boolean mExpandAnimationRunning; private boolean mExpandAnimationPending; + /** + * If set to true, the current gesture started below the notch and we need to dispatch touch + * events manually as it's outside of the regular view bounds. + */ + private boolean mExpandingBelowNotch; + public StatusBarWindowView(Context context, AttributeSet attrs) { super(context, attrs); setMotionEventSplittingEnabled(false); @@ -258,7 +264,16 @@ public class StatusBarWindowView extends FrameLayout { @Override public boolean dispatchTouchEvent(MotionEvent ev) { boolean isDown = ev.getActionMasked() == MotionEvent.ACTION_DOWN; + boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP; boolean isCancel = ev.getActionMasked() == MotionEvent.ACTION_CANCEL; + + // Reset manual touch dispatch state here but make sure the UP/CANCEL event still gets + // delivered. + boolean expandingBelowNotch = mExpandingBelowNotch; + if (isUp || isCancel) { + mExpandingBelowNotch = false; + } + if (!isCancel && mService.shouldIgnoreTouch()) { return false; } @@ -291,6 +306,17 @@ public class StatusBarWindowView extends FrameLayout { mService.mDozeScrimController.extendPulse(); } + // In case we start outside of the view bounds (below the status bar), we need to dispatch + // the touch manually as the view system can't accomodate for touches outside of the + // regular view bounds. + if (isDown && ev.getY() >= mBottom) { + mExpandingBelowNotch = true; + expandingBelowNotch = true; + } + if (expandingBelowNotch) { + return mNotificationPanel.dispatchTouchEvent(ev); + } + return super.dispatchTouchEvent(ev); }