Merge "Expose locations from NotifStackScrollLayout"
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 ff8ea405..f6eeb6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -22,6 +22,7 @@
 import android.graphics.Canvas;
 import android.graphics.Outline;
 import android.graphics.Paint;
+
 import android.util.AttributeSet;
 import android.util.Log;
 
@@ -37,6 +38,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
 
 /**
  * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
@@ -86,7 +88,9 @@
     /**
      * The current State this Layout is in
      */
-    private StackScrollState mCurrentStackScrollState;
+    private final StackScrollState mCurrentStackScrollState = new StackScrollState(this);
+
+    private OnChildLocationsChangedListener mListener;
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -153,7 +157,6 @@
         // currently the padding is in the elements themself
         mPaddingBetweenElements = 0;
         mStackScrollAlgorithm = new StackScrollAlgorithm(context);
-        mCurrentStackScrollState = null;
     }
 
     @Override
@@ -188,6 +191,24 @@
         updateContentHeight();
     }
 
+    public void setChildLocationsChangedListener(OnChildLocationsChangedListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Returns the location the given child is currently rendered at.
+     *
+     * @param child the child to get the location for
+     * @return one of {@link ViewState}'s <code>LOCATION_*</code> constants
+     */
+    public int getChildLocation(View child) {
+        ViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
+        if (childViewState == null) {
+            return ViewState.LOCATION_UNKNOWN;
+        }
+        return childViewState.location;
+    }
+
     private void setMaxLayoutHeight(int maxLayoutHeight) {
         mMaxLayoutHeight = maxLayoutHeight;
         updateAlgorithmHeight();
@@ -203,13 +224,13 @@
      */
     private void updateChildren() {
         if (!isCurrentlyAnimating()) {
-            if (mCurrentStackScrollState == null) {
-                mCurrentStackScrollState = new StackScrollState(this);
-            }
             mCurrentStackScrollState.setScrollY(mOwnScrollY);
             mStackScrollAlgorithm.getStackScrollState(mCurrentStackScrollState);
             mCurrentStackScrollState.apply();
             mOwnScrollY = mCurrentStackScrollState.getScrollY();
+            if (mListener != null) {
+                mListener.onChildLocationsChanged(this);
+            }
         } else {
             // TODO: handle animation
         }
@@ -823,4 +844,11 @@
     public View getHostView() {
         return this;
     }
+
+    /**
+     * A listener that is notified when some child locations might have changed.
+     */
+    public interface OnChildLocationsChangedListener {
+        public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout);
+    }
 }
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 9db4e77..6d2ba6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.stack;
 
 import android.content.Context;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.systemui.R;
@@ -28,6 +29,8 @@
  */
 public class StackScrollAlgorithm {
 
+    private static final String LOG_TAG = "StackScrollAlgorithm";
+
     private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
     private static final int MAX_ITEMS_IN_TOP_STACK = 3;
 
@@ -130,6 +133,7 @@
             View child = hostView.getChildAt(i);
             StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
             childViewState.yTranslation = currentYPosition;
+            childViewState.location = StackScrollState.ViewState.LOCATION_UNKNOWN;
             int childHeight = child.getHeight();
             // The y position after this element
             float nextYPosition = currentYPosition + childHeight + mPaddingBetweenElements;
@@ -143,12 +147,12 @@
                 nextYPosition = updateStateForTopStackChild(algorithmState,
                         numberOfElementsCompletelyIn,
                         i, childViewState);
-
             } else if (i == algorithmState.lastTopStackIndex) {
                 // Case 2:
                 // First element of regular scrollview comes next, so the position is just the
                 // scrolling position
                 nextYPosition = scrollOffset;
+                childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
             } else if (nextYPosition >= transitioningPositionStart) {
                 if (currentYPosition >= transitioningPositionStart) {
                     // Case 3:
@@ -156,8 +160,6 @@
                     // bottom of the screen so we are fully in the bottom stack
                     nextYPosition = updateStateForChildFullyInBottomStack(algorithmState,
                             transitioningPositionStart, childViewState, childHeight);
-
-
                 } else {
                     // Case 4:
                     // According to the regular scroll view we are currently translating out of /
@@ -167,6 +169,16 @@
                             currentYPosition, childViewState,
                             childHeight, nextYPosition);
                 }
+            } else {
+                childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
+            }
+            // The first card is always rendered.
+            if (i == 0) {
+                childViewState.alpha = 1.0f;
+                childViewState.location = StackScrollState.ViewState.LOCATION_FIRST_CARD;
+            }
+            if (childViewState.location == StackScrollState.ViewState.LOCATION_UNKNOWN) {
+                Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
             }
             currentYPosition = nextYPosition;
             yPositionInScrollView = yPositionInScrollViewAfterElement;
@@ -192,6 +204,8 @@
         if (childHeight != (int) newSize) {
             childViewState.height = (int) newSize;
         }
+        childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
+
         return nextYPosition;
     }
 
@@ -206,6 +220,7 @@
             nextYPosition = transitioningPositionStart
                     + mBottomStackIndentationFunctor.getValue(
                             algorithmState.itemsInBottomStack);
+            childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_PEEKING;
         } else {
             // we are fully inside the stack
             if (algorithmState.itemsInBottomStack > MAX_ITEMS_IN_BOTTOM_STACK + 2) {
@@ -214,6 +229,7 @@
                     > MAX_ITEMS_IN_BOTTOM_STACK + 1) {
                 childViewState.alpha = 1.0f - algorithmState.partialInBottom;
             }
+            childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_HIDDEN;
             nextYPosition = transitioningPositionStart + mBottomStackPeekSize;
         }
         // TODO: only temporarily collapse
@@ -237,14 +253,16 @@
             nextYPosition = mCollapsedSize + mPaddingBetweenElements -
                     mTopStackIndentationFunctor.getValue(
                             algorithmState.itemsInTopStack - i - 1);
-            if (paddedIndex == 0 && i != 0) {
+            if (paddedIndex == 0) {
                 childViewState.alpha = 1.0f - algorithmState.partialInTop;
+                childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN;
+            } else {
+                childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
             }
         } else {
-            // We are hidden behind the top card and faded out, so we can hide ourselfs
-            if (i != 0) {
-                childViewState.alpha = 0.0f;
-            }
+            // We are hidden behind the top card and faded out, so we can hide ourselves.
+            childViewState.alpha = 0.0f;
+            childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN;
         }
         return nextYPosition;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index f72a52f..881730a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -45,7 +45,7 @@
 
     public StackScrollState(ViewGroup hostView) {
         mHostView = hostView;
-        mStateMap = new HashMap<View, ViewState>(mHostView.getChildCount());
+        mStateMap = new HashMap<View, ViewState>();
     }
 
     public ViewGroup getHostView() {
@@ -144,10 +144,28 @@
     }
 
 
-    public class ViewState {
+    public static class ViewState {
+
+        // These are flags such that we can create masks for filtering.
+
+        public static final int LOCATION_UNKNOWN = 0x00;
+        public static final int LOCATION_FIRST_CARD = 0x01;
+        public static final int LOCATION_TOP_STACK_HIDDEN = 0x02;
+        public static final int LOCATION_TOP_STACK_PEEKING = 0x04;
+        public static final int LOCATION_MAIN_AREA = 0x08;
+        public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x10;
+        public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x20;
+
         float alpha;
         float yTranslation;
         float zTranslation;
         int height;
+
+        /**
+         * The location this view is currently rendered at.
+         *
+         * <p>See <code>LOCATION_</code> flags.</p>
+         */
+        int location;
     }
 }