1 /* 2 * Copyright (C) 2014 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.keyguard; 18 19 import android.content.Context; 20 import android.view.View; 21 import android.view.animation.AnimationUtils; 22 import android.view.animation.Interpolator; 23 24 /** 25 * A class to make nice appear transitions for views in a tabular layout. 26 */ 27 public class AppearAnimationUtils implements AppearAnimationCreator<View> { 28 29 public static final long DEFAULT_APPEAR_DURATION = 220; 30 31 private final Interpolator mInterpolator; 32 private final float mStartTranslation; 33 private final AppearAnimationProperties mProperties = new AppearAnimationProperties(); 34 private final float mDelayScale; 35 private final long mDuration; 36 37 public AppearAnimationUtils(Context ctx) { 38 this(ctx, DEFAULT_APPEAR_DURATION, 39 1.0f, 1.0f, 40 AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in)); 41 } 42 43 public AppearAnimationUtils(Context ctx, long duration, float translationScaleFactor, 44 float delayScaleFactor, Interpolator interpolator) { 45 mInterpolator = interpolator; 46 mStartTranslation = ctx.getResources().getDimensionPixelOffset( 47 R.dimen.appear_y_translation_start) * translationScaleFactor; 48 mDelayScale = delayScaleFactor; 49 mDuration = duration; 50 } 51 52 public void startAppearAnimation(View[][] objects, final Runnable finishListener) { 53 startAppearAnimation(objects, finishListener, this); 54 } 55 56 public void startAppearAnimation(View[] objects, final Runnable finishListener) { 57 startAppearAnimation(objects, finishListener, this); 58 } 59 60 public <T> void startAppearAnimation(T[][] objects, final Runnable finishListener, 61 AppearAnimationCreator<T> creator) { 62 AppearAnimationProperties properties = getDelays(objects); 63 startAnimations(properties, objects, finishListener, creator); 64 } 65 66 public <T> void startAppearAnimation(T[] objects, final Runnable finishListener, 67 AppearAnimationCreator<T> creator) { 68 AppearAnimationProperties properties = getDelays(objects); 69 startAnimations(properties, objects, finishListener, creator); 70 } 71 72 private <T> void startAnimations(AppearAnimationProperties properties, T[] objects, 73 final Runnable finishListener, AppearAnimationCreator<T> creator) { 74 if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) { 75 finishListener.run(); 76 return; 77 } 78 for (int row = 0; row < properties.delays.length; row++) { 79 long[] columns = properties.delays[row]; 80 long delay = columns[0]; 81 Runnable endRunnable = null; 82 if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == 0) { 83 endRunnable = finishListener; 84 } 85 creator.createAnimation(objects[row], delay, mDuration, 86 mStartTranslation, mInterpolator, endRunnable); 87 } 88 } 89 90 private <T> void startAnimations(AppearAnimationProperties properties, T[][] objects, 91 final Runnable finishListener, AppearAnimationCreator<T> creator) { 92 if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) { 93 finishListener.run(); 94 return; 95 } 96 for (int row = 0; row < properties.delays.length; row++) { 97 long[] columns = properties.delays[row]; 98 for (int col = 0; col < columns.length; col++) { 99 long delay = columns[col]; 100 Runnable endRunnable = null; 101 if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == col) { 102 endRunnable = finishListener; 103 } 104 creator.createAnimation(objects[row][col], delay, mDuration, 105 mStartTranslation, mInterpolator, endRunnable); 106 } 107 } 108 } 109 110 private <T> AppearAnimationProperties getDelays(T[] items) { 111 long maxDelay = -1; 112 mProperties.maxDelayColIndex = -1; 113 mProperties.maxDelayRowIndex = -1; 114 mProperties.delays = new long[items.length][]; 115 for (int row = 0; row < items.length; row++) { 116 mProperties.delays[row] = new long[1]; 117 long delay = calculateDelay(row, 0); 118 mProperties.delays[row][0] = delay; 119 if (items[row] != null && delay > maxDelay) { 120 maxDelay = delay; 121 mProperties.maxDelayColIndex = 0; 122 mProperties.maxDelayRowIndex = row; 123 } 124 } 125 return mProperties; 126 } 127 128 private <T> AppearAnimationProperties getDelays(T[][] items) { 129 long maxDelay = -1; 130 mProperties.maxDelayColIndex = -1; 131 mProperties.maxDelayRowIndex = -1; 132 mProperties.delays = new long[items.length][]; 133 for (int row = 0; row < items.length; row++) { 134 T[] columns = items[row]; 135 mProperties.delays[row] = new long[columns.length]; 136 for (int col = 0; col < columns.length; col++) { 137 long delay = calculateDelay(row, col); 138 mProperties.delays[row][col] = delay; 139 if (items[row][col] != null && delay > maxDelay) { 140 maxDelay = delay; 141 mProperties.maxDelayColIndex = col; 142 mProperties.maxDelayRowIndex = row; 143 } 144 } 145 } 146 return mProperties; 147 } 148 149 private long calculateDelay(int row, int col) { 150 return (long) ((row * 40 + col * (Math.pow(row, 0.4) + 0.4) * 20) * mDelayScale); 151 } 152 153 public Interpolator getInterpolator() { 154 return mInterpolator; 155 } 156 157 public float getStartTranslation() { 158 return mStartTranslation; 159 } 160 161 @Override 162 public void createAnimation(View view, long delay, long duration, float startTranslationY, 163 Interpolator interpolator, Runnable endRunnable) { 164 if (view != null) { 165 view.setAlpha(0f); 166 view.setTranslationY(startTranslationY); 167 view.animate() 168 .alpha(1f) 169 .translationY(0) 170 .setInterpolator(interpolator) 171 .setDuration(duration) 172 .setStartDelay(delay); 173 if (view.hasOverlappingRendering()) { 174 view.animate().withLayer(); 175 } 176 if (endRunnable != null) { 177 view.animate().withEndAction(endRunnable); 178 } 179 } 180 } 181 182 public class AppearAnimationProperties { 183 public long[][] delays; 184 public int maxDelayRowIndex; 185 public int maxDelayColIndex; 186 } 187 } 188