1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tv.common.ui.setup.animation; 18 19 import android.animation.Animator; 20 import android.animation.AnimatorListenerAdapter; 21 import android.animation.AnimatorSet; 22 import android.animation.ObjectAnimator; 23 import android.animation.TypeEvaluator; 24 import android.content.Context; 25 import android.transition.Transition; 26 import android.transition.TransitionSet; 27 import android.view.Gravity; 28 import android.view.View; 29 import android.widget.ImageView; 30 import com.android.tv.common.R; 31 32 /** A helper class for setup animation. */ 33 public final class SetupAnimationHelper { 34 public static final long DELAY_BETWEEN_SIBLINGS_MS = applyAnimationTimeScale(33); 35 36 private static final float ANIMATION_TIME_SCALE = 1.0f; 37 38 private static boolean sInitialized; 39 private static long sFragmentTransitionDuration; 40 private static int sFragmentTransitionLongDistance; 41 private static int sFragmentTransitionShortDistance; 42 SetupAnimationHelper()43 private SetupAnimationHelper() {} 44 45 /** Load initial parameters. This method should be called before using this class. */ initialize(Context context)46 public static void initialize(Context context) { 47 if (sInitialized) { 48 return; 49 } 50 sFragmentTransitionDuration = 51 context.getResources().getInteger(R.integer.setup_fragment_transition_duration); 52 sFragmentTransitionLongDistance = 53 context.getResources() 54 .getDimensionPixelOffset(R.dimen.setup_fragment_transition_long_distance); 55 sFragmentTransitionShortDistance = 56 context.getResources() 57 .getDimensionPixelOffset(R.dimen.setup_fragment_transition_short_distance); 58 sInitialized = true; 59 } 60 checkInitialized()61 private static void checkInitialized() { 62 if (!sInitialized) { 63 throw new IllegalStateException("SetupAnimationHelper not initialized"); 64 } 65 } 66 67 public static class TransitionBuilder { 68 private int mSlideEdge = Gravity.START; 69 private final int mDistance = sFragmentTransitionLongDistance; 70 private long mDuration = sFragmentTransitionDuration; 71 private int[] mParentIdForDelay; 72 private int[] mExcludeIds; 73 TransitionBuilder()74 public TransitionBuilder() { 75 checkInitialized(); 76 } 77 78 /** 79 * Sets the edge of the slide transition. 80 * 81 * @see android.transition.Slide#setSlideEdge 82 */ setSlideEdge(int slideEdge)83 public TransitionBuilder setSlideEdge(int slideEdge) { 84 mSlideEdge = slideEdge; 85 return this; 86 } 87 88 /** Sets the duration of the transition. */ setDuration(long duration)89 public TransitionBuilder setDuration(long duration) { 90 mDuration = duration; 91 return this; 92 } 93 94 /** 95 * Sets the ID of the view whose descendants will perform delayed move. 96 * 97 * @see android.view.ViewGroup#isTransitionGroup 98 */ setParentIdsForDelay(int[] parentIdForDelay)99 public TransitionBuilder setParentIdsForDelay(int[] parentIdForDelay) { 100 mParentIdForDelay = parentIdForDelay; 101 return this; 102 } 103 104 /** Sets the ID's of the views which will not be included in the transition. */ setExcludeIds(int[] excludeIds)105 public TransitionBuilder setExcludeIds(int[] excludeIds) { 106 mExcludeIds = excludeIds; 107 return this; 108 } 109 110 /** Builds and returns the {@link android.transition.Transition}. */ build()111 public Transition build() { 112 FadeAndShortSlide transition = new FadeAndShortSlide(mSlideEdge, mParentIdForDelay); 113 transition.setDistance(mDistance); 114 transition.setDuration(mDuration); 115 if (mExcludeIds != null) { 116 for (int id : mExcludeIds) { 117 transition.excludeTarget(id, true); 118 } 119 } 120 return transition; 121 } 122 } 123 124 /** Changes the move distance of the {@code transition} to long distance. */ setLongDistance(FadeAndShortSlide transition)125 public static void setLongDistance(FadeAndShortSlide transition) { 126 checkInitialized(); 127 transition.setDistance(sFragmentTransitionLongDistance); 128 } 129 130 /** Changes the move distance of the {@code transition} to short distance. */ setShortDistance(FadeAndShortSlide transition)131 public static void setShortDistance(FadeAndShortSlide transition) { 132 checkInitialized(); 133 transition.setDistance(sFragmentTransitionShortDistance); 134 } 135 136 /** Applies the animation scale to the given {@code animator}. */ applyAnimationTimeScale(Animator animator)137 public static Animator applyAnimationTimeScale(Animator animator) { 138 if (animator instanceof AnimatorSet) { 139 for (Animator child : ((AnimatorSet) animator).getChildAnimations()) { 140 applyAnimationTimeScale(child); 141 } 142 } 143 if (animator.getDuration() > 0) { 144 animator.setDuration((long) (animator.getDuration() * ANIMATION_TIME_SCALE)); 145 } 146 animator.setStartDelay((long) (animator.getStartDelay() * ANIMATION_TIME_SCALE)); 147 return animator; 148 } 149 150 /** Applies the animation scale to the given {@code transition}. */ applyAnimationTimeScale(Transition transition)151 public static Transition applyAnimationTimeScale(Transition transition) { 152 if (transition instanceof TransitionSet) { 153 TransitionSet set = (TransitionSet) transition; 154 int count = set.getTransitionCount(); 155 for (int i = 0; i < count; ++i) { 156 applyAnimationTimeScale(set.getTransitionAt(i)); 157 } 158 } 159 if (transition.getDuration() > 0) { 160 transition.setDuration((long) (transition.getDuration() * ANIMATION_TIME_SCALE)); 161 } 162 transition.setStartDelay((long) (transition.getStartDelay() * ANIMATION_TIME_SCALE)); 163 return transition; 164 } 165 166 /** Applies the animation scale to the given {@code time}. */ applyAnimationTimeScale(long time)167 public static long applyAnimationTimeScale(long time) { 168 return (long) (time * ANIMATION_TIME_SCALE); 169 } 170 171 /** 172 * Returns an animator which animates the source image of the {@link ImageView}. 173 * 174 * <p>The frame rate is 60 fps. 175 */ createFrameAnimator(ImageView imageView, int[] frames)176 public static ObjectAnimator createFrameAnimator(ImageView imageView, int[] frames) { 177 return createFrameAnimatorWithDelay(imageView, frames, 0); 178 } 179 180 /** 181 * Returns an animator which animates the source image of the {@link ImageView} with start 182 * delay. 183 * 184 * <p>The frame rate is 60 fps. 185 */ createFrameAnimatorWithDelay( ImageView imageView, int[] frames, long startDelay)186 public static ObjectAnimator createFrameAnimatorWithDelay( 187 ImageView imageView, int[] frames, long startDelay) { 188 ObjectAnimator animator = ObjectAnimator.ofInt(imageView, "imageResource", frames); 189 // Make it 60 fps. 190 animator.setDuration(frames.length * 1000 / 60); 191 animator.setInterpolator(null); 192 animator.setStartDelay(startDelay); 193 animator.setEvaluator( 194 new TypeEvaluator<Integer>() { 195 @Override 196 public Integer evaluate(float fraction, Integer startValue, Integer endValue) { 197 return startValue; 198 } 199 }); 200 return animator; 201 } 202 203 /** 204 * Creates a fade out animator. 205 * 206 * @param view The view which will be animated. 207 * @param duration The duration of the animation. 208 * @param makeVisibleAfterAnimation If {@code true}, the view will become visible after the 209 * animation ends. 210 */ createFadeOutAnimator( final View view, long duration, boolean makeVisibleAfterAnimation)211 public static Animator createFadeOutAnimator( 212 final View view, long duration, boolean makeVisibleAfterAnimation) { 213 ObjectAnimator animator = 214 ObjectAnimator.ofFloat(view, View.ALPHA, 1.0f, 0.0f).setDuration(duration); 215 if (makeVisibleAfterAnimation) { 216 animator.addListener( 217 new AnimatorListenerAdapter() { 218 @Override 219 public void onAnimationEnd(Animator animation) { 220 view.setAlpha(1.0f); 221 } 222 }); 223 } 224 return animator; 225 } 226 } 227