From a4d195d2e17f018d0b984c50282c7d0fa49ca481 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Fri, 16 Nov 2018 13:33:27 -0500 Subject: [PATCH] Refactor ExpandableView to maintain its own ExpandableViewState. Bug: 119282834 Test: atest SystemUITests (and manual) Change-Id: I2067488482d9f48767d8e2c9b37c69a40c3b0d88 --- .../systemui/statusbar/EmptyShadeView.java | 3 +- .../systemui/statusbar/NotificationShelf.java | 56 ++++---- .../row/ExpandableNotificationRow.java | 77 ++++------ .../notification/row/ExpandableView.java | 55 +++++++- .../notification/row/FooterView.java | 3 +- .../notification/stack/AmbientState.java | 7 +- .../stack/NotificationChildrenContainer.java | 23 ++- .../stack/NotificationListContainer.java | 17 +-- .../stack/NotificationRoundnessManager.java | 10 +- .../stack/NotificationStackScrollLayout.java | 104 +++++++------- .../stack/StackScrollAlgorithm.java | 133 ++++++++++-------- .../notification/stack/StackScrollState.java | 117 --------------- .../stack/StackStateAnimator.java | 62 ++++---- .../NotificationViewHierarchyManagerTest.java | 10 +- .../NotificationRoundnessManagerTest.java | 4 +- 15 files changed, 292 insertions(+), 389 deletions(-) delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollState.java diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java index 745b2f95329d1..b9684fcb8a01e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java @@ -27,7 +27,6 @@ import android.widget.TextView; import com.android.systemui.R; import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; -import com.android.systemui.statusbar.notification.stack.StackScrollState; public class EmptyShadeView extends StackScrollerDecorView { @@ -74,7 +73,7 @@ public class EmptyShadeView extends StackScrollerDecorView { } @Override - public ExpandableViewState createNewViewState(StackScrollState stackScrollState) { + public ExpandableViewState createExpandableViewState() { return new EmptyShadeViewState(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 37cc299b5880e..e7b4904a8ba5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -47,7 +47,6 @@ import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; -import com.android.systemui.statusbar.notification.stack.StackScrollState; import com.android.systemui.statusbar.notification.stack.ViewState; import com.android.systemui.statusbar.phone.NotificationIconContainer; @@ -68,7 +67,6 @@ public class NotificationShelf extends ActivatableNotificationView implements private boolean mDark; private NotificationIconContainer mShelfIcons; - private ShelfState mShelfState; private int[] mTmp = new int[2]; private boolean mHideBackground; private int mIconAppearTopPadding; @@ -115,7 +113,6 @@ public class NotificationShelf extends ActivatableNotificationView implements setClipChildren(false); setClipToPadding(false); mShelfIcons.setIsStaticLayout(false); - mShelfState = new ShelfState(); setBottomRoundness(1.0f, false /* animate */); initDimens(); } @@ -187,52 +184,53 @@ public class NotificationShelf extends ActivatableNotificationView implements } @Override - public ExpandableViewState createNewViewState(StackScrollState stackScrollState) { - return mShelfState; + public ExpandableViewState createExpandableViewState() { + return new ShelfState(); } - public void updateState(StackScrollState resultState, - AmbientState ambientState) { - View lastView = ambientState.getLastVisibleBackgroundChild(); + /** Update the state of the shelf. */ + public void updateState(AmbientState ambientState) { + ExpandableView lastView = ambientState.getLastVisibleBackgroundChild(); + ShelfState viewState = (ShelfState) getViewState(); if (mShowNotificationShelf && lastView != null) { float maxShelfEnd = ambientState.getInnerHeight() + ambientState.getTopPadding() + ambientState.getStackTranslation(); - ExpandableViewState lastViewState = resultState.getViewStateForView(lastView); + ExpandableViewState lastViewState = lastView.getViewState(); float viewEnd = lastViewState.yTranslation + lastViewState.height; - mShelfState.copyFrom(lastViewState); - mShelfState.height = getIntrinsicHeight(); + viewState.copyFrom(lastViewState); + viewState.height = getIntrinsicHeight(); - float awakenTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - mShelfState.height, + float awakenTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - viewState.height, getFullyClosedTranslation()); float darkTranslation = mAmbientState.getDarkTopPadding(); float yRatio = mAmbientState.hasPulsingNotifications() ? 0 : mAmbientState.getDarkAmount(); - mShelfState.yTranslation = MathUtils.lerp(awakenTranslation, darkTranslation, yRatio); - mShelfState.zTranslation = ambientState.getBaseZHeight(); + viewState.yTranslation = MathUtils.lerp(awakenTranslation, darkTranslation, yRatio); + viewState.zTranslation = ambientState.getBaseZHeight(); // For the small display size, it's not enough to make the icon not covered by // the top cutout so the denominator add the height of cutout. // Totally, (getIntrinsicHeight() * 2 + mCutoutHeight) should be smaller then // mAmbientState.getTopPadding(). - float openedAmount = (mShelfState.yTranslation - getFullyClosedTranslation()) + float openedAmount = (viewState.yTranslation - getFullyClosedTranslation()) / (getIntrinsicHeight() * 2 + mCutoutHeight); openedAmount = Math.min(1.0f, openedAmount); - mShelfState.openedAmount = openedAmount; - mShelfState.clipTopAmount = 0; - mShelfState.alpha = mAmbientState.hasPulsingNotifications() ? 0 : 1; - mShelfState.belowSpeedBump = mAmbientState.getSpeedBumpIndex() == 0; - mShelfState.hideSensitive = false; - mShelfState.xTranslation = getTranslationX(); + viewState.openedAmount = openedAmount; + viewState.clipTopAmount = 0; + viewState.alpha = mAmbientState.hasPulsingNotifications() ? 0 : 1; + viewState.belowSpeedBump = mAmbientState.getSpeedBumpIndex() == 0; + viewState.hideSensitive = false; + viewState.xTranslation = getTranslationX(); if (mNotGoneIndex != -1) { - mShelfState.notGoneIndex = Math.min(mShelfState.notGoneIndex, mNotGoneIndex); + viewState.notGoneIndex = Math.min(viewState.notGoneIndex, mNotGoneIndex); } - mShelfState.hasItemsInStableShelf = lastViewState.inShelf; - mShelfState.hidden = !mAmbientState.isShadeExpanded() + viewState.hasItemsInStableShelf = lastViewState.inShelf; + viewState.hidden = !mAmbientState.isShadeExpanded() || mAmbientState.isQsCustomizerShowing(); - mShelfState.maxShelfEnd = maxShelfEnd; + viewState.maxShelfEnd = maxShelfEnd; } else { - mShelfState.hidden = true; - mShelfState.location = ExpandableViewState.LOCATION_GONE; - mShelfState.hasItemsInStableShelf = false; + viewState.hidden = true; + viewState.location = ExpandableViewState.LOCATION_GONE; + viewState.hasItemsInStableShelf = false; } } @@ -261,7 +259,7 @@ public class NotificationShelf extends ActivatableNotificationView implements int notGoneIndex = 0; int colorOfViewBeforeLast = NO_COLOR; boolean backgroundForceHidden = false; - if (mHideBackground && !mShelfState.hasItemsInStableShelf) { + if (mHideBackground && !((ShelfState) getViewState()).hasItemsInStableShelf) { backgroundForceHidden = true; } int colorTwoBefore = NO_COLOR; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 23bfdad02e7dd..0cd431f9d25b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -17,22 +17,14 @@ package com.android.systemui.statusbar.notification.row; import static com.android.systemui.statusbar.StatusBarState.SHADE; -import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator - .ExpandAnimationParameters; -import static com.android.systemui.statusbar.notification.row.NotificationContentView - .VISIBLE_TYPE_AMBIENT; -import static com.android.systemui.statusbar.notification.row.NotificationContentView - .VISIBLE_TYPE_CONTRACTED; -import static com.android.systemui.statusbar.notification.row.NotificationContentView - .VISIBLE_TYPE_HEADSUP; -import static com.android.systemui.statusbar.notification.row.NotificationInflater - .FLAG_CONTENT_VIEW_AMBIENT; -import static com.android.systemui.statusbar.notification.row.NotificationInflater - .FLAG_CONTENT_VIEW_HEADS_UP; -import static com.android.systemui.statusbar.notification.row.NotificationInflater - .FLAG_CONTENT_VIEW_PUBLIC; -import static com.android.systemui.statusbar.notification.row.NotificationInflater - .InflationCallback; +import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters; +import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT; +import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED; +import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP; +import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT; +import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP; +import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_PUBLIC; +import static com.android.systemui.statusbar.notification.row.NotificationInflater.InflationCallback; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -105,7 +97,6 @@ import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; -import com.android.systemui.statusbar.notification.stack.StackScrollState; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -337,7 +328,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private float mTranslationWhenRemoved; private boolean mWasChildInGroupWhenRemoved; private int mNotificationColorAmbient; - private NotificationViewState mNotificationViewState; private SystemNotificationAsyncTask mSystemNotificationAsyncTask = new SystemNotificationAsyncTask(); @@ -894,29 +884,32 @@ public class ExpandableNotificationRow extends ActivatableNotificationView visualStabilityManager, callback); } - public void getChildrenStates(StackScrollState resultState, - AmbientState ambientState) { + /** Updates states of all children. */ + public void updateChildrenStates(AmbientState ambientState) { if (mIsSummaryWithChildren) { - ExpandableViewState parentState = resultState.getViewStateForView(this); - mChildrenContainer.getState(resultState, parentState, ambientState); + ExpandableViewState parentState = getViewState(); + mChildrenContainer.updateState(parentState, ambientState); } } - public void applyChildrenState(StackScrollState state) { + /** Applies children states. */ + public void applyChildrenState() { if (mIsSummaryWithChildren) { - mChildrenContainer.applyState(state); + mChildrenContainer.applyState(); } } - public void prepareExpansionChanged(StackScrollState state) { + /** Prepares expansion changed. */ + public void prepareExpansionChanged() { if (mIsSummaryWithChildren) { - mChildrenContainer.prepareExpansionChanged(state); + mChildrenContainer.prepareExpansionChanged(); } } - public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) { + /** Starts child animations. */ + public void startChildAnimation(AnimationProperties properties) { if (mIsSummaryWithChildren) { - mChildrenContainer.startAnimationToState(finalState, properties); + mChildrenContainer.startAnimationToState(properties); } } @@ -2047,7 +2040,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView .setInterpolator(Interpolators.ALPHA_OUT); setAboveShelf(true); mExpandAnimationRunning = true; - mNotificationViewState.cancelAnimations(this); + getViewState().cancelAnimations(this); mNotificationLaunchHeight = AmbientState.getNotificationLaunchHeight(getContext()); } else { mExpandAnimationRunning = false; @@ -2924,13 +2917,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } @Override - public ExpandableViewState createNewViewState(StackScrollState stackScrollState) { - mNotificationViewState = new NotificationViewState(stackScrollState); - return mNotificationViewState; - } - - public NotificationViewState getViewState() { - return mNotificationViewState; + public ExpandableViewState createExpandableViewState() { + return new NotificationViewState(); } @Override @@ -3040,14 +3028,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } } - public static class NotificationViewState extends ExpandableViewState { - - private final StackScrollState mOverallState; - - - private NotificationViewState(StackScrollState stackScrollState) { - mOverallState = stackScrollState; - } + private static class NotificationViewState extends ExpandableViewState { @Override public void applyToView(View view) { @@ -3058,7 +3039,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } handleFixedTranslationZ(row); super.applyToView(view); - row.applyChildrenState(mOverallState); + row.applyChildrenState(); } } @@ -3089,7 +3070,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } handleFixedTranslationZ(row); super.animateTo(child, properties); - row.startChildAnimation(mOverallState, properties); + row.startChildAnimation(properties); } } } @@ -3144,8 +3125,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView pw.println(); showingLayout.dump(fd, pw, args); pw.print(" "); - if (mNotificationViewState != null) { - mNotificationViewState.dump(fd, pw, args); + if (getViewState() != null) { + getViewState().dump(fd, pw, args); } else { pw.print("no viewState!!!"); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index 0589e3f63973b..1e8de076cbedf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -21,23 +21,27 @@ import android.content.Context; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; +import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; +import androidx.annotation.Nullable; + import com.android.systemui.Dumpable; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; -import com.android.systemui.statusbar.notification.stack.StackScrollState; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.List; /** * An abstract view for expandable views. */ public abstract class ExpandableView extends FrameLayout implements Dumpable { + private static final String TAG = "ExpandableView"; public static final float NO_ROUNDNESS = -1; protected OnHeightChangedListener mOnHeightChangedListener; @@ -54,6 +58,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { private ViewGroup mTransientContainer; private boolean mInShelf; private boolean mTransformingInShelf; + @Nullable private ExpandableViewState mViewState; public ExpandableView(Context context, AttributeSet attrs) { super(context, attrs); @@ -511,10 +516,56 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { public void setActualHeightAnimating(boolean animating) {} - public ExpandableViewState createNewViewState(StackScrollState stackScrollState) { + protected ExpandableViewState createExpandableViewState() { return new ExpandableViewState(); } + /** Sets {@link ExpandableViewState} to default state. */ + public ExpandableViewState resetViewState() { + // TODO(http://b/119762423): Move the null check to getViewState(). + if (mViewState == null) { + mViewState = createExpandableViewState(); + } + + // initialize with the default values of the view + mViewState.height = getIntrinsicHeight(); + mViewState.gone = getVisibility() == View.GONE; + mViewState.alpha = 1f; + mViewState.notGoneIndex = -1; + mViewState.xTranslation = getTranslationX(); + mViewState.hidden = false; + mViewState.scaleX = getScaleX(); + mViewState.scaleY = getScaleY(); + mViewState.inShelf = false; + mViewState.headsUpIsVisible = false; + + // handling reset for child notifications + if (this instanceof ExpandableNotificationRow) { + ExpandableNotificationRow row = (ExpandableNotificationRow) this; + List children = row.getNotificationChildren(); + if (row.isSummaryWithChildren() && children != null) { + for (ExpandableNotificationRow childRow : children) { + childRow.resetViewState(); + } + } + } + + return mViewState; + } + + @Nullable public ExpandableViewState getViewState() { + return mViewState; + } + + /** Applies internal {@link ExpandableViewState} to this view. */ + public void applyViewState() { + if (mViewState == null) { + Log.wtf(TAG, "No child state was found when applying this state to the hostView"); + } else if (!mViewState.gone) { + mViewState.applyToView(this); + } + } + /** * @return whether the current view doesn't add height to the overall content. This means that * if it is added to a list of items, it's content will still have the same height. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java index 1f15ed0125510..311bf7a244c11 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java @@ -24,7 +24,6 @@ import android.view.View; import com.android.systemui.R; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; -import com.android.systemui.statusbar.notification.stack.StackScrollState; public class FooterView extends StackScrollerDecorView { private final int mClearAllTopPadding; @@ -87,7 +86,7 @@ public class FooterView extends StackScrollerDecorView { } @Override - public ExpandableViewState createNewViewState(StackScrollState stackScrollState) { + public ExpandableViewState createExpandableViewState() { return new FooterViewState(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java index ff1a6fc075d09..670908fe175da 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java @@ -40,7 +40,7 @@ public class AmbientState { private static final int NO_SECTION_BOUNDARY = -1; - private ArrayList mDraggedViews = new ArrayList<>(); + private ArrayList mDraggedViews = new ArrayList<>(); private int mScrollY; private boolean mDimmed; private ActivatableNotificationView mActivatedChild; @@ -131,7 +131,8 @@ public class AmbientState { this.mScrollY = scrollY; } - public void onBeginDrag(View view) { + /** Call when dragging begins. */ + public void onBeginDrag(ExpandableView view) { mDraggedViews.add(view); } @@ -139,7 +140,7 @@ public class AmbientState { mDraggedViews.remove(view); } - public ArrayList getDraggedViews() { + public ArrayList getDraggedViews() { return mDraggedViews; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 74b4aa2a70578..0f38bd9804a9c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -274,7 +274,7 @@ public class NotificationChildrenContainer extends ViewGroup { updateGroupOverflow(); row.setContentTransformationAmount(0, false /* isLastChild */); // It doesn't make sense to keep old animations around, lets cancel them! - ExpandableNotificationRow.NotificationViewState viewState = row.getViewState(); + ExpandableViewState viewState = row.getViewState(); if (viewState != null) { viewState.cancelAnimations(row); row.cancelAppearDrawing(); @@ -562,12 +562,10 @@ public class NotificationChildrenContainer extends ViewGroup { /** * Update the state of all its children based on a linear layout algorithm. - * @param resultState the state to update * @param parentState the state of the parent * @param ambientState */ - public void getState(StackScrollState resultState, ExpandableViewState parentState, - AmbientState ambientState) { + public void updateState(ExpandableViewState parentState, AmbientState ambientState) { int childCount = mChildren.size(); int yPosition = mNotificationHeaderMargin + mCurrentHeaderTranslation; boolean firstChild = true; @@ -605,7 +603,7 @@ public class NotificationChildrenContainer extends ViewGroup { firstChild = false; } - ExpandableViewState childState = resultState.getViewStateForView(child); + ExpandableViewState childState = child.getViewState(); int intrinsicHeight = child.getIntrinsicHeight(); childState.height = intrinsicHeight; childState.yTranslation = yPosition + launchTransitionCompensation; @@ -639,7 +637,7 @@ public class NotificationChildrenContainer extends ViewGroup { if (mOverflowNumber != null) { ExpandableNotificationRow overflowView = mChildren.get(Math.min( getMaxAllowedVisibleChildren(true /* likeCollapsed */), childCount) - 1); - mGroupOverFlowState.copyFrom(resultState.getViewStateForView(overflowView)); + mGroupOverFlowState.copyFrom(overflowView.getViewState()); if (mContainingNotification.isOnAmbient()) { mGroupOverFlowState.alpha = 0.0f; @@ -724,7 +722,8 @@ public class NotificationChildrenContainer extends ViewGroup { return NUMBER_OF_CHILDREN_WHEN_COLLAPSED; } - public void applyState(StackScrollState state) { + /** Applies state to children. */ + public void applyState() { int childCount = mChildren.size(); ViewState tmpState = new ViewState(); float expandFraction = 0.0f; @@ -737,7 +736,7 @@ public class NotificationChildrenContainer extends ViewGroup { && !mHideDividersDuringExpand); for (int i = 0; i < childCount; i++) { ExpandableNotificationRow child = mChildren.get(i); - ExpandableViewState viewState = state.getViewStateForView(child); + ExpandableViewState viewState = child.getViewState(); viewState.applyToView(child); // layout the divider @@ -799,14 +798,14 @@ public class NotificationChildrenContainer extends ViewGroup { * This is called when the children expansion has changed and positions the children properly * for an appear animation. * - * @param state the new state we animate to */ - public void prepareExpansionChanged(StackScrollState state) { + public void prepareExpansionChanged() { // TODO: do something that makes sense, like placing the invisible views correctly return; } - public void startAnimationToState(StackScrollState state, AnimationProperties properties) { + /** Animate to a given state. */ + public void startAnimationToState(AnimationProperties properties) { int childCount = mChildren.size(); ViewState tmpState = new ViewState(); float expandFraction = getGroupExpandFraction(); @@ -816,7 +815,7 @@ public class NotificationChildrenContainer extends ViewGroup { && !mHideDividersDuringExpand); for (int i = childCount - 1; i >= 0; i--) { ExpandableNotificationRow child = mChildren.get(i); - ExpandableViewState viewState = state.getViewStateForView(child); + ExpandableViewState viewState = child.getViewState(); viewState.animateTo(child, properties); // layout the divider diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java index 6de4fc80cb4d0..f0a26536d7b85 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java @@ -45,34 +45,31 @@ public interface NotificationListContainer extends ExpandableView.OnHeightChange /** * Change the position of child to a new location - * - * @param child the view to change the position for + * @param child the view to change the position for * @param newIndex the new index */ - void changeViewPosition(View child, int newIndex); + void changeViewPosition(ExpandableView child, int newIndex); /** * Called when a child was added to a group. * * @param row row of the group child that was added */ - void notifyGroupChildAdded(View row); + void notifyGroupChildAdded(ExpandableView row); /** * Called when a child was removed from a group. - * - * @param row row of the child that was removed + * @param row row of the child that was removed * @param childrenContainer ViewGroup of the group that the child was removed from */ - void notifyGroupChildRemoved(View row, ViewGroup childrenContainer); + void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer); /** * Generate an animation for an added child view. - * - * @param child The view to be added. + * @param child The view to be added. * @param fromMoreCard Whether this add is coming from the "more" card on lockscreen. */ - void generateAddAnimation(View child, boolean fromMoreCard); + void generateAddAnimation(ExpandableView child, boolean fromMoreCard); /** * Generate a child order changed event. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java index 27838a2a6a978..4f0831f1043c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java @@ -16,14 +16,12 @@ package com.android.systemui.statusbar.notification.stack; -import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout - .NUM_SECTIONS; - -import android.view.View; +import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.NUM_SECTIONS; import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import java.util.HashSet; @@ -38,7 +36,7 @@ class NotificationRoundnessManager implements OnHeadsUpChangedListener { private ActivatableNotificationView[] mLastInSectionViews; private ActivatableNotificationView[] mTmpFirstInSectionViews; private ActivatableNotificationView[] mTmpLastInSectionViews; - private HashSet mAnimatedChildren; + private HashSet mAnimatedChildren; private Runnable mRoundingChangedCallback; private ExpandableNotificationRow mTrackedHeadsUp; private float mAppearFraction; @@ -212,7 +210,7 @@ class NotificationRoundnessManager implements OnHeadsUpChangedListener { return anyChanged; } - public void setAnimatedChildren(HashSet animatedChildren) { + public void setAnimatedChildren(HashSet animatedChildren) { mAnimatedChildren = animatedChildren; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index faccff392af5a..626e68850c12a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -208,16 +208,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd */ protected final StackScrollAlgorithm mStackScrollAlgorithm; - /** - * The current State this Layout is in - */ - private StackScrollState mCurrentStackScrollState = new StackScrollState(this); private final AmbientState mAmbientState; private NotificationGroupManager mGroupManager; - private HashSet mChildrenToAddAnimated = new HashSet<>(); + private HashSet mChildrenToAddAnimated = new HashSet<>(); private ArrayList mAddedHeadsUpChildren = new ArrayList<>(); - private ArrayList mChildrenToRemoveAnimated = new ArrayList<>(); - private ArrayList mChildrenChangingPositions = new ArrayList<>(); + private ArrayList mChildrenToRemoveAnimated = new ArrayList<>(); + private ArrayList mChildrenChangingPositions = new ArrayList<>(); private HashSet mFromMoreCardAdditions = new HashSet<>(); private ArrayList mAnimationEvents = new ArrayList<>(); private ArrayList mSwipedOutViews = new ArrayList<>(); @@ -275,7 +271,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private boolean mDontReportNextOverScroll; private boolean mDontClampNextScroll; private boolean mNeedViewResizeAnimation; - private View mExpandedGroupView; + private ExpandableView mExpandedGroupView; private boolean mEverythingNeedsAnimation; /** @@ -382,7 +378,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private boolean mGroupExpandedForMeasure; private boolean mScrollable; private View mForcedScroll; - private View mNeedingPulseAnimation; + private ExpandableView mNeedingPulseAnimation; /** * @see #setDarkAmount(float, float) @@ -899,7 +895,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM) public boolean isInVisibleLocation(NotificationData.Entry entry) { ExpandableNotificationRow row = entry.getRow(); - ExpandableViewState childViewState = mCurrentStackScrollState.getViewStateForView(row); + ExpandableViewState childViewState = row.getViewState(); + if (childViewState == null) { return false; } @@ -945,7 +942,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd ? 0 : mScroller.getCurrVelocity()); mAmbientState.setScrollY(mOwnScrollY); - mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState); + mStackScrollAlgorithm.resetViewStates(mAmbientState); if (!isCurrentlyAnimating() && !mNeedsAnimation) { applyCurrentState(); } else { @@ -1937,12 +1934,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * @return the last child which has visibility unequal to GONE */ @ShadeViewRefactor(RefactorComponent.COORDINATOR) - public View getLastChildNotGone() { + public ExpandableView getLastChildNotGone() { int childCount = getChildCount(); for (int i = childCount - 1; i >= 0; i--) { View child = getChildAt(i); if (child.getVisibility() != View.GONE && child != mShelf) { - return child; + return (ExpandableView) child; } } return null; @@ -2511,7 +2508,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd // we only call our internal methods if this is actually a removal and not just a // notification which becomes a child notification if (!mChildTransferInProgress) { - onViewRemovedInternal(child, this); + onViewRemovedInternal((ExpandableView) child, this); } } @@ -2522,25 +2519,22 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd if (child == mSwipeHelper.getTranslatingParentView()) { mSwipeHelper.clearTranslatingParentView(); } - mCurrentStackScrollState.removeViewStateForView(child); } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - private void onViewRemovedInternal(View child, ViewGroup container) { + private void onViewRemovedInternal(ExpandableView child, ViewGroup container) { if (mChangePositionInProgress) { // This is only a position change, don't do anything special return; } - ExpandableView expandableView = (ExpandableView) child; - expandableView.setOnHeightChangedListener(null); - mCurrentStackScrollState.removeViewStateForView(child); - updateScrollStateForRemovedChild(expandableView); + child.setOnHeightChangedListener(null); + updateScrollStateForRemovedChild(child); boolean animationGenerated = generateRemoveAnimation(child); if (animationGenerated) { if (!mSwipedOutViews.contains(child) - || Math.abs(expandableView.getTranslation()) != expandableView.getWidth()) { + || Math.abs(child.getTranslation()) != child.getWidth()) { container.addTransientView(child, 0); - expandableView.setTransientContainer(container); + child.setTransientContainer(container); } } else { mSwipedOutViews.remove(child); @@ -2584,14 +2578,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * @return Whether an animation was generated. */ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - private boolean generateRemoveAnimation(View child) { + private boolean generateRemoveAnimation(ExpandableView child) { if (removeRemovedChildFromHeadsUpChangeAnimations(child)) { mAddedHeadsUpChildren.remove(child); return false; } if (isClickedHeadsUp(child)) { // An animation is already running, add it transiently - mClearTransientViewsWhenFinished.add((ExpandableView) child); + mClearTransientViewsWhenFinished.add(child); return true; } if (mIsExpanded && mAnimationsEnabled && !isChildInInvisibleGroup(child)) { @@ -2765,7 +2759,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void onViewAdded(View child) { super.onViewAdded(child); - onViewAddedInternal(child); + onViewAddedInternal((ExpandableView) child); } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) @@ -2835,31 +2829,28 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - private void onViewAddedInternal(View child) { + private void onViewAddedInternal(ExpandableView child) { updateHideSensitiveForChild(child); - ((ExpandableView) child).setOnHeightChangedListener(this); + child.setOnHeightChangedListener(this); generateAddAnimation(child, false /* fromMoreCard */); updateAnimationState(child); updateChronometerForChild(child); } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - private void updateHideSensitiveForChild(View child) { - if (child instanceof ExpandableView) { - ExpandableView expandableView = (ExpandableView) child; - expandableView.setHideSensitiveForIntrinsicHeight(mAmbientState.isHideSensitive()); - } + private void updateHideSensitiveForChild(ExpandableView child) { + child.setHideSensitiveForIntrinsicHeight(mAmbientState.isHideSensitive()); } @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void notifyGroupChildRemoved(View row, ViewGroup childrenContainer) { + public void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer) { onViewRemovedInternal(row, childrenContainer); } @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void notifyGroupChildAdded(View row) { + public void notifyGroupChildAdded(ExpandableView row) { onViewAddedInternal(row); } @@ -2931,7 +2922,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void generateAddAnimation(View child, boolean fromMoreCard) { + public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) { if (mIsExpanded && mAnimationsEnabled && !mChangePositionInProgress) { // Generate Animations mChildrenToAddAnimated.add(child); @@ -2948,7 +2939,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void changeViewPosition(View child, int newIndex) { + public void changeViewPosition(ExpandableView child, int newIndex) { int currentIndex = indexOfChild(child); if (currentIndex == -1) { @@ -2987,8 +2978,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } if (!mAnimationEvents.isEmpty() || isCurrentlyAnimating()) { setAnimationRunning(true); - mStateAnimator.startAnimationForEvents(mAnimationEvents, mCurrentStackScrollState, - mGoToFullShadeDelay); + mStateAnimator.startAnimationForEvents(mAnimationEvents, mGoToFullShadeDelay); mAnimationEvents.clear(); updateBackground(); updateViewShadows(); @@ -3035,7 +3025,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd continue; } } else { - ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView(row); + ExpandableViewState viewState = row.getViewState(); if (viewState == null) { // A view state was never generated for this view, so we don't need to animate // this. This may happen with notification children. @@ -3101,7 +3091,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) private void generateChildRemovalEvents() { - for (View child : mChildrenToRemoveAnimated) { + for (ExpandableView child : mChildrenToRemoveAnimated) { boolean childWasSwipedOut = mSwipedOutViews.contains(child); // we need to know the view after this one @@ -3143,7 +3133,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) private void generatePositionChangeEvents() { - for (View child : mChildrenChangingPositions) { + for (ExpandableView child : mChildrenChangingPositions) { mAnimationEvents.add(new AnimationEvent(child, AnimationEvent.ANIMATION_TYPE_CHANGE_POSITION)); } @@ -3157,7 +3147,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) private void generateChildAdditionEvents() { - for (View child : mChildrenToAddAnimated) { + for (ExpandableView child : mChildrenToAddAnimated) { if (mFromMoreCardAdditions.contains(child)) { mAnimationEvents.add(new AnimationEvent(child, AnimationEvent.ANIMATION_TYPE_ADD, @@ -3249,7 +3239,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM) protected StackScrollAlgorithm createStackScrollAlgorithm(Context context) { - return new StackScrollAlgorithm(context); + return new StackScrollAlgorithm(context, this); } /** @@ -3914,7 +3904,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mStatusBar.resetUserExpandedStates(); clearTemporaryViews(); clearUserLockedViews(); - ArrayList draggedViews = mAmbientState.getDraggedViews(); + ArrayList draggedViews = mAmbientState.getDraggedViews(); if (draggedViews.size() > 0) { draggedViews.clear(); updateContinuousShadowDrawing(); @@ -4198,7 +4188,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) private void applyCurrentState() { - mCurrentStackScrollState.apply(); + int numChildren = getChildCount(); + for (int i = 0; i < numChildren; i++) { + ExpandableView child = (ExpandableView) getChildAt(i); + child.applyViewState(); + } + if (mListener != null) { mListener.onChildLocationsChanged(); } @@ -4942,8 +4937,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd if (!(child instanceof ExpandableNotificationRow)) { pw.println(" " + child.getClass().getSimpleName()); // Notifications dump it's viewstate as part of their dump to support children - ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView( - child); + ExpandableViewState viewState = child.getViewState(); if (viewState == null) { pw.println(" no viewState!!!"); } else { @@ -4960,7 +4954,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd ExpandableView child = (ExpandableView) getTransientView(i); child.dump(fd, pw, args); } - ArrayList draggedViews = mAmbientState.getDraggedViews(); + ArrayList draggedViews = mAmbientState.getDraggedViews(); int draggedCount = draggedViews.size(); pw.println(" Dragged Views: " + draggedCount); for (int i = 0; i < draggedCount; i++) { @@ -5496,7 +5490,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd static final int DARK_ANIMATION_ORIGIN_INDEX_BELOW = -2; final long eventStartTime; - final View changingView; + final ExpandableView mChangingView; final int animationType; final AnimationFilter filter; final long length; @@ -5504,21 +5498,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd int darkAnimationOriginIndex; boolean headsUpFromBottom; - AnimationEvent(View view, int type) { + AnimationEvent(ExpandableView view, int type) { this(view, type, LENGTHS[type]); } - AnimationEvent(View view, int type, AnimationFilter filter) { + AnimationEvent(ExpandableView view, int type, AnimationFilter filter) { this(view, type, LENGTHS[type], filter); } - AnimationEvent(View view, int type, long length) { + AnimationEvent(ExpandableView view, int type, long length) { this(view, type, length, FILTERS[type]); } - AnimationEvent(View view, int type, long length, AnimationFilter filter) { + AnimationEvent(ExpandableView view, int type, long length, AnimationFilter filter) { eventStartTime = AnimationUtils.currentAnimationTimeMillis(); - changingView = view; + mChangingView = view; animationType = type; this.length = length; this.filter = filter; @@ -5716,7 +5710,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd public void onBeginDrag(View v) { mFalsingManager.onNotificatonStartDismissing(); setSwipingInProgress(true); - mAmbientState.onBeginDrag(v); + mAmbientState.onBeginDrag((ExpandableView) v); updateContinuousShadowDrawing(); requestChildrenUpdate(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 87c361af9f660..25fb7f9197e47 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -42,6 +42,7 @@ import java.util.List; public class StackScrollAlgorithm { private static final String LOG_TAG = "StackScrollAlgorithm"; + private final ViewGroup mHostView; private int mPaddingBetweenElements; private int mIncreasedPaddingBetweenElements; @@ -55,7 +56,8 @@ public class StackScrollAlgorithm { private float mHeadsUpInset; private int mPinnedZTranslationExtra; - public StackScrollAlgorithm(Context context) { + public StackScrollAlgorithm(Context context, ViewGroup hostView) { + mHostView = hostView; initView(context); } @@ -79,49 +81,59 @@ public class StackScrollAlgorithm { mGapHeight = res.getDimensionPixelSize(R.dimen.notification_section_divider_height); } - public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) { + /** + * Updates the state of all children in the hostview based on this algorithm. + */ + public void resetViewStates(AmbientState ambientState) { // The state of the local variables are saved in an algorithmState to easily subdivide it // into multiple phases. StackScrollAlgorithmState algorithmState = mTempAlgorithmState; // First we reset the view states to their default values. - resultState.resetViewStates(); + resetChildViewStates(); - initAlgorithmState(resultState, algorithmState, ambientState); + initAlgorithmState(mHostView, algorithmState, ambientState); - updatePositionsForState(resultState, algorithmState, ambientState); + updatePositionsForState(algorithmState, ambientState); - updateZValuesForState(resultState, algorithmState, ambientState); + updateZValuesForState(algorithmState, ambientState); - updateHeadsUpStates(resultState, algorithmState, ambientState); + updateHeadsUpStates(algorithmState, ambientState); - updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState); - updateClipping(resultState, algorithmState, ambientState); - updateSpeedBumpState(resultState, algorithmState, ambientState); - updateShelfState(resultState, ambientState); - getNotificationChildrenStates(resultState, algorithmState, ambientState); + updateDimmedActivatedHideSensitive(ambientState, algorithmState); + updateClipping(algorithmState, ambientState); + updateSpeedBumpState(algorithmState, ambientState); + updateShelfState(ambientState); + getNotificationChildrenStates(algorithmState, ambientState); } - private void getNotificationChildrenStates(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, + private void resetChildViewStates() { + int numChildren = mHostView.getChildCount(); + for (int i = 0; i < numChildren; i++) { + ExpandableView child = (ExpandableView) mHostView.getChildAt(i); + child.resetViewState(); + } + } + + private void getNotificationChildrenStates(StackScrollAlgorithmState algorithmState, AmbientState ambientState) { int childCount = algorithmState.visibleChildren.size(); for (int i = 0; i < childCount; i++) { ExpandableView v = algorithmState.visibleChildren.get(i); if (v instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) v; - row.getChildrenStates(resultState, ambientState); + row.updateChildrenStates(ambientState); } } } - private void updateSpeedBumpState(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState) { + private void updateSpeedBumpState(StackScrollAlgorithmState algorithmState, + AmbientState ambientState) { int childCount = algorithmState.visibleChildren.size(); int belowSpeedBump = ambientState.getSpeedBumpIndex(); for (int i = 0; i < childCount; i++) { - View child = algorithmState.visibleChildren.get(i); - ExpandableViewState childViewState = resultState.getViewStateForView(child); + ExpandableView child = algorithmState.visibleChildren.get(i); + ExpandableViewState childViewState = child.getViewState(); // The speed bump can also be gone, so equality needs to be taken when comparing // indices. @@ -129,15 +141,16 @@ public class StackScrollAlgorithm { } } - private void updateShelfState(StackScrollState resultState, AmbientState ambientState) { + + private void updateShelfState(AmbientState ambientState) { NotificationShelf shelf = ambientState.getShelf(); if (shelf != null) { - shelf.updateState(resultState, ambientState); + shelf.updateState(ambientState); } } - private void updateClipping(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState) { + private void updateClipping(StackScrollAlgorithmState algorithmState, + AmbientState ambientState) { float drawStart = !ambientState.isOnKeyguard() ? ambientState.getTopPadding() + ambientState.getStackTranslation() + ambientState.getExpandAnimationTopChange() : 0; @@ -146,7 +159,7 @@ public class StackScrollAlgorithm { int childCount = algorithmState.visibleChildren.size(); for (int i = 0; i < childCount; i++) { ExpandableView child = algorithmState.visibleChildren.get(i); - ExpandableViewState state = resultState.getViewStateForView(child); + ExpandableViewState state = child.getViewState(); if (!child.mustStayOnScreen() || state.headsUpIsVisible) { previousNotificationEnd = Math.max(drawStart, previousNotificationEnd); previousNotificationStart = Math.max(drawStart, previousNotificationStart); @@ -190,15 +203,15 @@ public class StackScrollAlgorithm { * Updates the dimmed, activated and hiding sensitive states of the children. */ private void updateDimmedActivatedHideSensitive(AmbientState ambientState, - StackScrollState resultState, StackScrollAlgorithmState algorithmState) { + StackScrollAlgorithmState algorithmState) { boolean dimmed = ambientState.isDimmed(); boolean dark = ambientState.isFullyDark(); boolean hideSensitive = ambientState.isHideSensitive(); View activatedChild = ambientState.getActivatedChild(); int childCount = algorithmState.visibleChildren.size(); for (int i = 0; i < childCount; i++) { - View child = algorithmState.visibleChildren.get(i); - ExpandableViewState childViewState = resultState.getViewStateForView(child); + ExpandableView child = algorithmState.visibleChildren.get(i); + ExpandableViewState childViewState = child.getViewState(); childViewState.dimmed = dimmed; childViewState.dark = dark; childViewState.hideSensitive = hideSensitive; @@ -212,7 +225,7 @@ public class StackScrollAlgorithm { /** * Initialize the algorithm state like updating the visible children. */ - private void initAlgorithmState(StackScrollState resultState, StackScrollAlgorithmState state, + private void initAlgorithmState(ViewGroup hostView, StackScrollAlgorithmState state, AmbientState ambientState) { float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */); @@ -224,7 +237,6 @@ public class StackScrollAlgorithm { state.scrollY = (int) (scrollY + bottomOverScroll); //now init the visible children and update paddings - ViewGroup hostView = resultState.getHostView(); int childCount = hostView.getChildCount(); state.visibleChildren.clear(); state.visibleChildren.ensureCapacity(childCount); @@ -249,7 +261,7 @@ public class StackScrollAlgorithm { // we need normal padding now, to be in sync with what the stack calculates lastView = null; } - notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v); + notGoneIndex = updateNotGoneIndex(state, notGoneIndex, v); float increasedPadding = v.getIncreasedPaddingAmount(); if (increasedPadding != 0.0f) { state.paddingMap.put(v, increasedPadding); @@ -282,13 +294,11 @@ public class StackScrollAlgorithm { ExpandableNotificationRow row = (ExpandableNotificationRow) v; // handle the notgoneIndex for the children as well - List children = - row.getNotificationChildren(); + List children = row.getNotificationChildren(); if (row.isSummaryWithChildren() && children != null) { for (ExpandableNotificationRow childRow : children) { if (childRow.getVisibility() != View.GONE) { - ExpandableViewState childState - = resultState.getViewStateForView(childRow); + ExpandableViewState childState = childRow.getViewState(); childState.notGoneIndex = notGoneIndex; notGoneIndex++; } @@ -301,8 +311,8 @@ public class StackScrollAlgorithm { ExpandableNotificationRow expandingNotification = ambientState.getExpandingNotification(); state.indexOfExpandingNotification = expandingNotification != null ? expandingNotification.isChildInGroup() - ? state.visibleChildren.indexOf(expandingNotification.getNotificationParent()) - : state.visibleChildren.indexOf(expandingNotification) + ? state.visibleChildren.indexOf(expandingNotification.getNotificationParent()) + : state.visibleChildren.indexOf(expandingNotification) : -1; } @@ -322,10 +332,9 @@ public class StackScrollAlgorithm { } } - private int updateNotGoneIndex(StackScrollState resultState, - StackScrollAlgorithmState state, int notGoneIndex, + private int updateNotGoneIndex(StackScrollAlgorithmState state, int notGoneIndex, ExpandableView v) { - ExpandableViewState viewState = resultState.getViewStateForView(v); + ExpandableViewState viewState = v.getViewState(); viewState.notGoneIndex = notGoneIndex; state.visibleChildren.add(v); notGoneIndex++; @@ -335,27 +344,27 @@ public class StackScrollAlgorithm { /** * Determine the positions for the views. This is the main part of the algorithm. * - * @param resultState The result state to update if a change to the properties of a child occurs * @param algorithmState The state in which the current pass of the algorithm is currently in - * @param ambientState The current ambient state + * @param ambientState The current ambient state */ - private void updatePositionsForState(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState) { + private void updatePositionsForState(StackScrollAlgorithmState algorithmState, + AmbientState ambientState) { // The y coordinate of the current child. float currentYPosition = -algorithmState.scrollY; int childCount = algorithmState.visibleChildren.size(); for (int i = 0; i < childCount; i++) { - currentYPosition = updateChild(i, resultState, algorithmState, ambientState, - currentYPosition); + currentYPosition = updateChild(i, algorithmState, ambientState, currentYPosition); } } - protected float updateChild(int i, StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState, + protected float updateChild( + int i, + StackScrollAlgorithmState algorithmState, + AmbientState ambientState, float currentYPosition) { ExpandableView child = algorithmState.visibleChildren.get(i); - ExpandableViewState childViewState = resultState.getViewStateForView(child); + ExpandableViewState childViewState = child.getViewState(); childViewState.location = ExpandableViewState.LOCATION_UNKNOWN; int paddingAfterChild = getPaddingAfterChild(algorithmState, child); int childHeight = getMaxAllowedChildHeight(child); @@ -404,8 +413,8 @@ public class StackScrollAlgorithm { return algorithmState.getPaddingAfterChild(child); } - private void updateHeadsUpStates(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState) { + private void updateHeadsUpStates(StackScrollAlgorithmState algorithmState, + AmbientState ambientState) { int childCount = algorithmState.visibleChildren.size(); ExpandableNotificationRow topHeadsUpEntry = null; for (int i = 0; i < childCount; i++) { @@ -417,7 +426,7 @@ public class StackScrollAlgorithm { if (!row.isHeadsUp()) { break; } - ExpandableViewState childState = resultState.getViewStateForView(row); + ExpandableViewState childState = row.getViewState(); if (topHeadsUpEntry == null && row.mustStayOnScreen() && !childState.headsUpIsVisible) { topHeadsUpEntry = row; childState.location = ExpandableViewState.LOCATION_FIRST_HUN; @@ -439,7 +448,8 @@ public class StackScrollAlgorithm { childState.yTranslation = Math.max(childState.yTranslation, mHeadsUpInset); childState.height = Math.max(row.getIntrinsicHeight(), childState.height); childState.hidden = false; - ExpandableViewState topState = resultState.getViewStateForView(topHeadsUpEntry); + ExpandableViewState topState = + topHeadsUpEntry == null ? null : topHeadsUpEntry.getViewState(); if (topState != null && !isTopEntry && (!mIsExpanded || unmodifiedEndLocation < topState.yTranslation + topState.height)) { // Ensure that a headsUp doesn't vertically extend further than the heads-up at @@ -491,9 +501,8 @@ public class StackScrollAlgorithm { * Clamp the height of the child down such that its end is at most on the beginning of * the shelf. * - * @param child * @param childViewState the view state of the child - * @param ambientState the ambient state + * @param ambientState the ambient state */ private void clampPositionToShelf(ExpandableView child, ExpandableViewState childViewState, @@ -521,31 +530,31 @@ public class StackScrollAlgorithm { ExpandableView expandableView = (ExpandableView) child; return expandableView.getIntrinsicHeight(); } - return child == null? mCollapsedSize : child.getHeight(); + return child == null ? mCollapsedSize : child.getHeight(); } /** * Calculate the Z positions for all children based on the number of items in both stacks and * save it in the resultState - * @param resultState The result state to update the zTranslation values + * * @param algorithmState The state in which the current pass of the algorithm is currently in - * @param ambientState The ambient state of the algorithm + * @param ambientState The ambient state of the algorithm */ - private void updateZValuesForState(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState) { + private void updateZValuesForState(StackScrollAlgorithmState algorithmState, + AmbientState ambientState) { int childCount = algorithmState.visibleChildren.size(); float childrenOnTop = 0.0f; for (int i = childCount - 1; i >= 0; i--) { childrenOnTop = updateChildZValue(i, childrenOnTop, - resultState, algorithmState, ambientState); + algorithmState, ambientState); } } protected float updateChildZValue(int i, float childrenOnTop, - StackScrollState resultState, StackScrollAlgorithmState algorithmState, + StackScrollAlgorithmState algorithmState, AmbientState ambientState) { ExpandableView child = algorithmState.visibleChildren.get(i); - ExpandableViewState childViewState = resultState.getViewStateForView(child); + ExpandableViewState childViewState = child.getViewState(); int zDistanceBetweenElements = ambientState.getZDistanceBetweenElements(); float baseZ = ambientState.getBaseZHeight(); if (child.mustStayOnScreen() && !childViewState.headsUpIsVisible diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollState.java deleted file mode 100644 index e55707ce10d90..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollState.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.notification.stack; - -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; - -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.ExpandableView; - -import java.util.List; -import java.util.WeakHashMap; - -/** - * A state of a - * {@link com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout} which - * can be applied to a viewGroup. - */ -public class StackScrollState { - - private static final String CHILD_NOT_FOUND_TAG = "StackScrollStateNoSuchChild"; - - private final ViewGroup mHostView; - private WeakHashMap mStateMap; - - public StackScrollState(ViewGroup hostView) { - mHostView = hostView; - mStateMap = new WeakHashMap<>(); - } - - public ViewGroup getHostView() { - return mHostView; - } - - public void resetViewStates() { - int numChildren = mHostView.getChildCount(); - for (int i = 0; i < numChildren; i++) { - ExpandableView child = (ExpandableView) mHostView.getChildAt(i); - resetViewState(child); - - // handling reset for child notifications - if (child instanceof ExpandableNotificationRow) { - ExpandableNotificationRow row = (ExpandableNotificationRow) child; - List children = - row.getNotificationChildren(); - if (row.isSummaryWithChildren() && children != null) { - for (ExpandableNotificationRow childRow : children) { - resetViewState(childRow); - } - } - } - } - } - - private void resetViewState(ExpandableView view) { - ExpandableViewState viewState = mStateMap.get(view); - if (viewState == null) { - viewState = view.createNewViewState(this); - mStateMap.put(view, viewState); - } - // initialize with the default values of the view - viewState.height = view.getIntrinsicHeight(); - viewState.gone = view.getVisibility() == View.GONE; - viewState.alpha = 1f; - viewState.notGoneIndex = -1; - viewState.xTranslation = view.getTranslationX(); - viewState.hidden = false; - viewState.scaleX = view.getScaleX(); - viewState.scaleY = view.getScaleY(); - viewState.inShelf = false; - viewState.headsUpIsVisible = false; - } - - public ExpandableViewState getViewStateForView(View requestedView) { - return mStateMap.get(requestedView); - } - - public void removeViewStateForView(View child) { - mStateMap.remove(child); - } - - /** - * Apply the properties saved in {@link #mStateMap} to the children of the {@link #mHostView}. - * The properties are only applied if they effectively changed. - */ - public void apply() { - int numChildren = mHostView.getChildCount(); - for (int i = 0; i < numChildren; i++) { - ExpandableView child = (ExpandableView) mHostView.getChildAt(i); - ExpandableViewState state = mStateMap.get(child); - if (state == null) { - Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " + - "to the hostView"); - continue; - } - if (state.gone) { - continue; - } - state.applyToView(child); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java index 34dab53d4869a..713bd90b30c38 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java @@ -128,25 +128,25 @@ public class StackStateAnimator { public void startAnimationForEvents( ArrayList mAnimationEvents, - StackScrollState finalState, long additionalDelay) { + long additionalDelay) { - processAnimationEvents(mAnimationEvents, finalState); + processAnimationEvents(mAnimationEvents); int childCount = mHostLayout.getChildCount(); mAnimationFilter.applyCombination(mNewEvents); mCurrentAdditionalDelay = additionalDelay; mCurrentLength = NotificationStackScrollLayout.AnimationEvent.combineLength(mNewEvents); - mCurrentLastNotAddedIndex = findLastNotAddedIndex(finalState); + mCurrentLastNotAddedIndex = findLastNotAddedIndex(); for (int i = 0; i < childCount; i++) { final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i); - ExpandableViewState viewState = finalState.getViewStateForView(child); + ExpandableViewState viewState = child.getViewState(); if (viewState == null || child.getVisibility() == View.GONE - || applyWithoutAnimation(child, viewState, finalState)) { + || applyWithoutAnimation(child, viewState)) { continue; } - initAnimationProperties(finalState, child, viewState); + initAnimationProperties(child, viewState); viewState.animateTo(child, mAnimationProperties); } if (!isRunning()) { @@ -159,7 +159,7 @@ public class StackStateAnimator { mNewAddChildren.clear(); } - private void initAnimationProperties(StackScrollState finalState, ExpandableView child, + private void initAnimationProperties(ExpandableView child, ExpandableViewState viewState) { boolean wasAdded = mAnimationProperties.wasAdded(child); mAnimationProperties.duration = mCurrentLength; @@ -173,7 +173,7 @@ public class StackStateAnimator { || viewState.clipTopAmount != child.getClipTopAmount() || viewState.dark != child.isDark())) { mAnimationProperties.delay = mCurrentAdditionalDelay - + calculateChildAnimationDelay(viewState, finalState); + + calculateChildAnimationDelay(viewState); } } @@ -193,8 +193,7 @@ public class StackStateAnimator { * * @return true if no animation should be performed */ - private boolean applyWithoutAnimation(ExpandableView child, ExpandableViewState viewState, - StackScrollState finalState) { + private boolean applyWithoutAnimation(ExpandableView child, ExpandableViewState viewState) { if (mShadeExpanded) { return false; } @@ -214,12 +213,12 @@ public class StackStateAnimator { return true; } - private int findLastNotAddedIndex(StackScrollState finalState) { + private int findLastNotAddedIndex() { int childCount = mHostLayout.getChildCount(); for (int i = childCount - 1; i >= 0; i--) { final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i); - ExpandableViewState viewState = finalState.getViewStateForView(child); + ExpandableViewState viewState = child.getViewState(); if (viewState == null || child.getVisibility() == View.GONE) { continue; } @@ -230,8 +229,7 @@ public class StackStateAnimator { return -1; } - private long calculateChildAnimationDelay(ExpandableViewState viewState, - StackScrollState finalState) { + private long calculateChildAnimationDelay(ExpandableViewState viewState) { if (mAnimationFilter.hasGoToFullShadeEvent) { return calculateDelayGoToFullShade(viewState); } @@ -244,8 +242,8 @@ public class StackStateAnimator { switch (event.animationType) { case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD: { int ownIndex = viewState.notGoneIndex; - int changingIndex = finalState - .getViewStateForView(event.changingView).notGoneIndex; + int changingIndex = + ((ExpandableView) (event.mChangingView)).getViewState().notGoneIndex; int difference = Math.abs(ownIndex - changingIndex); difference = Math.max(0, Math.min(DELAY_EFFECT_MAX_INDEX_DIFFERENCE, difference - 1)); @@ -258,9 +256,9 @@ public class StackStateAnimator { case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE: { int ownIndex = viewState.notGoneIndex; boolean noNextView = event.viewAfterChangingView == null; - View viewAfterChangingView = noNextView + ExpandableView viewAfterChangingView = noNextView ? mHostLayout.getLastChildNotGone() - : event.viewAfterChangingView; + : (ExpandableView) event.viewAfterChangingView; if (viewAfterChangingView == null) { // This can happen when the last view in the list is removed. // Since the shelf is still around and the only view, the code still goes @@ -268,8 +266,7 @@ public class StackStateAnimator { // have changed. continue; } - int nextIndex = finalState - .getViewStateForView(viewAfterChangingView).notGoneIndex; + int nextIndex = viewAfterChangingView.getViewState().notGoneIndex; if (ownIndex >= nextIndex) { // we only have the view afterwards ownIndex++; @@ -351,20 +348,17 @@ public class StackStateAnimator { /** * Process the animationEvents for a new animation * - * @param animationEvents the animation events for the animation to perform - * @param finalState the final state to animate to + * @param animationEvents the animation events for the animation to perform */ private void processAnimationEvents( - ArrayList animationEvents, - StackScrollState finalState) { + ArrayList animationEvents) { for (NotificationStackScrollLayout.AnimationEvent event : animationEvents) { - final ExpandableView changingView = (ExpandableView) event.changingView; + final ExpandableView changingView = (ExpandableView) event.mChangingView; if (event.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) { // This item is added, initialize it's properties. - ExpandableViewState viewState = finalState - .getViewStateForView(changingView); + ExpandableViewState viewState = changingView.getViewState(); if (viewState == null || viewState.gone) { // The position for this child was never generated, let's continue. continue; @@ -381,8 +375,8 @@ public class StackStateAnimator { // Find the amount to translate up. This is needed in order to understand the // direction of the remove animation (either downwards or upwards) - ExpandableViewState viewState = finalState - .getViewStateForView(event.viewAfterChangingView); + ExpandableViewState viewState = + ((ExpandableView) event.viewAfterChangingView).getViewState(); int actualHeight = changingView.getActualHeight(); // upwards by default float translationDirection = -1.0f; @@ -426,11 +420,11 @@ public class StackStateAnimator { } } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_GROUP_EXPANSION_CHANGED) { - ExpandableNotificationRow row = (ExpandableNotificationRow) event.changingView; - row.prepareExpansionChanged(finalState); + ExpandableNotificationRow row = (ExpandableNotificationRow) event.mChangingView; + row.prepareExpansionChanged(); } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_PULSE_APPEAR) { - ExpandableViewState viewState = finalState.getViewStateForView(changingView); + ExpandableViewState viewState = changingView.getViewState(); if (viewState != null) { mTmpState.copyFrom(viewState); mTmpState.yTranslation += mPulsingAppearingTranslation; @@ -439,7 +433,7 @@ public class StackStateAnimator { } } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_PULSE_DISAPPEAR) { - ExpandableViewState viewState = finalState.getViewStateForView(changingView); + ExpandableViewState viewState = changingView.getViewState(); if (viewState != null) { viewState.alpha = 0; // We want to animate the alpha away before the view starts translating, @@ -454,7 +448,7 @@ public class StackStateAnimator { } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR) { // This item is added, initialize it's properties. - ExpandableViewState viewState = finalState.getViewStateForView(changingView); + ExpandableViewState viewState = changingView.getViewState(); mTmpState.copyFrom(viewState); if (event.headsUpFromBottom) { mTmpState.yTranslation = mHeadsUpAppearHeightBottom; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index f64e84c28218f..72d6cd8eaeea7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -74,7 +74,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { @Mock private ShadeController mShadeController; private NotificationViewHierarchyManager mViewHierarchyManager; - private NotificationTestHelper mHelper = new NotificationTestHelper(mContext);; + private NotificationTestHelper mHelper = new NotificationTestHelper(mContext); @Before public void setUp() { @@ -209,19 +209,19 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { public void setChildTransferInProgress(boolean childTransferInProgress) {} @Override - public void changeViewPosition(View child, int newIndex) { + public void changeViewPosition(ExpandableView child, int newIndex) { mRows.remove(child); mRows.add(newIndex, child); } @Override - public void notifyGroupChildAdded(View row) {} + public void notifyGroupChildAdded(ExpandableView row) {} @Override - public void notifyGroupChildRemoved(View row, ViewGroup childrenContainer) {} + public void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer) {} @Override - public void generateAddAnimation(View child, boolean fromMoreCard) {} + public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) {} @Override public void generateChildOrderChangedEvent() {} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java index a4a111aa58f04..662e016b77ff8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java @@ -26,11 +26,11 @@ import static org.mockito.Mockito.when; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; -import android.view.View; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.ExpandableView; import org.junit.Assert; import org.junit.Before; @@ -45,7 +45,7 @@ import java.util.HashSet; public class NotificationRoundnessManagerTest extends SysuiTestCase { private NotificationRoundnessManager mRoundnessManager = new NotificationRoundnessManager(); - private HashSet mAnimatedChildren = new HashSet<>(); + private HashSet mAnimatedChildren = new HashSet<>(); private Runnable mRoundnessCallback = mock(Runnable.class); private ExpandableNotificationRow mFirst; private ExpandableNotificationRow mSecond;