From 7a9b2a67b71f8f6c5cffc3fe90cc4b513b79a9b2 Mon Sep 17 00:00:00 2001 From: Mady Mellor Date: Wed, 23 Mar 2016 07:41:47 -0700 Subject: Close inline controls / hide the gear when interaction outside occurs This CL adds the behavior so that if the gear or inline controls are visible, they will close if the user interacts with another area of the screen (e.g. scrolls, pulls down QS, etc) this is on the lock screen as well as the shade. This CL makes an additional change to remove the GearDisplayedListener and use the StackScroller to maintain state of the gear / reset as appropriate. Bug: 27598072 Bug: 27335311 Change-Id: Iebff9aa542c9d91389054a4ff292d0dda11fe950 --- .../android/systemui/statusbar/BaseStatusBar.java | 32 +++--- .../statusbar/NotificationSettingsIconRow.java | 4 +- .../systemui/statusbar/phone/PhoneStatusBar.java | 1 - .../statusbar/phone/StatusBarWindowView.java | 4 + .../stack/NotificationStackScrollLayout.java | 122 ++++++++++++++------- 5 files changed, 100 insertions(+), 63 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 4ed64260dc7f..cdcb8d52c11c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -107,7 +107,6 @@ import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.PreviewInflater; import com.android.systemui.statusbar.policy.RemoteInputView; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; -import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.GearDisplayedListener; import com.android.systemui.statusbar.stack.StackStateAnimator; import java.util.ArrayList; @@ -120,7 +119,7 @@ import static com.android.keyguard.KeyguardHostView.OnDismissAction; public abstract class BaseStatusBar extends SystemUI implements CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener, ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment, - ExpandableNotificationRow.OnExpandClickListener, GearDisplayedListener { + ExpandableNotificationRow.OnExpandClickListener { public static final String TAG = "StatusBar"; public static final boolean DEBUG = false; public static final boolean MULTIUSER_DEBUG = false; @@ -242,7 +241,6 @@ public abstract class BaseStatusBar extends SystemUI implements // which notification is currently being longpress-examined by the user private NotificationGuts mNotificationGutsExposed; - private ExpandableNotificationRow mNotificationGearDisplayed; private KeyboardShortcuts mKeyboardShortcuts; @@ -1067,10 +1065,6 @@ public abstract class BaseStatusBar extends SystemUI implements guts.bindImportance(pmUser, sbn, row, mNotificationData.getImportance(sbn.getKey())); } - protected GearDisplayedListener getGearDisplayedListener() { - return this; - } - protected SwipeHelper.LongPressListener getNotificationLongClicker() { return new SwipeHelper.LongPressListener() { @Override @@ -1106,7 +1100,8 @@ public abstract class BaseStatusBar extends SystemUI implements // Post to ensure the the guts are properly laid out. guts.post(new Runnable() { public void run() { - dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */); + dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */, + false /* animate */); guts.setVisibility(View.VISIBLE); final double horz = Math.max(guts.getWidth() - x, x); final double vert = Math.max(guts.getHeight() - y, y); @@ -1135,22 +1130,22 @@ public abstract class BaseStatusBar extends SystemUI implements }; } - @Override - public void onGearDisplayed(ExpandableNotificationRow row) { - MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR, - row.getStatusBarNotification().getPackageName()); - mNotificationGearDisplayed = row; + /** + * Returns the exposed NotificationGuts or null if none are exposed. + */ + public NotificationGuts getExposedGuts() { + return mNotificationGutsExposed; } public void dismissPopups() { - dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */); + dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */, false /* animate */); } private void dismissPopups(int x, int y) { - dismissPopups(x, y, true /* resetGear */); + dismissPopups(x, y, true /* resetGear */, false /* animate */); } - public void dismissPopups(int x, int y, boolean resetGear) { + public void dismissPopups(int x, int y, boolean resetGear, boolean animate) { if (mNotificationGutsExposed != null) { final NotificationGuts v = mNotificationGutsExposed; mNotificationGutsExposed = null; @@ -1178,9 +1173,8 @@ public abstract class BaseStatusBar extends SystemUI implements v.setExposed(false); mStackScroller.onHeightChanged(null, true /* needsAnimation */); } - if (resetGear && mNotificationGearDisplayed != null) { - mNotificationGearDisplayed.resetTranslation(); - mNotificationGearDisplayed = null; + if (resetGear) { + mStackScroller.resetExposedGearView(animate, true /* force */); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java index 88aafe0e61bb..a5ebbbab36b3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java @@ -41,7 +41,7 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC /** * Called when a notification is slid back over the gear. */ - public void onSettingsIconRowReset(NotificationSettingsIconRow row); + public void onSettingsIconRowReset(ExpandableNotificationRow row); } private ExpandableNotificationRow mParent; @@ -94,7 +94,7 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC mDismissing = false; setIconLocation(true /* on left */, true /* force */); if (mListener != null) { - mListener.onSettingsIconRowReset(this); + mListener.onSettingsIconRowReset(mParent); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index c563eb606663..fce893e0b5f6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -755,7 +755,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById( R.id.notification_stack_scroller); mStackScroller.setLongPressListener(getNotificationLongClicker()); - mStackScroller.setGearDisplayedListener(getGearDisplayedListener()); mStackScroller.setPhoneStatusBar(this); mStackScroller.setGroupManager(mGroupManager); mStackScroller.setHeadsUpManager(mHeadsUpManager); 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 6a2ecf4e6b0b..ebfa0183f8b3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -226,6 +226,10 @@ public class StatusBarWindowView extends FrameLayout { return false; } } + if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { + mStackScrollLayout.closeControlsIfOutsideTouch(ev); + } + return super.dispatchTouchEvent(ev); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 4a8abe68a091..e9d645050f82 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -60,6 +60,7 @@ import com.android.systemui.statusbar.DismissView; import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.ExpandableView; +import com.android.systemui.statusbar.NotificationGuts; import com.android.systemui.statusbar.NotificationOverflowContainer; import com.android.systemui.statusbar.NotificationSettingsIconRow; import com.android.systemui.statusbar.NotificationSettingsIconRow.SettingsIconRowListener; @@ -220,7 +221,6 @@ public class NotificationStackScrollLayout extends ViewGroup */ private int mMaxScrollAfterExpand; private SwipeHelper.LongPressListener mLongPressListener; - private GearDisplayedListener mGearDisplayedListener; private NotificationSettingsIconRow mCurrIconRow; private View mTranslatingParentView; @@ -374,8 +374,12 @@ public class NotificationStackScrollLayout extends ViewGroup } @Override - public void onSettingsIconRowReset(NotificationSettingsIconRow row) { - mSwipeHelper.setSnappedToGear(false); + public void onSettingsIconRowReset(ExpandableNotificationRow row) { + if (mTranslatingParentView != null && row == mTranslatingParentView) { + mSwipeHelper.setSnappedToGear(false); + mGearExposedView = null; + mTranslatingParentView = null; + } } @Override @@ -669,10 +673,6 @@ public class NotificationStackScrollLayout extends ViewGroup mLongPressListener = listener; } - public void setGearDisplayedListener(GearDisplayedListener listener) { - mGearDisplayedListener = listener; - } - public void setQsContainer(ViewGroup qsContainer) { mQsContainer = qsContainer; } @@ -737,17 +737,9 @@ public class NotificationStackScrollLayout extends ViewGroup // We start the swipe and snap back in the same frame, we don't want any animation mDragAnimPendingChildren.remove(animView); } - - if (mCurrIconRow != null) { - if (targetLeft == 0) { - mCurrIconRow.resetState(); - mCurrIconRow = null; - if (mGearExposedView != null && mGearExposedView == mTranslatingParentView) { - mGearExposedView = null; - } - } else { - mSwipeHelper.setSnappedToGear(true); - } + if (mCurrIconRow != null && targetLeft == 0) { + mCurrIconRow.resetState(); + mCurrIconRow = null; } } @@ -3470,13 +3462,6 @@ public class NotificationStackScrollLayout extends ViewGroup public void flingTopOverscroll(float velocity, boolean open); } - /** - * A listener that is notified when the gear is shown behind a notification. - */ - public interface GearDisplayedListener { - void onGearDisplayed(ExpandableNotificationRow row); - } - private class NotificationSwipeHelper extends SwipeHelper { private static final long GEAR_SHOW_DELAY = 60; private CheckForDrag mCheckForDrag; @@ -3503,7 +3488,7 @@ public class NotificationStackScrollLayout extends ViewGroup mCurrIconRow = null; // Slide back any notifications that might be showing a gear - resetExposedGearView(); + resetExposedGearView(true /* animate */, false /* force */); if (currView instanceof ExpandableNotificationRow) { // Set the listener for the current row's gear @@ -3551,8 +3536,7 @@ public class NotificationStackScrollLayout extends ViewGroup public void dismissChild(final View view, float velocity, boolean useAccelerateInterpolator) { super.dismissChild(view, velocity, useAccelerateInterpolator); - cancelCheckForDrag(); - setSnappedToGear(false); + handleGearCoveredOrDismissed(); } @Override @@ -3560,11 +3544,17 @@ public class NotificationStackScrollLayout extends ViewGroup super.snapChild(animView, targetLeft, velocity); onDragCancelled(animView); if (targetLeft == 0) { - cancelCheckForDrag(); - setSnappedToGear(false); + handleGearCoveredOrDismissed(); } } + private void handleGearCoveredOrDismissed() { + cancelCheckForDrag(); + setSnappedToGear(false); + if (mGearExposedView != null && mGearExposedView == mTranslatingParentView) { + mGearExposedView = null; + } + } @Override public boolean handleUpEvent(MotionEvent ev, View animView, float velocity, @@ -3624,9 +3614,10 @@ public class NotificationStackScrollLayout extends ViewGroup final float target = mCurrIconRow.isIconOnLeft() ? snapBackThreshold : -snapBackThreshold; mGearExposedView = mTranslatingParentView; - if (mGearDisplayedListener != null - && (animView instanceof ExpandableNotificationRow)) { - mGearDisplayedListener.onGearDisplayed((ExpandableNotificationRow) animView); + if (animView instanceof ExpandableNotificationRow) { + MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR, + ((ExpandableNotificationRow) animView).getStatusBarNotification() + .getPackageName()); } if (mCurrIconRow != null) { mCurrIconRow.setSnapping(true); @@ -3637,6 +3628,9 @@ public class NotificationStackScrollLayout extends ViewGroup } private boolean swipedEnoughToShowGear(View animView) { + if (mTranslatingParentView == null) { + return false; + } final float snapBackThreshold = getSpaceForGear(animView); final float translation = getTranslation(animView); final boolean fromLeft = translation > 0; @@ -3682,6 +3676,37 @@ public class NotificationStackScrollLayout extends ViewGroup } } + public void closeControlsIfOutsideTouch(MotionEvent ev) { + NotificationGuts guts = mPhoneStatusBar.getExposedGuts(); + View view = null; + int height = 0; + if (guts != null) { + // Checking guts + view = guts; + height = guts.getActualHeight(); + } else if (mCurrIconRow != null && mCurrIconRow.isVisible() + && mTranslatingParentView != null) { + // Checking gear + view = mTranslatingParentView; + height = ((ExpandableView) mTranslatingParentView).getActualHeight(); + } + if (view != null) { + final int rx = (int) ev.getRawX(); + final int ry = (int) ev.getRawY(); + + getLocationOnScreen(mTempInt2); + int[] location = new int[2]; + view.getLocationOnScreen(location); + final int x = location[0] - mTempInt2[0]; + final int y = location[1] - mTempInt2[1]; + Rect rect = new Rect(x, y, x + view.getWidth(), y + height); + if (!rect.contains((int) rx, (int) ry)) { + // Touch was outside visible guts / gear notification, close what's visible + mPhoneStatusBar.dismissPopups(-1, -1, true /* resetGear */, true /* animate */); + } + } + } + /** * Returns whether the gesture is towards the gear location or not. */ @@ -3729,6 +3754,9 @@ public class NotificationStackScrollLayout extends ViewGroup private final class CheckForDrag implements Runnable { @Override public void run() { + if (mTranslatingParentView == null) { + return; + } final float translation = getTranslation(mTranslatingParentView); final float absTransX = Math.abs(translation); final float bounceBackToGearWidth = getSpaceForGear(mTranslatingParentView); @@ -3744,20 +3772,24 @@ public class NotificationStackScrollLayout extends ViewGroup } } - private void resetExposedGearView() { - if (mGearExposedView == null || mGearExposedView == mTranslatingParentView) { + public void resetExposedGearView(boolean animate, boolean force) { + if (mGearExposedView == null + || (!force && mGearExposedView == mTranslatingParentView)) { // If no gear is showing or it's showing for this view we do nothing. return; } - final View prevGearExposedView = mGearExposedView; + if (animate) { + Animator anim = getViewTranslationAnimator(prevGearExposedView, + 0 /* leftTarget */, null /* updateListener */); + if (anim != null) { + anim.start(); + } + } else if (mGearExposedView instanceof ExpandableNotificationRow) { + ((ExpandableNotificationRow) mGearExposedView).resetTranslation(); + } mGearExposedView = null; mGearSnappedTo = false; - Animator anim = getViewTranslationAnimator(prevGearExposedView, - 0 /* leftTarget */, null /* updateListener */); - if (anim != null) { - anim.start(); - } } } @@ -3773,6 +3805,14 @@ public class NotificationStackScrollLayout extends ViewGroup } } + public void resetExposedGearView(boolean animate, boolean force) { + mSwipeHelper.resetExposedGearView(animate, force); + } + + public void closeControlsIfOutsideTouch(MotionEvent ev) { + mSwipeHelper.closeControlsIfOutsideTouch(ev); + } + static class AnimationEvent { static AnimationFilter[] FILTERS = new AnimationFilter[] { -- cgit v1.2.3-59-g8ed1b