summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI
diff options
context:
space:
mode:
authorSelim Cinek <cinek@google.com>2015-02-20 15:56:28 +0100
committerSelim Cinek <cinek@google.com>2015-03-12 15:53:40 -0700
commitb036ca4de8e93d83bcdc093fbf8f096dc18a810d (patch)
treeaf042b833704fdae53139513b85cc9087788bffc /packages/SystemUI
parent67cf4a06c7f12389ccf131627bfcdfe8409fa598 (diff)
downloadframeworks_base-b036ca4de8e93d83bcdc093fbf8f096dc18a810d.zip
frameworks_base-b036ca4de8e93d83bcdc093fbf8f096dc18a810d.tar.gz
frameworks_base-b036ca4de8e93d83bcdc093fbf8f096dc18a810d.tar.bz2
Made stack scroller animation and apply logic reusable
Change-Id: I5d513dfc91b2a041ccefaa65074a64d1f211ec4a
Diffstat (limited to 'packages/SystemUI')
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java290
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java185
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java49
7 files changed, 396 insertions, 289 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index b14a70d..3bdc250 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -161,7 +161,7 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
-import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
+import com.android.systemui.statusbar.stack.StackViewState;
import com.android.systemui.volume.VolumeComponent;
import java.io.FileDescriptor;
@@ -444,10 +444,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
private int mLastLoggedStateFingerprint;
- private static final int VISIBLE_LOCATIONS = ViewState.LOCATION_FIRST_CARD
- | ViewState.LOCATION_TOP_STACK_PEEKING
- | ViewState.LOCATION_MAIN_AREA
- | ViewState.LOCATION_BOTTOM_STACK_PEEKING;
+ private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_CARD
+ | StackViewState.LOCATION_TOP_STACK_PEEKING
+ | StackViewState.LOCATION_MAIN_AREA
+ | StackViewState.LOCATION_BOTTOM_STACK_PEEKING;
private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
new OnChildLocationsChangedListener() {
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 6dcbed6..e30ab8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -46,7 +46,6 @@ import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.policy.ScrollAdapter;
-import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
import java.util.ArrayList;
import java.util.HashSet;
@@ -375,15 +374,15 @@ public class NotificationStackScrollLayout extends ViewGroup
* 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
+ * @return one of {@link StackViewState}'s <code>LOCATION_*</code> constants
*/
public int getChildLocation(View child) {
- ViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
+ StackViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
if (childViewState == null) {
- return ViewState.LOCATION_UNKNOWN;
+ return StackViewState.LOCATION_UNKNOWN;
}
if (childViewState.gone) {
- return ViewState.LOCATION_GONE;
+ return StackViewState.LOCATION_GONE;
}
return childViewState.location;
}
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 ddc4251..2c124d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -178,7 +178,7 @@ public class StackScrollAlgorithm {
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
View child = algorithmState.visibleChildren.get(i);
- StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+ StackViewState childViewState = resultState.getViewStateForView(child);
// The speed bump can also be gone, so equality needs to be taken when comparing
// indices.
@@ -194,7 +194,7 @@ public class StackScrollAlgorithm {
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
- StackScrollState.ViewState state = resultState.getViewStateForView(child);
+ 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
@@ -242,8 +242,8 @@ public class StackScrollAlgorithm {
* @param backgroundHeight the desired background height. The shadows of the view will be
* based on this height and the content will be clipped from the top
*/
- private void updateChildClippingAndBackground(StackScrollState.ViewState state,
- float realHeight, float clipHeight, float backgroundHeight) {
+ private void updateChildClippingAndBackground(StackViewState state, float realHeight,
+ float clipHeight, float backgroundHeight) {
if (realHeight > clipHeight) {
// Rather overlap than create a hole.
state.topOverLap = (int) Math.floor((realHeight - clipHeight) / state.scale);
@@ -270,7 +270,7 @@ public class StackScrollAlgorithm {
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
View child = algorithmState.visibleChildren.get(i);
- StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+ StackViewState childViewState = resultState.getViewStateForView(child);
childViewState.dimmed = dimmed;
childViewState.dark = dark;
childViewState.hideSensitive = hideSensitive;
@@ -297,14 +297,14 @@ public class StackScrollAlgorithm {
if (!draggedViews.contains(nextChild)) {
// only if the view is not dragged itself we modify its state to be fully
// visible
- StackScrollState.ViewState viewState = resultState.getViewStateForView(
+ StackViewState viewState = resultState.getViewStateForView(
nextChild);
// The child below the dragged one must be fully visible
viewState.alpha = 1;
}
// Lets set the alpha to the one it currently has, as its currently being dragged
- StackScrollState.ViewState viewState = resultState.getViewStateForView(draggedView);
+ StackViewState viewState = resultState.getViewStateForView(draggedView);
// The dragged child should keep the set alpha
viewState.alpha = draggedView.getAlpha();
}
@@ -320,12 +320,14 @@ public class StackScrollAlgorithm {
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) {
- StackScrollState.ViewState viewState = resultState.getViewStateForView(v);
- viewState.notGoneIndex = state.visibleChildren.size();
+ StackViewState viewState = resultState.getViewStateForView(v);
+ viewState.notGoneIndex = notGoneIndex;
state.visibleChildren.add(v);
+ notGoneIndex++;
}
}
}
@@ -355,8 +357,8 @@ public class StackScrollAlgorithm {
int numberOfElementsCompletelyIn = (int) algorithmState.itemsInTopStack;
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
- StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
- childViewState.location = StackScrollState.ViewState.LOCATION_UNKNOWN;
+ StackViewState childViewState = resultState.getViewStateForView(child);
+ childViewState.location = StackViewState.LOCATION_UNKNOWN;
int childHeight = getMaxAllowedChildHeight(child);
float yPositionInScrollViewAfterElement = yPositionInScrollView
+ childHeight
@@ -413,7 +415,7 @@ public class StackScrollAlgorithm {
} else {
// Case 3:
// We are in the regular scroll area.
- childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
+ childViewState.location = StackViewState.LOCATION_MAIN_AREA;
clampYTranslation(childViewState, childHeight);
}
@@ -427,9 +429,9 @@ public class StackScrollAlgorithm {
bottomPeekStart - mCollapseSecondCardPadding
- childViewState.yTranslation, mCollapsedSize);
}
- childViewState.location = StackScrollState.ViewState.LOCATION_FIRST_CARD;
+ childViewState.location = StackViewState.LOCATION_FIRST_CARD;
}
- if (childViewState.location == StackScrollState.ViewState.LOCATION_UNKNOWN) {
+ if (childViewState.location == StackViewState.LOCATION_UNKNOWN) {
Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
}
currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements;
@@ -445,7 +447,7 @@ public class StackScrollAlgorithm {
* @param childViewState the view state of the child
* @param childHeight the height of this child
*/
- private void clampYTranslation(StackScrollState.ViewState childViewState, int childHeight) {
+ private void clampYTranslation(StackViewState childViewState, int childHeight) {
clampPositionToBottomStackStart(childViewState, childHeight);
clampPositionToTopStackEnd(childViewState, childHeight);
}
@@ -457,7 +459,7 @@ public class StackScrollAlgorithm {
* @param childViewState the view state of the child
* @param childHeight the height of this child
*/
- private void clampPositionToBottomStackStart(StackScrollState.ViewState childViewState,
+ private void clampPositionToBottomStackStart(StackViewState childViewState,
int childHeight) {
childViewState.yTranslation = Math.min(childViewState.yTranslation,
mInnerHeight - mBottomStackPeekSize - mCollapseSecondCardPadding - childHeight);
@@ -470,7 +472,7 @@ public class StackScrollAlgorithm {
* @param childViewState the view state of the child
* @param childHeight the height of this child
*/
- private void clampPositionToTopStackEnd(StackScrollState.ViewState childViewState,
+ private void clampPositionToTopStackEnd(StackViewState childViewState,
int childHeight) {
childViewState.yTranslation = Math.max(childViewState.yTranslation,
mCollapsedSize - childHeight);
@@ -489,7 +491,7 @@ public class StackScrollAlgorithm {
private void updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState,
float transitioningPositionStart, float bottomPeakStart, float currentYPosition,
- StackScrollState.ViewState childViewState, int childHeight) {
+ StackViewState childViewState, int childHeight) {
// This is the transitioning element on top of bottom stack, calculate how far we are in.
algorithmState.partialInBottom = 1.0f - (
@@ -510,11 +512,11 @@ public class StackScrollAlgorithm {
// We want at least to be at the end of the top stack when collapsing
clampPositionToTopStackEnd(childViewState, newHeight);
- childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
+ childViewState.location = StackViewState.LOCATION_MAIN_AREA;
}
private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
- float transitioningPositionStart, StackScrollState.ViewState childViewState,
+ float transitioningPositionStart, StackViewState childViewState,
int childHeight) {
float currentYPosition;
@@ -524,7 +526,7 @@ public class StackScrollAlgorithm {
currentYPosition = transitioningPositionStart
+ mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack)
- mPaddingBetweenElements;
- childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_PEEKING;
+ childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_PEEKING;
} else {
// we are fully inside the stack
if (algorithmState.itemsInBottomStack > MAX_ITEMS_IN_BOTTOM_STACK + 2) {
@@ -533,7 +535,7 @@ public class StackScrollAlgorithm {
> MAX_ITEMS_IN_BOTTOM_STACK + 1) {
childViewState.alpha = 1.0f - algorithmState.partialInBottom;
}
- childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_HIDDEN;
+ childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_HIDDEN;
currentYPosition = mInnerHeight;
}
childViewState.yTranslation = currentYPosition - childHeight;
@@ -542,7 +544,7 @@ public class StackScrollAlgorithm {
private void updateStateForTopStackChild(StackScrollAlgorithmState algorithmState,
int numberOfElementsCompletelyIn, int i, int childHeight,
- StackScrollState.ViewState childViewState, float scrollOffset) {
+ StackViewState childViewState, float scrollOffset) {
// First we calculate the index relative to the current stack window of size at most
@@ -574,7 +576,7 @@ public class StackScrollAlgorithm {
- mTopStackIndentationFunctor.getValue(numItemsBefore);
childViewState.yTranslation = currentChildEndY - childHeight;
}
- childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
+ childViewState.location = StackViewState.LOCATION_TOP_STACK_PEEKING;
} else {
if (paddedIndex == -1) {
childViewState.alpha = 1.0f - algorithmState.partialInTop;
@@ -583,7 +585,7 @@ public class StackScrollAlgorithm {
childViewState.alpha = 0.0f;
}
childViewState.yTranslation = mCollapsedSize - childHeight;
- childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN;
+ childViewState.location = StackViewState.LOCATION_TOP_STACK_HIDDEN;
}
@@ -605,7 +607,7 @@ public class StackScrollAlgorithm {
// find the number of elements in the top stack.
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
- StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+ StackViewState childViewState = resultState.getViewStateForView(child);
int childHeight = getMaxAllowedChildHeight(child);
float yPositionInScrollViewAfterElement = yPositionInScrollView
+ childHeight
@@ -676,7 +678,7 @@ public class StackScrollAlgorithm {
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
View child = algorithmState.visibleChildren.get(i);
- StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+ StackViewState childViewState = resultState.getViewStateForView(child);
if (i < algorithmState.itemsInTopStack) {
float stackIndex = algorithmState.itemsInTopStack - i;
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 0b1ce8f..adfe953 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -39,13 +39,13 @@ public class StackScrollState {
private static final String CHILD_NOT_FOUND_TAG = "StackScrollStateNoSuchChild";
private final ViewGroup mHostView;
- private Map<ExpandableView, ViewState> mStateMap;
+ private Map<ExpandableView, StackViewState> mStateMap;
private final Rect mClipRect = new Rect();
private final int mClearAllTopPadding;
public StackScrollState(ViewGroup hostView) {
mHostView = hostView;
- mStateMap = new HashMap<ExpandableView, ViewState>();
+ mStateMap = new HashMap<ExpandableView, StackViewState>();
mClearAllTopPadding = hostView.getContext().getResources().getDimensionPixelSize(
R.dimen.clear_all_padding_top);
}
@@ -58,20 +58,24 @@ public class StackScrollState {
int numChildren = mHostView.getChildCount();
for (int i = 0; i < numChildren; i++) {
ExpandableView child = (ExpandableView) mHostView.getChildAt(i);
- ViewState viewState = mStateMap.get(child);
- if (viewState == null) {
- viewState = new ViewState();
- mStateMap.put(child, viewState);
- }
- // initialize with the default values of the view
- viewState.height = child.getIntrinsicHeight();
- viewState.gone = child.getVisibility() == View.GONE;
- viewState.alpha = 1;
- viewState.notGoneIndex = -1;
+ resetViewState(child);
}
}
- public ViewState getViewStateForView(View requestedView) {
+ private void resetViewState(ExpandableView view) {
+ StackViewState viewState = mStateMap.get(view);
+ if (viewState == null) {
+ viewState = new StackViewState();
+ mStateMap.put(view, viewState);
+ }
+ // initialize with the default values of the view
+ viewState.height = view.getIntrinsicHeight();
+ viewState.gone = view.getVisibility() == View.GONE;
+ viewState.alpha = 1;
+ viewState.notGoneIndex = -1;
+ }
+
+ public StackViewState getViewStateForView(View requestedView) {
return mStateMap.get(requestedView);
}
@@ -87,102 +91,123 @@ public class StackScrollState {
int numChildren = mHostView.getChildCount();
for (int i = 0; i < numChildren; i++) {
ExpandableView child = (ExpandableView) mHostView.getChildAt(i);
- ViewState 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");
+ StackViewState state = mStateMap.get(child);
+ if (!applyState(child, state)) {
continue;
}
- if (!state.gone) {
- float alpha = child.getAlpha();
- float yTranslation = child.getTranslationY();
- float xTranslation = child.getTranslationX();
- float zTranslation = child.getTranslationZ();
- float scale = child.getScaleX();
- int height = child.getActualHeight();
- float newAlpha = state.alpha;
- float newYTranslation = state.yTranslation;
- float newZTranslation = state.zTranslation;
- float newScale = state.scale;
- int newHeight = state.height;
- boolean becomesInvisible = newAlpha == 0.0f;
- if (alpha != newAlpha && xTranslation == 0) {
- // apply layer type
- boolean becomesFullyVisible = newAlpha == 1.0f;
- boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible;
- int layerType = child.getLayerType();
- int newLayerType = newLayerTypeIsHardware
- ? View.LAYER_TYPE_HARDWARE
- : View.LAYER_TYPE_NONE;
- if (layerType != newLayerType) {
- child.setLayerType(newLayerType, null);
- }
-
- // apply alpha
- child.setAlpha(newAlpha);
- }
-
- // apply visibility
- int oldVisibility = child.getVisibility();
- int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
- if (newVisibility != oldVisibility) {
- child.setVisibility(newVisibility);
- }
-
- // apply yTranslation
- if (yTranslation != newYTranslation) {
- child.setTranslationY(newYTranslation);
- }
-
- // apply zTranslation
- if (zTranslation != newZTranslation) {
- child.setTranslationZ(newZTranslation);
- }
-
- // apply scale
- if (scale != newScale) {
- child.setScaleX(newScale);
- child.setScaleY(newScale);
- }
-
- // apply height
- if (height != newHeight) {
- child.setActualHeight(newHeight, false /* notifyListeners */);
- }
-
- // apply dimming
- child.setDimmed(state.dimmed, false /* animate */);
-
- // apply dark
- child.setDark(state.dark, false /* animate */, 0 /* delay */);
-
- // apply hiding sensitive
- child.setHideSensitive(
- state.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
-
- // apply speed bump state
- child.setBelowSpeedBump(state.belowSpeedBump);
-
- // apply clipping
- float oldClipTopAmount = child.getClipTopAmount();
- if (oldClipTopAmount != state.clipTopAmount) {
- child.setClipTopAmount(state.clipTopAmount);
- }
- updateChildClip(child, newHeight, state.topOverLap);
-
- if(child instanceof SpeedBumpView) {
- performSpeedBumpAnimation(i, (SpeedBumpView) child, state, 0);
- } else if (child instanceof DismissView) {
- DismissView dismissView = (DismissView) child;
- boolean visible = state.topOverLap < mClearAllTopPadding;
- dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
- } else if (child instanceof EmptyShadeView) {
- EmptyShadeView emptyShadeView = (EmptyShadeView) child;
- boolean visible = state.topOverLap <= 0;
- emptyShadeView.performVisibilityAnimation(
- visible && !emptyShadeView.willBeGone());
- }
+ if(child instanceof SpeedBumpView) {
+ performSpeedBumpAnimation(i, (SpeedBumpView) child, state, 0);
+ } else if (child instanceof DismissView) {
+ DismissView dismissView = (DismissView) child;
+ boolean visible = state.topOverLap < mClearAllTopPadding;
+ dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
+ } else if (child instanceof EmptyShadeView) {
+ EmptyShadeView emptyShadeView = (EmptyShadeView) child;
+ boolean visible = state.topOverLap <= 0;
+ emptyShadeView.performVisibilityAnimation(
+ visible && !emptyShadeView.willBeGone());
+ }
+ }
+ }
+
+ /**
+ * Applies a {@link StackViewState} to an {@link ExpandableView}.
+ *
+ * @return whether the state was applied correctly
+ */
+ public boolean applyState(ExpandableView view, StackViewState state) {
+ if (state == null) {
+ Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " +
+ "to the hostView");
+ return false;
+ }
+ if (state.gone) {
+ return false;
+ }
+ applyViewState(view, state);
+
+ int height = view.getActualHeight();
+ int newHeight = state.height;
+
+ // apply height
+ if (height != newHeight) {
+ view.setActualHeight(newHeight, false /* notifyListeners */);
+ }
+
+ // apply dimming
+ view.setDimmed(state.dimmed, false /* animate */);
+
+ // apply dark
+ view.setDark(state.dark, false /* animate */, 0 /* delay */);
+
+ // apply hiding sensitive
+ view.setHideSensitive(
+ state.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
+
+ // apply speed bump state
+ view.setBelowSpeedBump(state.belowSpeedBump);
+
+ // apply clipping
+ float oldClipTopAmount = view.getClipTopAmount();
+ if (oldClipTopAmount != state.clipTopAmount) {
+ view.setClipTopAmount(state.clipTopAmount);
+ }
+ updateChildClip(view, newHeight, state.topOverLap);
+ return true;
+ }
+
+ /**
+ * Applies a {@link ViewState} to a normal view.
+ */
+ public void applyViewState(View view, ViewState state) {
+ float alpha = view.getAlpha();
+ float yTranslation = view.getTranslationY();
+ float xTranslation = view.getTranslationX();
+ float zTranslation = view.getTranslationZ();
+ float scale = view.getScaleX();
+ float newAlpha = state.alpha;
+ float newYTranslation = state.yTranslation;
+ float newZTranslation = state.zTranslation;
+ float newScale = state.scale;
+ boolean becomesInvisible = newAlpha == 0.0f;
+ if (alpha != newAlpha && xTranslation == 0) {
+ // apply layer type
+ boolean becomesFullyVisible = newAlpha == 1.0f;
+ boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible
+ && view.hasOverlappingRendering();
+ int layerType = view.getLayerType();
+ int newLayerType = newLayerTypeIsHardware
+ ? View.LAYER_TYPE_HARDWARE
+ : View.LAYER_TYPE_NONE;
+ if (layerType != newLayerType) {
+ view.setLayerType(newLayerType, null);
}
+
+ // apply alpha
+ view.setAlpha(newAlpha);
+ }
+
+ // apply visibility
+ int oldVisibility = view.getVisibility();
+ int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
+ if (newVisibility != oldVisibility) {
+ view.setVisibility(newVisibility);
+ }
+
+ // apply yTranslation
+ if (yTranslation != newYTranslation) {
+ view.setTranslationY(newYTranslation);
+ }
+
+ // apply zTranslation
+ if (zTranslation != newZTranslation) {
+ view.setTranslationZ(newZTranslation);
+ }
+
+ // apply scale
+ if (scale != newScale) {
+ view.setScaleX(newScale);
+ view.setScaleY(newScale);
}
}
@@ -201,12 +226,12 @@ public class StackScrollState {
child.setClipBounds(mClipRect);
}
- public void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, ViewState state,
+ public void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, StackViewState state,
long delay) {
View nextChild = getNextChildNotGone(i);
if (nextChild != null) {
float lineEnd = state.yTranslation + state.height / 2;
- ViewState nextState = getViewStateForView(nextChild);
+ StackViewState nextState = getViewStateForView(nextChild);
boolean startIsAboveNext = nextState.yTranslation > lineEnd;
speedBump.animateDivider(startIsAboveNext, delay, null /* onFinishedRunnable */);
}
@@ -223,53 +248,4 @@ public class StackScrollState {
return null;
}
- 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;
- /** The view isn't layouted at all. */
- public static final int LOCATION_GONE = 0x40;
-
- float alpha;
- float yTranslation;
- float zTranslation;
- int height;
- boolean gone;
- float scale;
- boolean dimmed;
- boolean dark;
- boolean hideSensitive;
- boolean belowSpeedBump;
-
- /**
- * The amount which the view should be clipped from the top. This is calculated to
- * perceive consistent shadows.
- */
- int clipTopAmount;
-
- /**
- * How much does the child overlap with the previous view on the top? Can be used for
- * a clipping optimization
- */
- int topOverLap;
-
- /**
- * The index of the view, only accounting for views not equal to GONE
- */
- int notGoneIndex;
-
- /**
- * The location this view is currently rendered at.
- *
- * <p>See <code>LOCATION_</code> flags.</p>
- */
- int location;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index b027787..215ed31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -113,13 +113,13 @@ public class StackStateAnimator {
for (int i = 0; i < childCount; i++) {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
- StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
+ StackViewState viewState = finalState.getViewStateForView(child);
if (viewState == null || child.getVisibility() == View.GONE) {
continue;
}
child.setClipBounds(null);
- startAnimations(child, viewState, finalState, i);
+ startStackAnimations(child, viewState, finalState, i, -1 /* fixedDelay */);
}
if (!isRunning()) {
// no child has preformed any animation, lets finish
@@ -134,7 +134,7 @@ public class StackStateAnimator {
for (int i = childCount - 1; i >= 0; i--) {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
- StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
+ StackViewState viewState = finalState.getViewStateForView(child);
if (viewState == null || child.getVisibility() == View.GONE) {
continue;
}
@@ -145,18 +145,29 @@ public class StackStateAnimator {
return -1;
}
+
/**
- * Start an animation to the given viewState
+ * Start an animation to the given {@link StackViewState}.
+ *
+ * @param child the child to start the animation on
+ * @param viewState the {@link StackViewState} of the view to animate to
+ * @param finalState the final state after the animation
+ * @param i the index of the view; only relevant if the view is the speed bump and is
+ * ignored otherwise
+ * @param fixedDelay a fixed delay if desired or -1 if the delay should be calculated
*/
- private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState,
- StackScrollState finalState, int i) {
- int childVisibility = child.getVisibility();
- boolean wasVisible = childVisibility == View.VISIBLE;
+ public void startStackAnimations(final ExpandableView child, StackViewState viewState,
+ StackScrollState finalState, int i, long fixedDelay) {
final float alpha = viewState.alpha;
- if (!wasVisible && alpha != 0 && !viewState.gone) {
- child.setVisibility(View.VISIBLE);
+ boolean wasAdded = mNewAddChildren.contains(child);
+ long duration = mCurrentLength;
+ if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
+ child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation);
+ float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex;
+ longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f);
+ duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 +
+ (long) (100 * longerDurationFactor);
}
-
boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
boolean scaleChanging = child.getScaleX() != viewState.scale;
@@ -164,94 +175,40 @@ public class StackStateAnimator {
boolean heightChanging = viewState.height != child.getActualHeight();
boolean darkChanging = viewState.dark != child.isDark();
boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount();
- boolean wasAdded = mNewAddChildren.contains(child);
boolean hasDelays = mAnimationFilter.hasDelays;
boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || scaleChanging ||
alphaChanging || heightChanging || topInsetChanging || darkChanging;
- boolean noAnimation = wasAdded;
long delay = 0;
- long duration = mCurrentLength;
- if (hasDelays && isDelayRelevant || wasAdded) {
+ if (fixedDelay != -1) {
+ delay = fixedDelay;
+ } else if (hasDelays && isDelayRelevant || wasAdded) {
delay = mCurrentAdditionalDelay + calculateChildAnimationDelay(viewState, finalState);
}
- if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
- child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation);
- yTranslationChanging = true;
- float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex;
- longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f);
- duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 +
- (long) (100 * longerDurationFactor);
- }
-
- // start translationY animation
- if (yTranslationChanging) {
- if (noAnimation && !mAnimationFilter.hasGoToFullShadeEvent) {
- child.setTranslationY(viewState.yTranslation);
- } else {
- startYTranslationAnimation(child, viewState, duration, delay);
- }
- }
-
- // start translationZ animation
- if (zTranslationChanging) {
- if (noAnimation) {
- child.setTranslationZ(viewState.zTranslation);
- } else {
- startZTranslationAnimation(child, viewState, duration, delay);
- }
- }
-
- // start scale animation
- if (scaleChanging) {
- if (noAnimation) {
- child.setScaleX(viewState.scale);
- child.setScaleY(viewState.scale);
- } else {
- startScaleAnimation(child, viewState, duration);
- }
- }
-
- // start alpha animation
- if (alphaChanging && child.getTranslationX() == 0) {
- if (noAnimation) {
- child.setAlpha(viewState.alpha);
- } else {
- startAlphaAnimation(child, viewState, duration, delay);
- }
- }
+ startViewAnimations(child, viewState, delay, duration);
// start height animation
if (heightChanging && child.getActualHeight() != 0) {
- if (noAnimation) {
- child.setActualHeight(viewState.height, false);
- } else {
- startHeightAnimation(child, viewState, duration, delay);
- }
+ startHeightAnimation(child, viewState, duration, delay);
}
// start top inset animation
if (topInsetChanging) {
- if (noAnimation) {
- child.setClipTopAmount(viewState.clipTopAmount);
- } else {
- startInsetAnimation(child, viewState, duration, delay);
- }
+ startInsetAnimation(child, viewState, duration, delay);
}
// start dimmed animation
- child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed && !wasAdded
- && !noAnimation);
+ child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
// start dark animation
- child.setDark(viewState.dark, mAnimationFilter.animateDark && !noAnimation, delay);
+ child.setDark(viewState.dark, mAnimationFilter.animateDark, delay);
// apply speed bump state
child.setBelowSpeedBump(viewState.belowSpeedBump);
// start hiding sensitive animation
- child.setHideSensitive(viewState.hideSensitive, mAnimationFilter.animateHideSensitive &&
- !wasAdded && !noAnimation, delay, duration);
+ child.setHideSensitive(viewState.hideSensitive, mAnimationFilter.animateHideSensitive,
+ delay, duration);
if (wasAdded) {
child.performAddAnimation(delay, mCurrentLength);
@@ -262,7 +219,48 @@ public class StackStateAnimator {
}
}
- private long calculateChildAnimationDelay(StackScrollState.ViewState viewState,
+ /**
+ * Start an animation to a new {@link ViewState}.
+ *
+ * @param child the child to start the animation on
+ * @param viewState the {@link StackViewState} of the view to animate to
+ * @param delay a fixed delay
+ * @param duration the duration of the animation
+ */
+ public void startViewAnimations(View child, ViewState viewState, long delay, long duration) {
+ boolean wasVisible = child.getVisibility() == View.VISIBLE;
+ final float alpha = viewState.alpha;
+ if (!wasVisible && alpha != 0 && !viewState.gone) {
+ child.setVisibility(View.VISIBLE);
+ }
+ boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
+ boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
+ boolean scaleChanging = child.getScaleX() != viewState.scale;
+ float childAlpha = child.getVisibility() == View.INVISIBLE ? 0.0f : child.getAlpha();
+ boolean alphaChanging = viewState.alpha != childAlpha;
+
+ // start translationY animation
+ if (yTranslationChanging) {
+ startYTranslationAnimation(child, viewState, duration, delay);
+ }
+
+ // start translationZ animation
+ if (zTranslationChanging) {
+ startZTranslationAnimation(child, viewState, duration, delay);
+ }
+
+ // start scale animation
+ if (scaleChanging) {
+ startScaleAnimation(child, viewState, duration);
+ }
+
+ // start alpha animation
+ if (alphaChanging && child.getTranslationX() == 0) {
+ startAlphaAnimation(child, viewState, duration, delay);
+ }
+ }
+
+ private long calculateChildAnimationDelay(StackViewState viewState,
StackScrollState finalState) {
if (mAnimationFilter.hasDarkEvent) {
return calculateDelayDark(viewState);
@@ -314,7 +312,7 @@ public class StackStateAnimator {
return minDelay;
}
- private long calculateDelayDark(StackScrollState.ViewState viewState) {
+ private long calculateDelayDark(StackViewState viewState) {
int referenceIndex;
if (mAnimationFilter.darkAnimationOriginIndex ==
NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE) {
@@ -328,14 +326,14 @@ public class StackStateAnimator {
return Math.abs(referenceIndex - viewState.notGoneIndex) * ANIMATION_DELAY_PER_ELEMENT_DARK;
}
- private long calculateDelayGoToFullShade(StackScrollState.ViewState viewState) {
+ private long calculateDelayGoToFullShade(StackViewState viewState) {
float index = viewState.notGoneIndex;
index = (float) Math.pow(index, 0.7f);
return (long) (index * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE);
}
private void startHeightAnimation(final ExpandableView child,
- StackScrollState.ViewState viewState, long duration, long delay) {
+ StackViewState viewState, long duration, long delay) {
Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
int newEndValue = viewState.height;
@@ -394,7 +392,7 @@ public class StackStateAnimator {
}
private void startInsetAnimation(final ExpandableView child,
- StackScrollState.ViewState viewState, long duration, long delay) {
+ StackViewState viewState, long duration, long delay) {
Integer previousStartValue = getChildTag(child, TAG_START_TOP_INSET);
Integer previousEndValue = getChildTag(child, TAG_END_TOP_INSET);
int newEndValue = viewState.clipTopAmount;
@@ -451,8 +449,8 @@ public class StackStateAnimator {
child.setTag(TAG_END_TOP_INSET, newEndValue);
}
- private void startAlphaAnimation(final ExpandableView child,
- final StackScrollState.ViewState viewState, long duration, long delay) {
+ private void startAlphaAnimation(final View child,
+ final ViewState viewState, long duration, long delay) {
Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
final float newEndValue = viewState.alpha;
@@ -525,8 +523,8 @@ public class StackStateAnimator {
child.setTag(TAG_END_ALPHA, newEndValue);
}
- private void startZTranslationAnimation(final ExpandableView child,
- final StackScrollState.ViewState viewState, long duration, long delay) {
+ private void startZTranslationAnimation(final View child,
+ final ViewState viewState, long duration, long delay) {
Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
float newEndValue = viewState.zTranslation;
@@ -577,8 +575,8 @@ public class StackStateAnimator {
child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
}
- private void startYTranslationAnimation(final ExpandableView child,
- StackScrollState.ViewState viewState, long duration, long delay) {
+ private void startYTranslationAnimation(final View child,
+ ViewState viewState, long duration, long delay) {
Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
float newEndValue = viewState.yTranslation;
@@ -630,8 +628,8 @@ public class StackStateAnimator {
child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
}
- private void startScaleAnimation(final ExpandableView child,
- StackScrollState.ViewState viewState, long duration) {
+ private void startScaleAnimation(final View child,
+ ViewState viewState, long duration) {
Float previousStartValue = getChildTag(child, TAG_START_SCALE);
Float previousEndValue = getChildTag(child, TAG_END_SCALE);
float newEndValue = viewState.scale;
@@ -765,7 +763,7 @@ public class StackStateAnimator {
NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) {
// This item is added, initialize it's properties.
- StackScrollState.ViewState viewState = finalState
+ StackViewState viewState = finalState
.getViewStateForView(changingView);
if (viewState == null) {
// The position for this child was never generated, let's continue.
@@ -776,10 +774,7 @@ public class StackStateAnimator {
finalState.removeViewStateForView(changingView);
continue;
}
- changingView.setAlpha(viewState.alpha);
- changingView.setTranslationY(viewState.yTranslation);
- changingView.setTranslationZ(viewState.zTranslation);
- changingView.setActualHeight(viewState.height, false);
+ finalState.applyState(changingView, viewState);
mNewAddChildren.add(changingView);
} else if (event.animationType ==
@@ -791,7 +786,7 @@ 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)
- StackScrollState.ViewState viewState = finalState
+ StackViewState viewState = finalState
.getViewStateForView(event.viewAfterChangingView);
int actualHeight = changingView.getActualHeight();
// upwards by default
@@ -813,7 +808,7 @@ public class StackStateAnimator {
mHostLayout.getOverlay().remove(changingView);
}
});
- } else if (event.animationType ==
+ } else if (event.animationType ==
NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT) {
// A race condition can trigger the view to be added to the overlay even though
// it is swiped out. So let's remove it
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
new file mode 100644
index 0000000..55ef440
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 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.stack;
+
+import android.view.View;
+
+import com.android.systemui.statusbar.ExpandableView;
+
+/**
+* A state of an expandable view
+*/
+public class StackViewState extends 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;
+ /** The view isn't layouted at all. */
+ public static final int LOCATION_GONE = 0x40;
+
+ public int height;
+ public boolean dimmed;
+ public boolean dark;
+ public boolean hideSensitive;
+ public boolean belowSpeedBump;
+
+ /**
+ * The amount which the view should be clipped from the top. This is calculated to
+ * perceive consistent shadows.
+ */
+ public int clipTopAmount;
+
+ /**
+ * How much does the child overlap with the previous view on the top? Can be used for
+ * a clipping optimization
+ */
+ public int topOverLap;
+
+ /**
+ * The index of the view, only accounting for views not equal to GONE
+ */
+ public int notGoneIndex;
+
+ /**
+ * The location this view is currently rendered at.
+ *
+ * <p>See <code>LOCATION_</code> flags.</p>
+ */
+ public int location;
+
+ @Override
+ public void copyFrom(ViewState viewState) {
+ super.copyFrom(viewState);
+ if (viewState instanceof StackViewState) {
+ StackViewState svs = (StackViewState) viewState;
+ height = svs.height;
+ dimmed = svs.dimmed;
+ dark = svs.dark;
+ hideSensitive = svs.hideSensitive;
+ belowSpeedBump = svs.belowSpeedBump;
+ clipTopAmount = svs.clipTopAmount;
+ topOverLap = svs.topOverLap;
+ notGoneIndex = svs.notGoneIndex;
+ location = svs.location;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
new file mode 100644
index 0000000..3e538df
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 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.stack;
+
+import android.view.View;
+
+/**
+ * A state of a view. This can be used to apply a set of view properties to a view with
+ * {@link com.android.systemui.statusbar.stack.StackScrollState} or start animations with
+ * {@link com.android.systemui.statusbar.stack.StackStateAnimator}.
+*/
+public class ViewState {
+
+ public float alpha;
+ public float yTranslation;
+ public float zTranslation;
+ public boolean gone;
+ public float scale;
+
+ public void copyFrom(ViewState viewState) {
+ alpha = viewState.alpha;
+ yTranslation = viewState.yTranslation;
+ zTranslation = viewState.zTranslation;
+ gone = viewState.gone;
+ scale = viewState.scale;
+ }
+
+ public void initFrom(View view) {
+ alpha = view.getVisibility() == View.INVISIBLE ? 0.0f : view.getAlpha();
+ yTranslation = view.getTranslationY();
+ zTranslation = view.getTranslationZ();
+ gone = view.getVisibility() == View.GONE;
+ scale = view.getScaleX();
+ }
+}