| /* |
| * 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.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.animation.Interpolator; |
| |
| import com.android.systemui.Interpolators; |
| import com.android.systemui.R; |
| import com.android.systemui.statusbar.ExpandableView; |
| import com.android.systemui.statusbar.notification.AnimatableProperty; |
| import com.android.systemui.statusbar.notification.PropertyAnimator; |
| import com.android.systemui.statusbar.policy.HeadsUpUtil; |
| |
| /** |
| * 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 { |
| |
| /** |
| * Some animation properties that can be used to update running animations but not creating |
| * any new ones. |
| */ |
| protected static final AnimationProperties NO_NEW_ANIMATIONS = new AnimationProperties() { |
| AnimationFilter mAnimationFilter = new AnimationFilter(); |
| @Override |
| public AnimationFilter getAnimationFilter() { |
| return mAnimationFilter; |
| } |
| }; |
| private static final int TAG_ANIMATOR_TRANSLATION_X = R.id.translation_x_animator_tag; |
| 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_X = R.id.translation_x_animator_end_value_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_X = R.id.translation_x_animator_start_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 AnimatableProperty SCALE_X_PROPERTY |
| = new AnimatableProperty() { |
| |
| @Override |
| public int getAnimationStartTag() { |
| return R.id.scale_x_animator_start_value_tag; |
| } |
| |
| @Override |
| public int getAnimationEndTag() { |
| return R.id.scale_x_animator_end_value_tag; |
| } |
| |
| @Override |
| public int getAnimatorTag() { |
| return R.id.scale_x_animator_tag; |
| } |
| |
| @Override |
| public Property getProperty() { |
| return View.SCALE_X; |
| } |
| }; |
| |
| private static final AnimatableProperty SCALE_Y_PROPERTY |
| = new AnimatableProperty() { |
| |
| @Override |
| public int getAnimationStartTag() { |
| return R.id.scale_y_animator_start_value_tag; |
| } |
| |
| @Override |
| public int getAnimationEndTag() { |
| return R.id.scale_y_animator_end_value_tag; |
| } |
| |
| @Override |
| public int getAnimatorTag() { |
| return R.id.scale_y_animator_tag; |
| } |
| |
| @Override |
| public Property getProperty() { |
| return View.SCALE_Y; |
| } |
| }; |
| |
| public float alpha; |
| public float xTranslation; |
| public float yTranslation; |
| public float zTranslation; |
| public boolean gone; |
| public boolean hidden; |
| public float scaleX = 1.0f; |
| public float scaleY = 1.0f; |
| |
| public void copyFrom(ViewState viewState) { |
| alpha = viewState.alpha; |
| xTranslation = viewState.xTranslation; |
| yTranslation = viewState.yTranslation; |
| zTranslation = viewState.zTranslation; |
| gone = viewState.gone; |
| hidden = viewState.hidden; |
| scaleX = viewState.scaleX; |
| scaleY = viewState.scaleY; |
| } |
| |
| public void initFrom(View view) { |
| alpha = view.getAlpha(); |
| xTranslation = view.getTranslationX(); |
| yTranslation = view.getTranslationY(); |
| zTranslation = view.getTranslationZ(); |
| gone = view.getVisibility() == View.GONE; |
| hidden = view.getVisibility() == View.INVISIBLE; |
| scaleX = view.getScaleX(); |
| scaleY = view.getScaleY(); |
| } |
| |
| /** |
| * Applies a {@link ViewState} to a normal view. |
| */ |
| public void applyToView(View view) { |
| if (this.gone) { |
| // don't do anything with it |
| return; |
| } |
| |
| // apply xTranslation |
| boolean animatingX = isAnimating(view, TAG_ANIMATOR_TRANSLATION_X); |
| if (animatingX) { |
| updateAnimationX(view); |
| } else if (view.getTranslationX() != this.xTranslation){ |
| view.setTranslationX(this.xTranslation); |
| } |
| |
| // apply yTranslation |
| boolean animatingY = isAnimating(view, TAG_ANIMATOR_TRANSLATION_Y); |
| if (animatingY) { |
| updateAnimationY(view); |
| } else if (view.getTranslationY() != this.yTranslation) { |
| view.setTranslationY(this.yTranslation); |
| } |
| |
| // apply zTranslation |
| boolean animatingZ = isAnimating(view, TAG_ANIMATOR_TRANSLATION_Z); |
| if (animatingZ) { |
| updateAnimationZ(view); |
| } else if (view.getTranslationZ() != this.zTranslation) { |
| view.setTranslationZ(this.zTranslation); |
| } |
| |
| // apply scaleX |
| boolean animatingScaleX = isAnimating(view, SCALE_X_PROPERTY); |
| if (animatingScaleX) { |
| updateAnimation(view, SCALE_X_PROPERTY, scaleX); |
| } else if (view.getScaleX() != scaleX) { |
| view.setScaleX(scaleX); |
| } |
| |
| // apply scaleY |
| boolean animatingScaleY = isAnimating(view, SCALE_Y_PROPERTY); |
| if (animatingScaleY) { |
| updateAnimation(view, SCALE_Y_PROPERTY, scaleY); |
| } else if (view.getScaleY() != scaleY) { |
| view.setScaleY(scaleY); |
| } |
| |
| int oldVisibility = view.getVisibility(); |
| boolean becomesInvisible = this.alpha == 0.0f |
| || (this.hidden && (!isAnimating(view) || oldVisibility != View.VISIBLE)); |
| boolean animatingAlpha = isAnimating(view, TAG_ANIMATOR_ALPHA); |
| if (animatingAlpha) { |
| updateAlphaAnimation(view); |
| } else if (view.getAlpha() != this.alpha) { |
| // apply layer type |
| boolean becomesFullyVisible = this.alpha == 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(this.alpha); |
| } |
| |
| // apply visibility |
| int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE; |
| if (newVisibility != oldVisibility) { |
| if (!(view instanceof ExpandableView) || !((ExpandableView) view).willBeGone()) { |
| // We don't want views to change visibility when they are animating to GONE |
| view.setVisibility(newVisibility); |
| } |
| } |
| } |
| |
| public boolean isAnimating(View view) { |
| if (isAnimating(view, TAG_ANIMATOR_TRANSLATION_X)) { |
| return true; |
| } |
| if (isAnimating(view, TAG_ANIMATOR_TRANSLATION_Y)) { |
| return true; |
| } |
| if (isAnimating(view, TAG_ANIMATOR_TRANSLATION_Z)) { |
| return true; |
| } |
| if (isAnimating(view, TAG_ANIMATOR_ALPHA)) { |
| return true; |
| } |
| if (isAnimating(view, SCALE_X_PROPERTY)) { |
| return true; |
| } |
| if (isAnimating(view, SCALE_Y_PROPERTY)) { |
| return true; |
| } |
| return false; |
| } |
| |
| private static boolean isAnimating(View view, int tag) { |
| return getChildTag(view, tag) != null; |
| } |
| |
| public static boolean isAnimating(View view, AnimatableProperty property) { |
| return getChildTag(view, property.getAnimatorTag()) != null; |
| } |
| |
| /** |
| * 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); |
| } |
| 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 translationX animation |
| if (child.getTranslationX() != this.xTranslation) { |
| startXTranslationAnimation(child, animationProperties); |
| } else { |
| abortAnimation(child, TAG_ANIMATOR_TRANSLATION_X); |
| } |
| |
| // start translationY animation |
| if (child.getTranslationY() != this.yTranslation) { |
| startYTranslationAnimation(child, animationProperties); |
| } else { |
| abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Y); |
| } |
| |
| // start translationZ animation |
| if (child.getTranslationZ() != this.zTranslation) { |
| startZTranslationAnimation(child, animationProperties); |
| } else { |
| abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Z); |
| } |
| |
| // start scaleX animation |
| if (child.getScaleX() != scaleX) { |
| PropertyAnimator.startAnimation(child, SCALE_X_PROPERTY, scaleX, animationProperties); |
| } else { |
| abortAnimation(child, SCALE_X_PROPERTY.getAnimatorTag()); |
| } |
| |
| // start scaleX animation |
| if (child.getScaleY() != scaleY) { |
| PropertyAnimator.startAnimation(child, SCALE_Y_PROPERTY, scaleY, animationProperties); |
| } else { |
| abortAnimation(child, SCALE_Y_PROPERTY.getAnimatorTag()); |
| } |
| |
| // start alpha animation |
| if (alphaChanging) { |
| startAlphaAnimation(child, animationProperties); |
| } else { |
| abortAnimation(child, TAG_ANIMATOR_ALPHA); |
| } |
| } |
| |
| private void updateAlphaAnimation(View view) { |
| startAlphaAnimation(view, NO_NEW_ANIMATIONS); |
| } |
| |
| 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 updateAnimationZ(View view) { |
| startZTranslationAnimation(view, NO_NEW_ANIMATIONS); |
| } |
| |
| private void updateAnimation(View view, AnimatableProperty property, |
| float endValue) { |
| PropertyAnimator.startAnimation(view, property, endValue, NO_NEW_ANIMATIONS); |
| } |
| |
| 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 updateAnimationX(View view) { |
| startXTranslationAnimation(view, NO_NEW_ANIMATIONS); |
| } |
| |
| private void startXTranslationAnimation(final View child, AnimationProperties properties) { |
| Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_X); |
| Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_X); |
| float newEndValue = this.xTranslation; |
| if (previousEndValue != null && previousEndValue == newEndValue) { |
| return; |
| } |
| ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_X); |
| AnimationFilter filter = properties.getAnimationFilter(); |
| if (!filter.animateX) { |
| // 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_X, newStartValue); |
| child.setTag(TAG_END_TRANSLATION_X, newEndValue); |
| previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); |
| return; |
| } else { |
| // no new animation needed, let's just apply the value |
| child.setTranslationX(newEndValue); |
| return; |
| } |
| } |
| |
| ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_X, |
| child.getTranslationX(), newEndValue); |
| Interpolator customInterpolator = properties.getCustomInterpolator(child, |
| View.TRANSLATION_X); |
| 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) { |
| child.setTag(TAG_ANIMATOR_TRANSLATION_X, null); |
| child.setTag(TAG_START_TRANSLATION_X, null); |
| child.setTag(TAG_END_TRANSLATION_X, null); |
| } |
| }); |
| startAnimator(animator, listener); |
| child.setTag(TAG_ANIMATOR_TRANSLATION_X, animator); |
| child.setTag(TAG_START_TRANSLATION_X, child.getTranslationX()); |
| child.setTag(TAG_END_TRANSLATION_X, newEndValue); |
| } |
| |
| private void updateAnimationY(View view) { |
| startYTranslationAnimation(view, NO_NEW_ANIMATIONS); |
| } |
| |
| 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.shouldAnimateY(child)) { |
| // 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) { |
| HeadsUpUtil.setIsClickedHeadsUpNotification(child, false); |
| child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null); |
| child.setTag(TAG_START_TRANSLATION_Y, null); |
| child.setTag(TAG_END_TRANSLATION_Y, null); |
| onYTranslationAnimationFinished(child); |
| } |
| }); |
| 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(View view) { |
| if (hidden && !gone) { |
| view.setVisibility(View.INVISIBLE); |
| } |
| } |
| |
| public static 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 |
| */ |
| public static 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); |
| } |
| } |
| |
| /** |
| * Get the end value of the zTranslation animation running on a view or the zTranslation |
| * if no animation is running. |
| */ |
| public static float getFinalTranslationZ(View view) { |
| if (view == null) { |
| return 0; |
| } |
| ValueAnimator zAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Z); |
| if (zAnimator == null) { |
| return view.getTranslationZ(); |
| } else { |
| return getChildTag(view, TAG_END_TRANSLATION_Z); |
| } |
| } |
| |
| public static boolean isAnimatingY(View child) { |
| return getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y) != null; |
| } |
| |
| public void cancelAnimations(View view) { |
| Animator animator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_X); |
| if (animator != null) { |
| animator.cancel(); |
| } |
| animator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Y); |
| if (animator != null) { |
| animator.cancel(); |
| } |
| animator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Z); |
| if (animator != null) { |
| animator.cancel(); |
| } |
| animator = getChildTag(view, TAG_ANIMATOR_ALPHA); |
| if (animator != null) { |
| animator.cancel(); |
| } |
| } |
| } |