From 737bff3476a3af8f930d29fccce16d033fbc3efa Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Fri, 8 May 2015 16:08:35 -0700 Subject: [PATCH] Fixed a bug where the HUN would interfere with the normal touches When a hun came in or went away, the touchable regions were not enforced correctly due to a race condition. This lead to the user grabing the notification panel unintentionally and ripping him out of the normal touch state. Also fixed a small bug where the alpha was not correctly animating sometimes and the HUN shadow would still draw. Bug: 20956211 Change-Id: Iae1fef5825b3d2b8b4128cc8c3272019194cd819 (cherry picked from commit 8b4a06e9e269140c93c1a9ef5add008f7610d1a4) --- .../systemui/statusbar/phone/PhoneStatusBar.java | 31 +++++++--- .../systemui/statusbar/phone/ScrimController.java | 3 +- .../statusbar/phone/StatusBarWindowManager.java | 16 ++++- .../systemui/statusbar/policy/HeadsUpManager.java | 71 +++++++++++++++++++++- 4 files changed, 106 insertions(+), 15 deletions(-) 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 da65a01ebeb5..8ccd222b50c4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -619,7 +619,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, R.color.notification_panel_solid_background))); } - mHeadsUpManager = new HeadsUpManager(context, mNotificationPanel.getViewTreeObserver()); + mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow); mHeadsUpManager.setBar(this); mHeadsUpManager.addListener(this); mHeadsUpManager.addListener(mNotificationPanel); @@ -1869,21 +1869,34 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, @Override public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) { if (inPinnedMode) { + // We need to ensure that the touchable region is updated before the window will be + // resized, in order to not catch any touches. A layout will ensure that + // onComputeInternalInsets will be called and after that we can resize the layout. Let's + // make sure that the window stays small for one frame until the touchableRegion is set. + mNotificationPanel.requestLayout(); mStatusBarWindowManager.setHeadsUpShowing(true); mStatusBarWindowManager.setForceStatusBarVisible(true); - } else { - Runnable endRunnable = new Runnable() { + mStatusBarWindowManager.setForceWindowCollapsed(true); + mNotificationPanel.post(new Runnable() { @Override public void run() { - if (!mHeadsUpManager.hasPinnedHeadsUp()) { - mStatusBarWindowManager.setHeadsUpShowing(false); - } + mStatusBarWindowManager.setForceWindowCollapsed(false); } - }; + }); + } else { if (!mNotificationPanel.isFullyCollapsed()) { - endRunnable.run(); + mStatusBarWindowManager.setHeadsUpShowing(false); } else { - mStackScroller.runAfterAnimationFinished(endRunnable); + mHeadsUpManager.setHeadsUpGoingAway(true); + mStackScroller.runAfterAnimationFinished(new Runnable() { + @Override + public void run() { + if (!mHeadsUpManager.hasPinnedHeadsUp()) { + mStatusBarWindowManager.setHeadsUpShowing(false); + mHeadsUpManager.setHeadsUpGoingAway(false); + } + } + }); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index e6edbeac61a3..acf2f570e50b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -378,8 +378,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, if (previousAnimator != null) { if (animate || alpha == mCurrentHeadsUpAlpha) { previousAnimator.cancel(); + } else { + animEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim, TAG_HUN_END_ALPHA); } - animEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim, TAG_HUN_START_ALPHA); } if (alpha != mCurrentHeadsUpAlpha && alpha != animEndValue) { if (animate) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index e7e4384f6f4a..422d86864600 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -129,8 +129,9 @@ public class StatusBarWindowManager { } private void applyHeight(State state) { - boolean expanded = state.isKeyguardShowingAndNotOccluded() || state.statusBarExpanded - || state.keyguardFadingAway || state.bouncerShowing || state.headsUpShowing; + boolean expanded = !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded() + || state.statusBarExpanded || state.keyguardFadingAway || state.bouncerShowing + || state.headsUpShowing); if (expanded) { mLpChanged.height = ViewGroup.LayoutParams.MATCH_PARENT; } else { @@ -256,6 +257,16 @@ public class StatusBarWindowManager { apply(mCurrentState); } + /** + * Force the window to be collapsed, even if it should theoretically be expanded. + * Used for when a heads-up comes in but we still need to wait for the touchable regions to + * be computed. + */ + public void setForceWindowCollapsed(boolean force) { + mCurrentState.forceCollapsed = force; + apply(mCurrentState); + } + private static class State { boolean keyguardShowing; boolean keyguardOccluded; @@ -267,6 +278,7 @@ public class StatusBarWindowManager { boolean qsExpanded; boolean headsUpShowing; boolean forceStatusBarVisible; + boolean forceCollapsed; /** * The {@link BaseStatusBar} state from the status bar. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java index 0db922160ef0..98822a9392dc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -25,6 +25,7 @@ import android.provider.Settings; import android.util.ArrayMap; import android.util.Log; import android.util.Pools; +import android.view.View; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityEvent; @@ -78,6 +79,8 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL } }; + private final View mStatusBarWindowView; + private final int mStatusBarHeight; private PhoneStatusBar mBar; private int mSnoozeLengthMs; private ContentObserver mSettingsObserver; @@ -92,8 +95,11 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL private boolean mIsExpanded; private boolean mHasPinnedNotification; private int[] mTmpTwoArray = new int[2]; + private boolean mHeadsUpGoingAway; + private boolean mWaitingOnCollapseWhenGoingAway; + private boolean mIsObserving; - public HeadsUpManager(final Context context, ViewTreeObserver observer) { + public HeadsUpManager(final Context context, View statusBarWindowView) { Resources resources = context.getResources(); mTouchAcceptanceDelay = resources.getInteger(R.integer.touch_acceptance_delay); mSnoozedPackages = new ArrayMap<>(); @@ -119,7 +125,24 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL context.getContentResolver().registerContentObserver( Settings.Global.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS), false, mSettingsObserver); - observer.addOnComputeInternalInsetsListener(this); + mStatusBarWindowView = statusBarWindowView; + mStatusBarHeight = resources.getDimensionPixelSize( + com.android.internal.R.dimen.status_bar_height); + } + + private void updateTouchableRegionListener() { + boolean shouldObserve = mHasPinnedNotification || mHeadsUpGoingAway + || mWaitingOnCollapseWhenGoingAway; + if (shouldObserve == mIsObserving) { + return; + } + if (shouldObserve) { + mStatusBarWindowView.getViewTreeObserver().addOnComputeInternalInsetsListener(this); + mStatusBarWindowView.requestLayout(); + } else { + mStatusBarWindowView.getViewTreeObserver().removeOnComputeInternalInsetsListener(this); + } + mIsObserving = shouldObserve; } public void setBar(PhoneStatusBar bar) { @@ -207,6 +230,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL return; } mHasPinnedNotification = hasPinnedNotification; + updateTouchableRegionListener(); for (OnHeadsUpChangedListener listener : mListeners) { listener.onHeadsUpPinnedModeChanged(hasPinnedNotification); } @@ -326,7 +350,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL } public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) { - if (!mIsExpanded && mHasPinnedNotification) { + if (mHasPinnedNotification) { int minX = Integer.MAX_VALUE; int maxX = 0; int minY = Integer.MAX_VALUE; @@ -344,6 +368,9 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); info.touchableRegion.set(minX, minY, maxX, maxY); + } else if (mHeadsUpGoingAway || mWaitingOnCollapseWhenGoingAway) { + info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); + info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight); } } @@ -419,6 +446,10 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL mIsExpanded = isExpanded; if (isExpanded) { unpinAll(); + // make sure our state is sane + mWaitingOnCollapseWhenGoingAway = false; + mHeadsUpGoingAway = false; + updateTouchableRegionListener(); } } } @@ -443,6 +474,40 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL return aEntry.compareTo(bEntry); } + /** + * Set that we are exiting the headsUp pinned mode, but some notifications might still be + * animating out. This is used to keep the touchable regions in a sane state. + */ + public void setHeadsUpGoingAway(boolean headsUpGoingAway) { + if (headsUpGoingAway != mHeadsUpGoingAway) { + mHeadsUpGoingAway = headsUpGoingAway; + if (!headsUpGoingAway) { + waitForStatusBarLayout(); + } + updateTouchableRegionListener(); + } + } + + /** + * We need to wait on the whole panel to collapse, before we can remove the touchable region + * listener. + */ + private void waitForStatusBarLayout() { + mWaitingOnCollapseWhenGoingAway = true; + mStatusBarWindowView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, + int oldTop, int oldRight, int oldBottom) { + if (mStatusBarWindowView.getHeight() <= mStatusBarHeight) { + mStatusBarWindowView.removeOnLayoutChangeListener(this); + mWaitingOnCollapseWhenGoingAway = false; + updateTouchableRegionListener(); + } + } + }); + } + /** * This represents a notification and how long it is in a heads up mode. It also manages its -- 2.11.0