Handling a few more border cases with HUNs

Also does sorting correctly now.
The status bar now allows touches below when a
heads-up is on.
Also fixes a few flashes when a heads up was
dismissed or appeared.

Change-Id: I4d90a07333ad2e5ea2a13704cdc9d9184716681a
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 b0f287f..1a42f45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -29,7 +29,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.TreeMap;
+import java.util.TreeSet;
 
 /**
  * The Algorithm of the {@link com.android.systemui.statusbar.stack
@@ -167,7 +167,7 @@
 
         handleDraggedViews(ambientState, resultState, algorithmState);
         updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState);
-        updateClipping(resultState, algorithmState);
+        updateClipping(resultState, algorithmState, ambientState);
         updateSpeedBumpState(resultState, algorithmState, ambientState.getSpeedBumpIndex());
         getNotificationChildrenStates(resultState, algorithmState);
     }
@@ -198,7 +198,7 @@
     }
 
     private void updateClipping(StackScrollState resultState,
-            StackScrollAlgorithmState algorithmState) {
+            StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
         float previousNotificationEnd = 0;
         float previousNotificationStart = 0;
         boolean previousNotificationIsSwiped = false;
@@ -239,7 +239,7 @@
                 // otherwise we would clip to a transparent view.
                 previousNotificationStart = newYTranslation + state.clipTopAmount * state.scale;
                 previousNotificationEnd = newNotificationEnd;
-                previousNotificationIsSwiped = child.getTranslationX() != 0;
+                previousNotificationIsSwiped = ambientState.getDraggedViews().contains(child);
             }
         }
     }
@@ -311,7 +311,9 @@
                     StackViewState viewState = resultState.getViewStateForView(
                             nextChild);
                     // The child below the dragged one must be fully visible
-                    viewState.alpha = 1;
+                    if (!isPinnedHeadsUpView(draggedView) || isPinnedHeadsUpView(nextChild)) {
+                        viewState.alpha = 1;
+                    }
                 }
 
                 // Lets set the alpha to the one it currently has, as its currently being dragged
@@ -322,6 +324,14 @@
         }
     }
 
+    private boolean isPinnedHeadsUpView(View view) {
+        if (view instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+            return row.isHeadsUp() && !row.isInShade();
+        }
+        return false;
+    }
+
     /**
      * Update the visible children on the state.
      */
@@ -332,16 +342,15 @@
         state.visibleChildren.clear();
         state.visibleChildren.ensureCapacity(childCount);
         int notGoneIndex = 0;
-        TreeMap<String, HeadsUpManager.HeadsUpEntry> headsUpEntries =
-                ambientState.getHeadsUpEntries();
-        for (String key: headsUpEntries.keySet()) {
-            ExpandableView v = headsUpEntries.get(key).entry.row;
+        TreeSet<HeadsUpManager.HeadsUpEntry> headsUpEntries
+                = ambientState.getSortedHeadsUpEntries();
+        for (HeadsUpManager.HeadsUpEntry entry: headsUpEntries) {
+            ExpandableView v = entry.entry.row;
             notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v);
         }
         for (int i = 0; i < childCount; i++) {
             ExpandableView v = (ExpandableView) hostView.getChildAt(i);
             if (v.getVisibility() != View.GONE) {
-
                 if (v instanceof ExpandableNotificationRow) {
                     ExpandableNotificationRow row = (ExpandableNotificationRow) v;
                     if (row.isHeadsUp()) {
@@ -401,13 +410,17 @@
         // How far in is the element currently transitioning into the bottom stack.
         float yPositionInScrollView = 0.0f;
 
+        // If we have a heads-up higher than the collapsed height we need to add the difference to
+        // the padding of all other elements, i.e push in the top stack slightly.
+        ExpandableNotificationRow topHeadsUpEntry = ambientState.getTopHeadsUpEntry();
+
         int childCount = algorithmState.visibleChildren.size();
         int numberOfElementsCompletelyIn = (int) algorithmState.itemsInTopStack;
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
             StackViewState childViewState = resultState.getViewStateForView(child);
             childViewState.location = StackViewState.LOCATION_UNKNOWN;
-            int childHeight = getMaxAllowedChildHeight(child);
+            int childHeight = getMaxAllowedChildHeight(child, ambientState);
             float yPositionInScrollViewAfterElement = yPositionInScrollView
                     + childHeight
                     + mPaddingBetweenElements;
@@ -486,45 +499,31 @@
             currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements;
             yPositionInScrollView = yPositionInScrollViewAfterElement;
 
+            if (ambientState.isShadeExpanded() && topHeadsUpEntry != null
+                    && child != topHeadsUpEntry) {
+                childViewState.yTranslation += topHeadsUpEntry.getHeadsUpHeight() - mCollapsedSize;
+            }
             childViewState.yTranslation += ambientState.getTopPadding()
-                    + ambientState.getPaddingOffset();
-
-            updateHeadsUpStates(resultState, algorithmState, ambientState);
+                    + ambientState.getStackTranslation();
         }
+        updateHeadsUpStates(resultState, algorithmState, ambientState);
     }
 
     private void updateHeadsUpStates(StackScrollState resultState,
             StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
-        TreeMap<String, HeadsUpManager.HeadsUpEntry> headsUpEntries =
-                ambientState.getHeadsUpEntries();
-        boolean hasPinnedHeadsUp = false;
-        for (String key: headsUpEntries.keySet()) {
-            ExpandableNotificationRow row = headsUpEntries.get(key).entry.row;
+        TreeSet<HeadsUpManager.HeadsUpEntry> headsUpEntries = ambientState.getSortedHeadsUpEntries();
+        for (HeadsUpManager.HeadsUpEntry entry: headsUpEntries) {
+            ExpandableNotificationRow row = entry.entry.row;
             StackViewState childState = resultState.getViewStateForView(row);
             if (!row.isInShade()) {
-                childState.yTranslation = Math.max(childState.yTranslation, 0);
-                hasPinnedHeadsUp = true;
+                childState.yTranslation = 0;
             }
             childState.height = Math.max(childState.height, row.getHeadsUpHeight());
+
+            // Ensure that the heads up is always visible even when scrolled of from the bottom
             childState.yTranslation = Math.min(childState.yTranslation,
                     ambientState.getMaxHeadsUpTranslation() - childState.height);
         }
-        if (hasPinnedHeadsUp && !ambientState.isShadeExpanded()) {
-            // Let's hide all normal views
-            int childCount = algorithmState.visibleChildren.size();
-            for (int i = 0; i < childCount; i++) {
-                ExpandableView child = algorithmState.visibleChildren.get(i);
-                StackViewState state = resultState.getViewStateForView(child);
-                boolean hideView = true;
-                if (child instanceof ExpandableNotificationRow) {
-                    ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                    hideView = !row.isHeadsUp();
-                }
-                if (hideView) {
-                    state.alpha = 0.0f;
-                }
-            }
-        }
     }
 
     /**
@@ -555,7 +554,7 @@
 
     /**
      * Clamp the yTranslation of the child up such that its end is at lest on the end of the top
-     * stack.get
+     * stack.
      *
      * @param childViewState the view state of the child
      * @param childHeight the height of this child
@@ -566,9 +565,12 @@
                 mCollapsedSize - childHeight);
     }
 
-    private int getMaxAllowedChildHeight(View child) {
+    private int getMaxAllowedChildHeight(View child, AmbientState ambientState) {
         if (child instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+            if (ambientState != null && ambientState.getTopHeadsUpEntry() == child) {
+                return mCollapsedSize;
+            }
             return row.getIntrinsicHeight();
         } else if (child instanceof ExpandableView) {
             ExpandableView expandableView = (ExpandableView) child;
@@ -695,7 +697,7 @@
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
             StackViewState childViewState = resultState.getViewStateForView(child);
-            int childHeight = getMaxAllowedChildHeight(child);
+            int childHeight = getMaxAllowedChildHeight(child, ambientState);
             float yPositionInScrollViewAfterElement = yPositionInScrollView
                     + childHeight
                     + mPaddingBetweenElements;
@@ -850,7 +852,7 @@
                                 int oldBottom) {
                             if (mFirstChildWhileExpanding != null) {
                                 mFirstChildMaxHeight = getMaxAllowedChildHeight(
-                                        mFirstChildWhileExpanding);
+                                        mFirstChildWhileExpanding, null);
                             } else {
                                 mFirstChildMaxHeight = 0;
                             }
@@ -858,7 +860,7 @@
                         }
                     });
         } else {
-            mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
+            mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding, null);
         }
     }