/** Update the visible children on the state. */
  private void updateVisibleChildren(
      StackScrollState resultState, StackScrollAlgorithmState state) {
    Log.d(TAG, "updateVisibleChildren: ");
    ViewGroup hostView = resultState.getHostView();
    int childCount = hostView.getChildCount();
    state.visibleChildren.clear();
    state.visibleChildren.ensureCapacity(childCount);
    int notGoneIndex = 0;
    for (int i = 0; i < childCount; i++) {
      ExpandableView v = (ExpandableView) hostView.getChildAt(i);
      if (v.getVisibility() != View.GONE) {
        notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v);
        if (v instanceof ExpandableNotificationRow) {
          ExpandableNotificationRow row = (ExpandableNotificationRow) v;

          // handle the notgoneIndex for the children as well
          List<ExpandableNotificationRow> children = row.getNotificationChildren();
          if (row.areChildrenExpanded() && children != null) {
            for (ExpandableNotificationRow childRow : children) {
              if (childRow.getVisibility() != View.GONE) {
                StackViewState childState = resultState.getViewStateForView(childRow);
                childState.notGoneIndex = notGoneIndex;
                notGoneIndex++;
              }
            }
          }
        }
      }
    }
  }
  private void updateClipping(
      StackScrollState resultState,
      StackScrollAlgorithmState algorithmState,
      AmbientState ambientState) {
    Log.d(TAG, "updateClipping: ");
    boolean dismissAllInProgress = ambientState.isDismissAllInProgress();
    float previousNotificationEnd = 0;
    float previousNotificationStart = 0;
    boolean previousNotificationIsSwiped = false;
    int childCount = algorithmState.visibleChildren.size();
    for (int i = 0; i < childCount; i++) {
      ExpandableView child = algorithmState.visibleChildren.get(i);
      StackViewState state = resultState.getViewStateForView(child);
      float newYTranslation = state.yTranslation + state.height * (1f - state.scale) / 2f;
      float newHeight = state.height * state.scale;
      // apply clipping and shadow
      float newNotificationEnd = newYTranslation + newHeight;

      float clipHeight;
      if (previousNotificationIsSwiped) {
        // When the previous notification is swiped, we don't clip the content to the
        // bottom of it.
        clipHeight = newHeight;
      } else {
        clipHeight = newNotificationEnd - previousNotificationEnd;
        clipHeight = Math.max(0.0f, clipHeight);
        if (clipHeight != 0.0f) {

          // In the unlocked shade we have to clip a little bit higher because of the rounded
          // corners of the notifications, but only if we are not fully overlapped by
          // the top card.
          float clippingCorrection = state.dimmed ? 0 : mRoundedRectCornerRadius * state.scale;
          clipHeight += clippingCorrection;
        }
      }

      updateChildClippingAndBackground(
          state, newHeight, clipHeight, newHeight - (previousNotificationStart - newYTranslation));

      if (dismissAllInProgress) {
        state.clipTopAmount = Math.max(child.getMinClipTopAmount(), state.clipTopAmount);
      }

      if (!child.isTransparent()) {
        // Only update the previous values if we are not transparent,
        // otherwise we would clip to a transparent view.
        if ((dismissAllInProgress && canChildBeDismissed(child))) {
          previousNotificationIsSwiped = true;
        } else {
          previousNotificationIsSwiped = ambientState.getDraggedViews().contains(child);
          previousNotificationEnd = newNotificationEnd;
          previousNotificationStart = newYTranslation + state.clipTopAmount * state.scale;
        }
      }
    }
  }
  private void updateFirstChildMaxSizeToMaxHeight() {
    Log.d(TAG, "updateFirstChildMaxSizeToMaxHeight: ");
    // We are expanding the shade, expand it to its full height.
    if (!isMaxSizeInitialized(mFirstChildWhileExpanding)) {

      // This child was not layouted yet, wait for a layout pass
      mFirstChildWhileExpanding.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 (mFirstChildWhileExpanding != null) {
                mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding, null);
              } else {
                mFirstChildMaxHeight = 0;
              }
              v.removeOnLayoutChangeListener(this);
            }
          });
    } else {
      mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding, null);
    }
  }
 private int getMaxAllowedChildHeight(View child, AmbientState ambientState) {
   Log.d(TAG, "getMaxAllowedChildHeight: ");
   if (child instanceof ExpandableNotificationRow) {
     ExpandableNotificationRow row = (ExpandableNotificationRow) child;
     if (ambientState == null && row.isHeadsUp()
         || ambientState != null && ambientState.getTopHeadsUpEntry() == child) {
       int extraSize = row.getIntrinsicHeight() - row.getHeadsUpHeight();
       return mCollapsedSize + extraSize;
     }
     return row.getIntrinsicHeight();
   } else if (child instanceof ExpandableView) {
     ExpandableView expandableView = (ExpandableView) child;
     return expandableView.getIntrinsicHeight();
   }
   return child == null ? mCollapsedSize : child.getHeight();
 }
 private boolean isMaxSizeInitialized(ExpandableView child) {
   Log.d(TAG, "isMaxSizeInitialized: ");
   if (child instanceof ExpandableNotificationRow) {
     ExpandableNotificationRow row = (ExpandableNotificationRow) child;
     return row.isMaxExpandHeightInitialized();
   }
   return child == null || child.getWidth() != 0;
 }
 public void onReset(ExpandableView view) {
   Log.d(TAG, "onReset: ");
   if (view.equals(mFirstChildWhileExpanding)) {
     updateFirstChildMaxSizeToMaxHeight();
   }
 }