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 AppearAnimationUtils(Context ctx)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 AppearAnimationUtils(Context ctx, long duration, float translationScaleFactor, float delayScaleFactor, Interpolator interpolator)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 startAnimation(View[][] objects, final Runnable finishListener)56 public void startAnimation(View[][] objects, final Runnable finishListener) { 57 startAnimation(objects, finishListener, this); 58 } 59 startAnimation(View[] objects, final Runnable finishListener)60 public void startAnimation(View[] objects, final Runnable finishListener) { 61 startAnimation(objects, finishListener, this); 62 } 63 startAnimation(T[][] objects, final Runnable finishListener, AppearAnimationCreator<T> creator)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 startAnimation(T[] objects, final Runnable finishListener, AppearAnimationCreator<T> creator)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 startAnimations(AppearAnimationProperties properties, T[] objects, final Runnable finishListener, AppearAnimationCreator<T> creator)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 startAnimations(AppearAnimationProperties properties, T[][] objects, final Runnable finishListener, AppearAnimationCreator<T> creator)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 getDelays(T[] items)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 getDelays(T[][] items)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 calculateDelay(int row, int col)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 getInterpolator()162 public Interpolator getInterpolator() { 163 return mInterpolator; 164 } 165 getStartTranslation()166 public float getStartTranslation() { 167 return mStartTranslation; 168 } 169 170 @Override createAnimation(View view, long delay, long duration, float translationY, boolean appearing, Interpolator interpolator, Runnable endRunnable)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