Home | History | Annotate | Download | only in keyguard
      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