From 131c1e2960fa5bdf54bfb6fcd5ac98c9f728f796 Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Mon, 11 May 2015 19:04:49 -0700 Subject: [PATCH] Made sure that HUNS with full screen intents stay pinned When a HUN came in with a full screen intent came in and the shade was open, the notification was not pinned and therefore got lost when the shade was closed, potentially leading to missed alarms or calls. Bug: 20431566 Change-Id: I0d5da0f9baba8d9f68ba2755c40c5fd9a8471191 --- .../statusbar/phone/HeadsUpTouchHelper.java | 4 +- .../statusbar/phone/PhoneStatusBar.java | 38 +++++++++++-------- .../statusbar/phone/ScrimController.java | 13 +++++-- .../statusbar/policy/HeadsUpManager.java | 23 +++++++---- .../stack/NotificationStackScrollLayout.java | 15 ++++---- .../statusbar/stack/StackScrollAlgorithm.java | 24 ++++++------ .../statusbar/stack/StackStateAnimator.java | 2 +- 7 files changed, 71 insertions(+), 48 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java index 3eb6b13417a8b..e6da81e759d9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java @@ -95,13 +95,15 @@ public class HeadsUpTouchHelper implements Gefingerpoken { case MotionEvent.ACTION_MOVE: final float h = y - mInitialTouchY; - if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)) { + if (mTouchingHeadsUpView && Math.abs(h) > mTouchSlop + && Math.abs(h) > Math.abs(x - mInitialTouchX)) { setTrackingHeadsUp(true); mCollapseSnoozes = h < 0; mInitialTouchX = x; mInitialTouchY = y; int expandedHeight = mPickedChild.getActualHeight(); mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight); + mHeadsUpManager.unpinAll(); return true; } break; 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 df0a95915b6c1..f983f58061c7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1602,9 +1602,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (DEBUG_MEDIA) { Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " + mMediaNotificationKey - + " metadata=" + mMediaMetadata - + " metaDataChanged=" + metaDataChanged - + " state=" + mState); + + " metadata=" + mMediaMetadata + + " metaDataChanged=" + metaDataChanged + + " state=" + mState); } Bitmap artworkBitmap = null; @@ -1872,24 +1872,30 @@ 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); - mStatusBarWindowManager.setForceWindowCollapsed(true); - mNotificationPanel.post(new Runnable() { - @Override - public void run() { - mStatusBarWindowManager.setForceWindowCollapsed(false); - } - }); + if (mNotificationPanel.isFullyCollapsed()) { + // 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.setForceWindowCollapsed(true); + mNotificationPanel.post(new Runnable() { + @Override + public void run() { + mStatusBarWindowManager.setForceWindowCollapsed(false); + } + }); + } } else { - if (!mNotificationPanel.isFullyCollapsed()) { + if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) { + // We are currently tracking or is open and the shade doesn't need to be kept + // open artificially. mStatusBarWindowManager.setHeadsUpShowing(false); } else { + // we need to keep the panel open artificially, let's wait until the animation + // is finished. mHeadsUpManager.setHeadsUpGoingAway(true); mStackScroller.runAfterAnimationFinished(new Runnable() { @Override 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 acf2f570e50bb..808f1ff2edf5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -115,6 +115,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, if (mFraction != fraction) { mFraction = fraction; scheduleUpdate(); + if (mPinnedHeadsUpCount != 0) { + updateHeadsUpScrim(false); + } } } @@ -425,12 +428,16 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, } private float calculateHeadsUpAlpha() { + float alpha; if (mPinnedHeadsUpCount >= 2) { - return 1.0f; + alpha = 1.0f; } else if (mPinnedHeadsUpCount == 0) { - return 0.0f; + alpha = 0.0f; } else { - return 1.0f - mTopHeadsUpDragAmount; + alpha = 1.0f - mTopHeadsUpDragAmount; } + float expandFactor = (1.0f - mFraction); + expandFactor = Math.max(expandFactor, 0.0f); + return alpha * expandFactor; } } 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 98822a9392dc3..14060df6bf8c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -179,7 +179,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL if (alert) { HeadsUpEntry headsUpEntry = mHeadsUpEntries.get(headsUp.key); headsUpEntry.updateEntry(); - setEntryPinned(headsUpEntry, !mIsExpanded /* isPinned */); + setEntryPinned(headsUpEntry, shouldHeadsUpBecomePinned(headsUp)); } } @@ -190,13 +190,21 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL headsUpEntry.setEntry(entry); mHeadsUpEntries.put(entry.key, headsUpEntry); entry.row.setHeadsUp(true); - setEntryPinned(headsUpEntry, !mIsExpanded /* isPinned */); + setEntryPinned(headsUpEntry, shouldHeadsUpBecomePinned(entry)); for (OnHeadsUpChangedListener listener : mListeners) { listener.onHeadsUpStateChanged(entry, true); } entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); } + private boolean shouldHeadsUpBecomePinned(NotificationData.Entry entry) { + return !mIsExpanded || hasFullScreenIntent(entry); + } + + private boolean hasFullScreenIntent(NotificationData.Entry entry) { + return entry.notification.getNotification().fullScreenIntent != null; + } + private void setEntryPinned(HeadsUpEntry headsUpEntry, boolean isPinned) { ExpandableNotificationRow row = headsUpEntry.entry.row; if (row.isPinned() != isPinned) { @@ -350,6 +358,10 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL } public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) { + if (mIsExpanded) { + // The touchable region is always the full area when expanded + return; + } if (mHasPinnedNotification) { int minX = Integer.MAX_VALUE; int maxX = 0; @@ -445,7 +457,6 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL if (isExpanded != mIsExpanded) { mIsExpanded = isExpanded; if (isExpanded) { - unpinAll(); // make sure our state is sane mWaitingOnCollapseWhenGoingAway = false; mHeadsUpGoingAway = false; @@ -542,7 +553,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL earliestRemovaltime = currentTime + mMinimumDisplayTime; postTime = Math.max(postTime, currentTime); removeAutoRemovalCallbacks(); - if (canEntryDecay()) { + if (!hasFullScreenIntent(entry)) { long finishTime = postTime + mHeadsUpNotificationDecay; long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime); mHandler.postDelayed(mRemoveHeadsUpRunnable, removeDelay); @@ -550,10 +561,6 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL updateSortOrder(HeadsUpEntry.this); } - private boolean canEntryDecay() { - return entry.notification.getNotification().fullScreenIntent == null; - } - @Override public int compareTo(HeadsUpEntry o) { return postTime < o.postTime ? 1 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 a1b0caef9dfc2..bd3b9ebbd959d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -485,7 +485,7 @@ public class NotificationStackScrollLayout extends ViewGroup int minStackHeight = getMinStackHeight(); int stackHeight; float paddingOffset; - boolean trackingHeadsUp = mTrackingHeadsUp; + boolean trackingHeadsUp = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp(); int normalUnfoldPositionStart = trackingHeadsUp ? mHeadsUpManager.getTopHeadsUpHeight() : minStackHeight; if (newStackHeight - mTopPadding - mTopPaddingOverflow >= normalUnfoldPositionStart @@ -608,7 +608,7 @@ public class NotificationStackScrollLayout extends ViewGroup @Override public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) { - if (isPinnedHeadsUp(animView) && canChildBeDismissed(animView)) { + if (!mIsExpanded && isPinnedHeadsUp(animView) && canChildBeDismissed(animView)) { mScrimController.setTopHeadsUpDragAmount(animView, Math.min(Math.abs(swipeProgress - 1.0f), 1.0f)); } @@ -618,7 +618,7 @@ public class NotificationStackScrollLayout extends ViewGroup public void onBeginDrag(View v) { setSwipingInProgress(true); mAmbientState.onBeginDrag(v); - if (mAnimationsEnabled && !isPinnedHeadsUp(v)) { + if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) { mDragAnimPendingChildren.add(v); mNeedsAnimation = true; } @@ -710,7 +710,7 @@ public class NotificationStackScrollLayout extends ViewGroup if (touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) { if (slidingChild instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild; - if (row.isHeadsUp() && row.isPinned() + if (!mIsExpanded && row.isHeadsUp() && row.isPinned() && mHeadsUpManager.getTopEntry().entry.row != row) { continue; } @@ -1871,17 +1871,18 @@ public class NotificationStackScrollLayout extends ViewGroup boolean isHeadsUp = eventPair.second; int type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_OTHER; boolean onBottom = false; + boolean pinnedAndClosed = row.isPinned() && !mIsExpanded; if (!mIsExpanded && !isHeadsUp) { type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR; - } else if (mAddedHeadsUpChildren.contains(row) || (row.isPinned() && !mIsExpanded)) { - if (row.isPinned() || shouldHunAppearFromBottom(row)) { + } else if (isHeadsUp && (mAddedHeadsUpChildren.contains(row) || pinnedAndClosed)) { + if (pinnedAndClosed || shouldHunAppearFromBottom(row)) { // Our custom add animation type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR; } else { // Normal add animation type = AnimationEvent.ANIMATION_TYPE_ADD; } - onBottom = !row.isPinned(); + onBottom = !pinnedAndClosed; } AnimationEvent event = new AnimationEvent(row, type); event.headsUpFromBottom = onBottom; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index de28ac7aa41be..081a9c532c19a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -311,8 +311,7 @@ public class StackScrollAlgorithm { StackViewState viewState = resultState.getViewStateForView( nextChild); // The child below the dragged one must be fully visible - if (!NotificationStackScrollLayout.isPinnedHeadsUp(draggedView) - || NotificationStackScrollLayout.isPinnedHeadsUp(nextChild)) { + if (ambientState.isShadeExpanded()) { viewState.alpha = 1; } } @@ -508,8 +507,18 @@ public class StackScrollAlgorithm { } StackViewState childState = resultState.getViewStateForView(row); boolean isTopEntry = topHeadsUpEntry == row; + if (mIsExpanded) { + if (isTopEntry) { + childState.height += row.getHeadsUpHeight() - mCollapsedSize; + } + childState.height = Math.max(childState.height, row.getHeadsUpHeight()); + // Ensure that the heads up is always visible even when scrolled off from the bottom + float bottomPosition = ambientState.getMaxHeadsUpTranslation() - childState.height; + childState.yTranslation = Math.min(childState.yTranslation, + bottomPosition); + } if (row.isPinned()) { - childState.yTranslation = 0; + childState.yTranslation = Math.max(childState.yTranslation, 0); childState.height = row.getHeadsUpHeight(); if (!isTopEntry) { // Ensure that a headsUp doesn't vertically extend further than the heads-up at @@ -519,15 +528,6 @@ public class StackScrollAlgorithm { childState.yTranslation = topState.yTranslation + topState.height - childState.height; } - } else if (mIsExpanded) { - if (isTopEntry) { - childState.height += row.getHeadsUpHeight() - mCollapsedSize; - } - childState.height = Math.max(childState.height, row.getHeadsUpHeight()); - // Ensure that the heads up is always visible even when scrolled of from the bottom - float bottomPosition = ambientState.getMaxHeadsUpTranslation() - childState.height; - childState.yTranslation = Math.min(childState.yTranslation, - bottomPosition); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java index b9466d4dd1032..eac5e79960f3b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -163,7 +163,7 @@ public class StackStateAnimator { // This is a heads up animation return false; } - if (mHostLayout.isPinnedHeadsUp(child)) { + if (NotificationStackScrollLayout.isPinnedHeadsUp(child)) { // This is another headsUp which might move. Let's animate! return false; }