summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java287
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java675
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java320
10 files changed, 773 insertions, 637 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 0616db594cdb..903a9dc389f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -37,6 +37,7 @@ import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index bba411c3f99a..f7fb0796ae9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -51,11 +51,11 @@ import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.stack.AnimationProperties;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackScrollState;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
-import com.android.systemui.statusbar.stack.ExpandableViewState;
import java.util.ArrayList;
import java.util.List;
@@ -485,11 +485,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
- public void startChildAnimation(StackScrollState finalState,
- StackStateAnimator stateAnimator, long delay, long duration) {
+ public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
if (mIsSummaryWithChildren) {
- mChildrenContainer.startAnimationToState(finalState, stateAnimator, delay,
- duration);
+ mChildrenContainer.startAnimationToState(finalState, properties);
}
}
@@ -1762,7 +1760,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return new NotificationViewState(stackScrollState);
}
- public static class NotificationViewState extends ExpandableViewState {
+ public class NotificationViewState extends ExpandableViewState {
private final StackScrollState mOverallState;
@@ -1782,5 +1780,22 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
row.applyChildrenState(mOverallState);
}
}
+
+ @Override
+ protected void onYTranslationAnimationFinished() {
+ super.onYTranslationAnimationFinished();
+ if (mHeadsupDisappearRunning) {
+ setHeadsupDisappearRunning(false);
+ }
+ }
+
+ @Override
+ public void animateTo(View child, AnimationProperties properties) {
+ super.animateTo(child, properties);
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ row.startChildAnimation(mOverallState, properties);
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 8a6ce56913b3..f094f529f4ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -30,6 +30,7 @@ import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.stack.AmbientState;
+import com.android.systemui.statusbar.stack.AnimationProperties;
import com.android.systemui.statusbar.stack.ExpandableViewState;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackScrollAlgorithm;
@@ -300,5 +301,12 @@ public class NotificationShelf extends ActivatableNotificationView {
updateAppearance();
setIconContainerTranslation(iconContainerTranslation);
}
+
+ @Override
+ public void animateTo(View child, AnimationProperties properties) {
+ super.animateTo(child, properties);
+ updateAppearance();
+ setIconContainerTranslation(iconContainerTranslation);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index a4b76ebb53dd..249022e4dd4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -21,7 +21,6 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.Color;
import android.graphics.Rect;
import android.support.v4.graphics.ColorUtils;
import android.view.View;
@@ -37,7 +36,7 @@ import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
+import com.android.systemui.statusbar.stack.ViewState;
/**
* Controls both the scrim behind the notifications and in front of the notifications (when a
@@ -478,14 +477,14 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
return;
}
- ValueAnimator previousAnimator = StackStateAnimator.getChildTag(scrim,
+ ValueAnimator previousAnimator = ViewState.getChildTag(scrim,
TAG_KEY_ANIM);
float animEndValue = -1;
if (previousAnimator != null) {
if (animate || alpha == currentAlpha) {
previousAnimator.cancel();
} else {
- animEndValue = StackStateAnimator.getChildTag(scrim, TAG_END_ALPHA);
+ animEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA);
}
}
if (alpha != currentAlpha && alpha != animEndValue) {
@@ -495,10 +494,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
scrim.setTag(TAG_END_ALPHA, alpha);
} else {
if (previousAnimator != null) {
- float previousStartValue = StackStateAnimator.getChildTag(scrim,
- TAG_START_ALPHA);
- float previousEndValue = StackStateAnimator.getChildTag(scrim,
- TAG_END_ALPHA);
+ float previousStartValue = ViewState.getChildTag(scrim, TAG_START_ALPHA);
+ float previousEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA);
// we need to increase all animation keyframes of the previous animator by the
// relative change to the end value
PropertyValuesHolder[] values = previousAnimator.getValues();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java
new file mode 100644
index 000000000000..3cb6e5b1ca2f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 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.animation.AnimatorListenerAdapter;
+import android.util.Property;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+/**
+ * Properties for a View animation
+ */
+public class AnimationProperties {
+ public long duration;
+ public long delay;
+
+ /**
+ * @return an animation filter for this animation.
+ */
+ public AnimationFilter getAnimationFilter() {
+ return null;
+ }
+
+ /**
+ * @return a listener that should be run whenever any property finished its animation
+ */
+ public AnimatorListenerAdapter getAnimationFinishListener() {
+ return null;
+ }
+
+ public boolean wasAdded(View view) {
+ return false;
+ }
+
+ /**
+ * Get a custom interpolator for a property instead of the normal one.
+ */
+ public Interpolator getCustomInterpolator(View child, Property translationY) {
+ return null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
index c78def4c89d8..0472db092e40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
@@ -16,8 +16,15 @@
package com.android.systemui.statusbar.stack;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
import android.view.View;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
/**
@@ -25,6 +32,16 @@ import com.android.systemui.statusbar.ExpandableView;
*/
public class ExpandableViewState extends ViewState {
+ private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
+ private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
+ private static final int TAG_ANIMATOR_SHADOW_ALPHA = R.id.shadow_alpha_animator_tag;
+ private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
+ private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
+ private static final int TAG_END_SHADOW_ALPHA = R.id.shadow_alpha_animator_end_value_tag;
+ private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag;
+ private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
+ private static final int TAG_START_SHADOW_ALPHA = R.id.shadow_alpha_animator_start_value_tag;
+
// These are flags such that we can create masks for filtering.
/**
@@ -156,4 +173,274 @@ public class ExpandableViewState extends ViewState {
}
}
}
+
+ @Override
+ public void animateTo(View child, AnimationProperties properties) {
+ super.animateTo(child, properties);
+ if (!(child instanceof ExpandableView)) {
+ return;
+ }
+ ExpandableView expandableView = (ExpandableView) child;
+ AnimationFilter animationFilter = properties.getAnimationFilter();
+
+ // start height animation
+ if (this.height != expandableView.getActualHeight()) {
+ startHeightAnimation(expandableView, properties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_HEIGHT);
+ }
+
+ // start shadow alpha animation
+ if (this.shadowAlpha != expandableView.getShadowAlpha()) {
+ startShadowAlphaAnimation(expandableView, properties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_SHADOW_ALPHA);
+ }
+
+ // start top inset animation
+ if (this.clipTopAmount != expandableView.getClipTopAmount()) {
+ startInsetAnimation(expandableView, properties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_TOP_INSET);
+ }
+
+ // start dimmed animation
+ expandableView.setDimmed(this.dimmed, animationFilter.animateDimmed);
+
+ // apply below shelf state
+ expandableView.setBelowShelf(this.belowShelf);
+
+ // start hiding sensitive animation
+ expandableView.setHideSensitive(this.hideSensitive, animationFilter.animateHideSensitive,
+ properties.delay, properties.duration);
+
+ // start dark animation
+ expandableView.setDark(this.dark, animationFilter.animateDark, properties.delay);
+
+ if (properties.wasAdded(child)) {
+ expandableView.performAddAnimation(properties.delay, properties.duration);
+ }
+ }
+
+ private void startHeightAnimation(final ExpandableView child, AnimationProperties properties) {
+ Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
+ Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
+ int newEndValue = this.height;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateHeight) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ int relativeDiff = newEndValue - previousEndValue;
+ int newStartValue = previousStartValue + relativeDiff;
+ values[0].setIntValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_HEIGHT, newStartValue);
+ child.setTag(TAG_END_HEIGHT, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setActualHeight(newEndValue, false);
+ return;
+ }
+ }
+
+ ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ child.setActualHeight((int) animation.getAnimatedValue(),
+ false /* notifyListeners */);
+ }
+ });
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ boolean mWasCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_HEIGHT, null);
+ child.setTag(TAG_START_HEIGHT, null);
+ child.setTag(TAG_END_HEIGHT, null);
+ child.setActualHeightAnimating(false);
+ if (!mWasCancelled && child instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) child).setGroupExpansionChanging(
+ false /* isExpansionChanging */);
+ }
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mWasCancelled = false;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+ });
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_HEIGHT, animator);
+ child.setTag(TAG_START_HEIGHT, child.getActualHeight());
+ child.setTag(TAG_END_HEIGHT, newEndValue);
+ child.setActualHeightAnimating(true);
+ }
+
+ private void startShadowAlphaAnimation(final ExpandableView child,
+ AnimationProperties properties) {
+ Float previousStartValue = getChildTag(child, TAG_START_SHADOW_ALPHA);
+ Float previousEndValue = getChildTag(child, TAG_END_SHADOW_ALPHA);
+ float newEndValue = this.shadowAlpha;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SHADOW_ALPHA);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateShadowAlpha) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_SHADOW_ALPHA, newStartValue);
+ child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setShadowAlpha(newEndValue);
+ return;
+ }
+ }
+
+ ValueAnimator animator = ValueAnimator.ofFloat(child.getShadowAlpha(), newEndValue);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ child.setShadowAlpha((float) animation.getAnimatedValue());
+ }
+ });
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, null);
+ child.setTag(TAG_START_SHADOW_ALPHA, null);
+ child.setTag(TAG_END_SHADOW_ALPHA, null);
+ }
+ });
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, animator);
+ child.setTag(TAG_START_SHADOW_ALPHA, child.getShadowAlpha());
+ child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
+ }
+
+ private void startInsetAnimation(final ExpandableView child, AnimationProperties properties) {
+ Integer previousStartValue = getChildTag(child, TAG_START_TOP_INSET);
+ Integer previousEndValue = getChildTag(child, TAG_END_TOP_INSET);
+ int newEndValue = this.clipTopAmount;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TOP_INSET);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateTopInset) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ int relativeDiff = newEndValue - previousEndValue;
+ int newStartValue = previousStartValue + relativeDiff;
+ values[0].setIntValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_TOP_INSET, newStartValue);
+ child.setTag(TAG_END_TOP_INSET, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setClipTopAmount(newEndValue);
+ return;
+ }
+ }
+
+ ValueAnimator animator = ValueAnimator.ofInt(child.getClipTopAmount(), newEndValue);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ child.setClipTopAmount((int) animation.getAnimatedValue());
+ }
+ });
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_TOP_INSET, null);
+ child.setTag(TAG_START_TOP_INSET, null);
+ child.setTag(TAG_END_TOP_INSET, null);
+ }
+ });
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_TOP_INSET, animator);
+ child.setTag(TAG_START_TOP_INSET, child.getClipTopAmount());
+ child.setTag(TAG_END_TOP_INSET, newEndValue);
+ }
+
+ /**
+ * Get the end value of the height animation running on a view or the actualHeight
+ * if no animation is running.
+ */
+ public static int getFinalActualHeight(ExpandableView view) {
+ if (view == null) {
+ return 0;
+ }
+ ValueAnimator heightAnimator = getChildTag(view, TAG_ANIMATOR_HEIGHT);
+ if (heightAnimator == null) {
+ return view.getActualHeight();
+ } else {
+ return getChildTag(view, TAG_END_HEIGHT);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index dfbc31f4f9eb..33b9d38bc6bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -594,11 +594,11 @@ public class NotificationChildrenContainer extends ViewGroup {
// There is no fake shadow to be drawn on the children
child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
}
- if (mOverflowNumber != null) {
+ if (mGroupOverFlowState != null) {
mGroupOverFlowState.applyToView(mOverflowNumber);
mNeverAppliedGroupState = false;
}
- if (mNotificationHeader != null) {
+ if (mHeaderViewState != null) {
mHeaderViewState.applyToView(mNotificationHeader);
}
}
@@ -614,8 +614,7 @@ public class NotificationChildrenContainer extends ViewGroup {
return;
}
- public void startAnimationToState(StackScrollState state, StackStateAnimator stateAnimator,
- long baseDelay, long duration) {
+ public void startAnimationToState(StackScrollState state, AnimationProperties properties) {
int childCount = mChildren.size();
ViewState tmpState = new ViewState();
float expandFraction = getGroupExpandFraction();
@@ -624,7 +623,7 @@ public class NotificationChildrenContainer extends ViewGroup {
for (int i = childCount - 1; i >= 0; i--) {
ExpandableNotificationRow child = mChildren.get(i);
ExpandableViewState viewState = state.getViewStateForView(child);
- stateAnimator.startStackAnimations(child, viewState, state, -1, baseDelay);
+ viewState.animateTo(child, properties);
// layout the divider
View divider = mDividers.get(i);
@@ -637,7 +636,7 @@ public class NotificationChildrenContainer extends ViewGroup {
}
tmpState.hidden = !dividersVisible;
tmpState.alpha = alpha;
- stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration);
+ tmpState.animateTo(divider, properties);
// There is no fake shadow to be drawn on the children
child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
}
@@ -649,8 +648,7 @@ public class NotificationChildrenContainer extends ViewGroup {
mGroupOverFlowState.alpha = alpha;
mNeverAppliedGroupState = false;
}
- stateAnimator.startViewAnimations(mOverflowNumber, mGroupOverFlowState,
- baseDelay, duration);
+ mGroupOverFlowState.animateTo(mOverflowNumber, properties);
}
if (mNotificationHeader != null) {
mHeaderViewState.applyToView(mNotificationHeader);
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 d35e4a5d6b47..89c1d6e5071a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -69,9 +69,9 @@ import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationGuts;
-import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationSettingsIconRow;
import com.android.systemui.statusbar.NotificationSettingsIconRow.SettingsIconRowListener;
+import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.FakeShadowView;
@@ -2095,7 +2095,7 @@ public class NotificationStackScrollLayout extends ViewGroup
ActivatableNotificationView firstView = mFirstVisibleBackgroundChild;
int top = 0;
if (firstView != null) {
- int finalTranslationY = (int) StackStateAnimator.getFinalTranslationY(firstView);
+ int finalTranslationY = (int) ViewState.getFinalTranslationY(firstView);
if (mAnimateNextBackgroundTop
|| mTopAnimator == null && mCurrentBounds.top == finalTranslationY
|| mTopAnimator != null && mEndAnimationRect.top == finalTranslationY) {
@@ -2108,8 +2108,8 @@ public class NotificationStackScrollLayout extends ViewGroup
ActivatableNotificationView lastView = mLastVisibleBackgroundChild;
int bottom = 0;
if (lastView != null) {
- int finalTranslationY = (int) StackStateAnimator.getFinalTranslationY(lastView);
- int finalHeight = StackStateAnimator.getFinalActualHeight(lastView);
+ int finalTranslationY = (int) ViewState.getFinalTranslationY(lastView);
+ int finalHeight = ExpandableViewState.getFinalActualHeight(lastView);
int finalBottom = finalTranslationY + finalHeight;
finalBottom = Math.min(finalBottom, getHeight());
if (mAnimateNextBackgroundBottom
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 3ba7774dfd88..5cf0a27fcb90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -18,9 +18,8 @@ package com.android.systemui.statusbar.stack;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
+import android.util.Property;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
@@ -29,7 +28,6 @@ import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
import java.util.HashSet;
@@ -54,28 +52,10 @@ public class StackStateAnimator {
public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
public static final int ANIMATION_DELAY_HEADS_UP = 120;
- private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
- private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
- private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
- private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
- private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
- private static final int TAG_ANIMATOR_SHADOW_ALPHA = R.id.shadow_alpha_animator_tag;
- private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
- private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
- private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
- private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
- private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
- private static final int TAG_END_SHADOW_ALPHA = R.id.shadow_alpha_animator_end_value_tag;
- private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
- private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
- private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
- private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag;
- private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
- private static final int TAG_START_SHADOW_ALPHA = R.id.shadow_alpha_animator_start_value_tag;
-
private final Interpolator mHeadsUpAppearInterpolator;
private final int mGoToFullShadeAppearingTranslation;
private final ExpandableViewState mTmpState = new ExpandableViewState();
+ private final AnimationProperties mAnimationProperties;
public NotificationStackScrollLayout mHostLayout;
private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
new ArrayList<>();
@@ -102,6 +82,30 @@ public class StackStateAnimator {
hostLayout.getContext().getResources().getDimensionPixelSize(
R.dimen.go_to_full_shade_appearing_translation);
mHeadsUpAppearInterpolator = new HeadsUpAppearInterpolator();
+ mAnimationProperties = new AnimationProperties() {
+ @Override
+ public AnimationFilter getAnimationFilter() {
+ return mAnimationFilter;
+ }
+
+ @Override
+ public AnimatorListenerAdapter getAnimationFinishListener() {
+ return getGlobalAnimationFinishedListener();
+ }
+
+ @Override
+ public boolean wasAdded(View view) {
+ return mNewAddChildren.contains(view);
+ }
+
+ @Override
+ public Interpolator getCustomInterpolator(View child, Property property) {
+ if (mHeadsUpAppearChildren.contains(child) && View.TRANSLATION_Y.equals(property)) {
+ return mHeadsUpAppearInterpolator;
+ }
+ return null;
+ }
+ };
}
public boolean isRunning() {
@@ -128,7 +132,8 @@ public class StackStateAnimator {
continue;
}
- startStackAnimations(child, viewState, finalState, i, -1 /* fixedDelay */);
+ initAnimationProperties(finalState, child, viewState);
+ viewState.animateTo(child, mAnimationProperties);
}
if (!isRunning()) {
// no child has preformed any animation, lets finish
@@ -140,6 +145,36 @@ public class StackStateAnimator {
mNewAddChildren.clear();
}
+ private void initAnimationProperties(StackScrollState finalState, ExpandableView child,
+ ExpandableViewState viewState) {
+ boolean wasAdded = mAnimationProperties.wasAdded(child);
+ mAnimationProperties.duration = mCurrentLength;
+ adaptDurationWhenGoingToFullShade(child, viewState, wasAdded);
+ mAnimationProperties.delay = 0;
+ if (wasAdded || mAnimationFilter.hasDelays
+ && (viewState.yTranslation != child.getTranslationY()
+ || viewState.zTranslation != child.getTranslationZ()
+ || viewState.alpha != child.getAlpha()
+ || viewState.height != child.getActualHeight()
+ || viewState.clipTopAmount != child.getClipTopAmount()
+ || viewState.dark != child.isDark()
+ || viewState.shadowAlpha != child.getShadowAlpha())) {
+ mAnimationProperties.delay = mCurrentAdditionalDelay
+ + calculateChildAnimationDelay(viewState, finalState);
+ }
+ }
+
+ private void adaptDurationWhenGoingToFullShade(ExpandableView child,
+ ExpandableViewState viewState, boolean wasAdded) {
+ if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
+ child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation);
+ float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex;
+ longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f);
+ mAnimationProperties.duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 +
+ (long) (100 * longerDurationFactor);
+ }
+ }
+
/**
* Determines if a view should not perform an animation and applies it directly.
*
@@ -150,7 +185,7 @@ public class StackStateAnimator {
if (mShadeExpanded) {
return false;
}
- if (getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y) != null) {
+ if (ViewState.isAnimatingY(child)) {
// A Y translation animation is running
return false;
}
@@ -182,143 +217,6 @@ public class StackStateAnimator {
return -1;
}
-
- /**
- * Start an animation to the given {@link ExpandableViewState}.
- *
- * @param child the child to start the animation on
- * @param viewState the {@link ExpandableViewState} 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
- */
- public void startStackAnimations(final ExpandableView child, ExpandableViewState viewState,
- StackScrollState finalState, int i, long fixedDelay) {
- 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 alphaChanging = viewState.alpha != child.getAlpha();
- boolean heightChanging = viewState.height != child.getActualHeight();
- boolean shadowAlphaChanging = viewState.shadowAlpha != child.getShadowAlpha();
- boolean darkChanging = viewState.dark != child.isDark();
- boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount();
- boolean hasDelays = mAnimationFilter.hasDelays;
- boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || alphaChanging
- || heightChanging || topInsetChanging || darkChanging || shadowAlphaChanging;
- long delay = 0;
- if (fixedDelay != -1) {
- delay = fixedDelay;
- } else if (hasDelays && isDelayRelevant || wasAdded) {
- delay = mCurrentAdditionalDelay + calculateChildAnimationDelay(viewState, finalState);
- }
-
- startViewAnimations(child, viewState, delay, duration);
-
- // start height animation
- if (heightChanging) {
- startHeightAnimation(child, viewState, duration, delay);
- } else {
- abortAnimation(child, TAG_ANIMATOR_HEIGHT);
- }
-
- // start shadow alpha animation
- if (shadowAlphaChanging) {
- startShadowAlphaAnimation(child, viewState, duration, delay);
- } else {
- abortAnimation(child, TAG_ANIMATOR_SHADOW_ALPHA);
- }
-
- // start top inset animation
- if (topInsetChanging) {
- startInsetAnimation(child, viewState, duration, delay);
- } else {
- abortAnimation(child, TAG_ANIMATOR_TOP_INSET);
- }
-
- // start dimmed animation
- child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
-
- // apply below shelf state
- child.setBelowShelf(viewState.belowShelf);
-
- // start hiding sensitive animation
- child.setHideSensitive(viewState.hideSensitive, mAnimationFilter.animateHideSensitive,
- delay, duration);
-
- // start dark animation
- child.setDark(viewState.dark, mAnimationFilter.animateDark, delay);
-
- if (wasAdded) {
- child.performAddAnimation(delay, mCurrentLength);
- }
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- row.startChildAnimation(finalState, this, delay, duration);
- }
- }
-
- /**
- * Start an animation to a new {@link ViewState}.
- *
- * @param child the child to start the animation on
- * @param viewState the {@link ExpandableViewState} 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 || child.getAlpha() != 0)
- && !viewState.gone && !viewState.hidden) {
- child.setVisibility(View.VISIBLE);
- }
- boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
- boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
- float childAlpha = child.getAlpha();
- boolean alphaChanging = viewState.alpha != childAlpha;
- if (child instanceof ExpandableView) {
- // We don't want views to change visibility when they are animating to GONE
- alphaChanging &= !((ExpandableView) child).willBeGone();
- }
-
- // start translationY animation
- if (yTranslationChanging) {
- startYTranslationAnimation(child, viewState, duration, delay);
- } else {
- abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Y);
- }
-
- // start translationZ animation
- if (zTranslationChanging) {
- startZTranslationAnimation(child, viewState, duration, delay);
- } else {
- abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Z);
- }
-
- // start alpha animation
- if (alphaChanging && child.getTranslationX() == 0) {
- startAlphaAnimation(child, viewState, duration, delay);
- } else {
- abortAnimation(child, TAG_ANIMATOR_ALPHA);
- }
- }
-
- private void abortAnimation(View child, int animatorTag) {
- Animator previousAnimator = getChildTag(child, animatorTag);
- if (previousAnimator != null) {
- previousAnimator.cancel();
- }
- }
-
private long calculateChildAnimationDelay(ExpandableViewState viewState,
StackScrollState finalState) {
if (mAnimationFilter.hasDarkEvent) {
@@ -394,396 +292,6 @@ public class StackStateAnimator {
return (long) (index * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE);
}
- private void startShadowAlphaAnimation(final ExpandableView child,
- ExpandableViewState viewState, long duration, long delay) {
- Float previousStartValue = getChildTag(child, TAG_START_SHADOW_ALPHA);
- Float previousEndValue = getChildTag(child, TAG_END_SHADOW_ALPHA);
- float newEndValue = viewState.shadowAlpha;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SHADOW_ALPHA);
- if (!mAnimationFilter.animateShadowAlpha) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- float relativeDiff = newEndValue - previousEndValue;
- float newStartValue = previousStartValue + relativeDiff;
- values[0].setFloatValues(newStartValue, newEndValue);
- child.setTag(TAG_START_SHADOW_ALPHA, newStartValue);
- child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setShadowAlpha(newEndValue);
- return;
- }
- }
-
- ValueAnimator animator = ValueAnimator.ofFloat(child.getShadowAlpha(), newEndValue);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- child.setShadowAlpha((float) animation.getAnimatedValue());
- }
- });
- animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null
- || previousAnimator.getAnimatedFraction() == 0)) {
- animator.setStartDelay(delay);
- }
- animator.addListener(getGlobalAnimationFinishedListener());
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, null);
- child.setTag(TAG_START_SHADOW_ALPHA, null);
- child.setTag(TAG_END_SHADOW_ALPHA, null);
- }
- });
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, animator);
- child.setTag(TAG_START_SHADOW_ALPHA, child.getShadowAlpha());
- child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
- }
-
- private void startHeightAnimation(final ExpandableView child,
- ExpandableViewState viewState, long duration, long delay) {
- Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
- Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
- int newEndValue = viewState.height;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
- if (!mAnimationFilter.animateHeight) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- int relativeDiff = newEndValue - previousEndValue;
- int newStartValue = previousStartValue + relativeDiff;
- values[0].setIntValues(newStartValue, newEndValue);
- child.setTag(TAG_START_HEIGHT, newStartValue);
- child.setTag(TAG_END_HEIGHT, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setActualHeight(newEndValue, false);
- return;
- }
- }
-
- ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- child.setActualHeight((int) animation.getAnimatedValue(),
- false /* notifyListeners */);
- }
- });
- animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null
- || previousAnimator.getAnimatedFraction() == 0)) {
- animator.setStartDelay(delay);
- }
- animator.addListener(getGlobalAnimationFinishedListener());
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- boolean mWasCancelled;
-
- @Override
- public void onAnimationEnd(Animator animation) {
- child.setTag(TAG_ANIMATOR_HEIGHT, null);
- child.setTag(TAG_START_HEIGHT, null);
- child.setTag(TAG_END_HEIGHT, null);
- child.setActualHeightAnimating(false);
- if (!mWasCancelled && child instanceof ExpandableNotificationRow) {
- ((ExpandableNotificationRow) child).setGroupExpansionChanging(
- false /* isExpansionChanging */);
- }
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- mWasCancelled = false;
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mWasCancelled = true;
- }
- });
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_HEIGHT, animator);
- child.setTag(TAG_START_HEIGHT, child.getActualHeight());
- child.setTag(TAG_END_HEIGHT, newEndValue);
- child.setActualHeightAnimating(true);
- }
-
- private void startInsetAnimation(final ExpandableView child,
- ExpandableViewState 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;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TOP_INSET);
- if (!mAnimationFilter.animateTopInset) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- int relativeDiff = newEndValue - previousEndValue;
- int newStartValue = previousStartValue + relativeDiff;
- values[0].setIntValues(newStartValue, newEndValue);
- child.setTag(TAG_START_TOP_INSET, newStartValue);
- child.setTag(TAG_END_TOP_INSET, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setClipTopAmount(newEndValue);
- return;
- }
- }
-
- ValueAnimator animator = ValueAnimator.ofInt(child.getClipTopAmount(), newEndValue);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- child.setClipTopAmount((int) animation.getAnimatedValue());
- }
- });
- animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null
- || previousAnimator.getAnimatedFraction() == 0)) {
- animator.setStartDelay(delay);
- }
- animator.addListener(getGlobalAnimationFinishedListener());
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- child.setTag(TAG_ANIMATOR_TOP_INSET, null);
- child.setTag(TAG_START_TOP_INSET, null);
- child.setTag(TAG_END_TOP_INSET, null);
- }
- });
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_TOP_INSET, animator);
- child.setTag(TAG_START_TOP_INSET, child.getClipTopAmount());
- child.setTag(TAG_END_TOP_INSET, newEndValue);
- }
-
- 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;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA);
- if (!mAnimationFilter.animateAlpha) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- float relativeDiff = newEndValue - previousEndValue;
- float newStartValue = previousStartValue + relativeDiff;
- values[0].setFloatValues(newStartValue, newEndValue);
- child.setTag(TAG_START_ALPHA, newStartValue);
- child.setTag(TAG_END_ALPHA, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setAlpha(newEndValue);
- if (newEndValue == 0) {
- child.setVisibility(View.INVISIBLE);
- }
- }
- }
-
- ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
- child.getAlpha(), newEndValue);
- animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- // Handle layer type
- child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- animator.addListener(new AnimatorListenerAdapter() {
- public boolean mWasCancelled;
-
- @Override
- public void onAnimationEnd(Animator animation) {
- child.setLayerType(View.LAYER_TYPE_NONE, null);
- if (newEndValue == 0 && !mWasCancelled) {
- child.setVisibility(View.INVISIBLE);
- }
- // remove the tag when the animation is finished
- child.setTag(TAG_ANIMATOR_ALPHA, null);
- child.setTag(TAG_START_ALPHA, null);
- child.setTag(TAG_END_ALPHA, null);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mWasCancelled = true;
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- mWasCancelled = false;
- }
- });
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null
- || previousAnimator.getAnimatedFraction() == 0)) {
- animator.setStartDelay(delay);
- }
- animator.addListener(getGlobalAnimationFinishedListener());
-
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_ALPHA, animator);
- child.setTag(TAG_START_ALPHA, child.getAlpha());
- child.setTag(TAG_END_ALPHA, newEndValue);
- }
-
- 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;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z);
- if (!mAnimationFilter.animateZ) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- float relativeDiff = newEndValue - previousEndValue;
- float newStartValue = previousStartValue + relativeDiff;
- values[0].setFloatValues(newStartValue, newEndValue);
- child.setTag(TAG_START_TRANSLATION_Z, newStartValue);
- child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setTranslationZ(newEndValue);
- }
- }
-
- ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
- child.getTranslationZ(), newEndValue);
- animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null
- || previousAnimator.getAnimatedFraction() == 0)) {
- animator.setStartDelay(delay);
- }
- animator.addListener(getGlobalAnimationFinishedListener());
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null);
- child.setTag(TAG_START_TRANSLATION_Z, null);
- child.setTag(TAG_END_TRANSLATION_Z, null);
- }
- });
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator);
- child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ());
- child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
- }
-
- 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;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y);
- if (!mAnimationFilter.animateY) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- float relativeDiff = newEndValue - previousEndValue;
- float newStartValue = previousStartValue + relativeDiff;
- values[0].setFloatValues(newStartValue, newEndValue);
- child.setTag(TAG_START_TRANSLATION_Y, newStartValue);
- child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setTranslationY(newEndValue);
- return;
- }
- }
-
- ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
- child.getTranslationY(), newEndValue);
- Interpolator interpolator = mHeadsUpAppearChildren.contains(child) ?
- mHeadsUpAppearInterpolator :Interpolators.FAST_OUT_SLOW_IN;
- animator.setInterpolator(interpolator);
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null
- || previousAnimator.getAnimatedFraction() == 0)) {
- animator.setStartDelay(delay);
- }
- animator.addListener(getGlobalAnimationFinishedListener());
- final boolean isHeadsUpDisappear = mHeadsUpDisappearChildren.contains(child);
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- HeadsUpManager.setIsClickedNotification(child, false);
- child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
- child.setTag(TAG_START_TRANSLATION_Y, null);
- child.setTag(TAG_END_TRANSLATION_Y, null);
- if (isHeadsUpDisappear) {
- ((ExpandableNotificationRow) child).setHeadsupDisappearRunning(false);
- }
- }
- });
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator);
- child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY());
- child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
- }
-
- private void startAnimator(ValueAnimator animator) {
- mAnimatorSet.add(animator);
- animator.start();
- }
-
/**
* @return an adapter which ensures that onAnimationFinished is called once no animation is
* running anymore
@@ -814,33 +322,11 @@ public class StackStateAnimator {
@Override
public void onAnimationStart(Animator animation) {
mWasCancelled = false;
+ mAnimatorSet.add(animation);
}
};
}
- public static <T> T getChildTag(View child, int tag) {
- return (T) child.getTag(tag);
- }
-
- /**
- * Cancel the previous animator and get the duration of the new animation.
- *
- * @param duration the new duration
- * @param previousAnimator the animator which was running before
- * @return the new duration
- */
- private long cancelAnimatorAndGetNewDuration(long duration, ValueAnimator previousAnimator) {
- long newDuration = duration;
- if (previousAnimator != null) {
- // We take either the desired length of the new animation or the remaining time of
- // the previous animator, whichever is longer.
- newDuration = Math.max(previousAnimator.getDuration()
- - previousAnimator.getCurrentPlayTime(), newDuration);
- previousAnimator.cancel();
- }
- return newDuration;
- }
-
private void onAnimationFinished() {
mHostLayout.onChildAnimationFinished();
for (View v : mChildrenToClearFromOverlay) {
@@ -942,12 +428,13 @@ public class StackStateAnimator {
// We temporarily enable Y animations, the real filter will be combined
// afterwards anyway
mAnimationFilter.animateY = true;
- startViewAnimations(changingView, mTmpState,
+ mAnimationProperties.delay =
event.animationType == NotificationStackScrollLayout
.AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
- ? ANIMATION_DELAY_HEADS_UP
- : 0,
- ANIMATION_DURATION_HEADS_UP_DISAPPEAR);
+ ? ANIMATION_DELAY_HEADS_UP
+ : 0;
+ mAnimationProperties.duration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR;
+ mTmpState.animateTo(changingView, mAnimationProperties);
mChildrenToClearFromOverlay.add(changingView);
}
}
@@ -1007,38 +494,6 @@ public class StackStateAnimator {
}
}
- /**
- * Get the end value of the height animation running on a view or the actualHeight
- * if no animation is running.
- */
- public static int getFinalActualHeight(ExpandableView view) {
- if (view == null) {
- return 0;
- }
- ValueAnimator heightAnimator = getChildTag(view, TAG_ANIMATOR_HEIGHT);
- if (heightAnimator == null) {
- return view.getActualHeight();
- } else {
- return getChildTag(view, TAG_END_HEIGHT);
- }
- }
-
- /**
- * Get the end value of the yTranslation animation running on a view or the yTranslation
- * if no animation is running.
- */
- public static float getFinalTranslationY(View view) {
- if (view == null) {
- return 0;
- }
- ValueAnimator yAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Y);
- if (yAnimator == null) {
- return view.getTranslationY();
- } else {
- return getChildTag(view, TAG_END_TRANSLATION_Y);
- }
- }
-
public void setHeadsUpAppearHeightBottom(int headsUpAppearHeightBottom) {
mHeadsUpAppearHeightBottom = headsUpAppearHeightBottom;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
index 108f0e16589f..c120bbbe23ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -16,9 +16,18 @@
package com.android.systemui.statusbar.stack;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
import android.view.View;
+import android.view.animation.Interpolator;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
/**
* A state of a view. This can be used to apply a set of view properties to a view with
@@ -27,6 +36,16 @@ import com.android.systemui.statusbar.ExpandableView;
*/
public class ViewState {
+ private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
+ private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
+ private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
+ private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
+ private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
+ private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
+ private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
+ private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
+ private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
+
public float alpha;
public float xTranslation;
public float yTranslation;
@@ -119,4 +138,305 @@ public class ViewState {
view.setScaleY(this.scaleY);
}
}
+
+ /**
+ * Start an animation to this viewstate
+ * @param child the view to animate
+ * @param animationProperties the properties of the animation
+ */
+ public void animateTo(View child, AnimationProperties animationProperties) {
+ boolean wasVisible = child.getVisibility() == View.VISIBLE;
+ final float alpha = this.alpha;
+ if (!wasVisible && (alpha != 0 || child.getAlpha() != 0)
+ && !this.gone && !this.hidden) {
+ child.setVisibility(View.VISIBLE);
+ }
+ boolean yTranslationChanging = child.getTranslationY() != this.yTranslation;
+ boolean zTranslationChanging = child.getTranslationZ() != this.zTranslation;
+ float childAlpha = child.getAlpha();
+ boolean alphaChanging = this.alpha != childAlpha;
+ if (child instanceof ExpandableView) {
+ // We don't want views to change visibility when they are animating to GONE
+ alphaChanging &= !((ExpandableView) child).willBeGone();
+ }
+
+ // start translationY animation
+ if (yTranslationChanging) {
+ startYTranslationAnimation(child, animationProperties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Y);
+ }
+
+ // start translationZ animation
+ if (zTranslationChanging) {
+ startZTranslationAnimation(child, animationProperties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Z);
+ }
+
+ // start alpha animation
+ if (alphaChanging && child.getTranslationX() == 0) {
+ startAlphaAnimation(child, animationProperties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_ALPHA);
+ }
+ }
+
+ private void startAlphaAnimation(final View child, AnimationProperties properties) {
+ Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
+ Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
+ final float newEndValue = this.alpha;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateAlpha) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_ALPHA, newStartValue);
+ child.setTag(TAG_END_ALPHA, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setAlpha(newEndValue);
+ if (newEndValue == 0) {
+ child.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
+ child.getAlpha(), newEndValue);
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ // Handle layer type
+ child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ animator.addListener(new AnimatorListenerAdapter() {
+ public boolean mWasCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setLayerType(View.LAYER_TYPE_NONE, null);
+ if (newEndValue == 0 && !mWasCancelled) {
+ child.setVisibility(View.INVISIBLE);
+ }
+ // remove the tag when the animation is finished
+ child.setTag(TAG_ANIMATOR_ALPHA, null);
+ child.setTag(TAG_START_ALPHA, null);
+ child.setTag(TAG_END_ALPHA, null);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mWasCancelled = false;
+ }
+ });
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_ALPHA, animator);
+ child.setTag(TAG_START_ALPHA, child.getAlpha());
+ child.setTag(TAG_END_ALPHA, newEndValue);
+ }
+
+ private void startZTranslationAnimation(final View child, AnimationProperties properties) {
+ Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
+ Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
+ float newEndValue = this.zTranslation;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateZ) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_TRANSLATION_Z, newStartValue);
+ child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setTranslationZ(newEndValue);
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
+ child.getTranslationZ(), newEndValue);
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null);
+ child.setTag(TAG_START_TRANSLATION_Z, null);
+ child.setTag(TAG_END_TRANSLATION_Z, null);
+ }
+ });
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator);
+ child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ());
+ child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+ }
+
+ private void startYTranslationAnimation(final View child, AnimationProperties properties) {
+ Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
+ Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
+ float newEndValue = this.yTranslation;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateY) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_TRANSLATION_Y, newStartValue);
+ child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setTranslationY(newEndValue);
+ return;
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
+ child.getTranslationY(), newEndValue);
+ Interpolator customInterpolator = properties.getCustomInterpolator(child,
+ View.TRANSLATION_Y);
+ Interpolator interpolator = customInterpolator != null ? customInterpolator
+ : Interpolators.FAST_OUT_SLOW_IN;
+ animator.setInterpolator(interpolator);
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ HeadsUpManager.setIsClickedNotification(child, false);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
+ child.setTag(TAG_START_TRANSLATION_Y, null);
+ child.setTag(TAG_END_TRANSLATION_Y, null);
+ onYTranslationAnimationFinished();
+ }
+ });
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator);
+ child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY());
+ child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+ }
+
+ protected void onYTranslationAnimationFinished() {
+ }
+
+ protected void startAnimator(Animator animator, AnimatorListenerAdapter listener) {
+ if (listener != null) {
+ // Even if there's a delay we'd want to notify it of the start immediately.
+ listener.onAnimationStart(animator);
+ }
+ animator.start();
+ }
+
+ public static <T> T getChildTag(View child, int tag) {
+ return (T) child.getTag(tag);
+ }
+
+ protected void abortAnimation(View child, int animatorTag) {
+ Animator previousAnimator = getChildTag(child, animatorTag);
+ if (previousAnimator != null) {
+ previousAnimator.cancel();
+ }
+ }
+
+ /**
+ * Cancel the previous animator and get the duration of the new animation.
+ *
+ * @param duration the new duration
+ * @param previousAnimator the animator which was running before
+ * @return the new duration
+ */
+ protected long cancelAnimatorAndGetNewDuration(long duration, ValueAnimator previousAnimator) {
+ long newDuration = duration;
+ if (previousAnimator != null) {
+ // We take either the desired length of the new animation or the remaining time of
+ // the previous animator, whichever is longer.
+ newDuration = Math.max(previousAnimator.getDuration()
+ - previousAnimator.getCurrentPlayTime(), newDuration);
+ previousAnimator.cancel();
+ }
+ return newDuration;
+ }
+
+ /**
+ * Get the end value of the yTranslation animation running on a view or the yTranslation
+ * if no animation is running.
+ */
+ public static float getFinalTranslationY(View view) {
+ if (view == null) {
+ return 0;
+ }
+ ValueAnimator yAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Y);
+ if (yAnimator == null) {
+ return view.getTranslationY();
+ } else {
+ return getChildTag(view, TAG_END_TRANSLATION_Y);
+ }
+ }
+
+ public static boolean isAnimatingY(ExpandableView child) {
+ return getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y) != null;
+ }
}