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