115a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi/*
215a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * Copyright (C) 2014 The Android Open Source Project
315a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi *
415a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License");
515a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * you may not use this file except in compliance with the License.
615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * You may obtain a copy of the License at
715a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi *
815a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi *      http://www.apache.org/licenses/LICENSE-2.0
915a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi *
1015a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * Unless required by applicable law or agreed to in writing, software
1115a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS,
1215a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1315a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * See the License for the specific language governing permissions and
1415a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * limitations under the License
1515a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi */
1615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi
1715a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggipackage com.android.keyguard;
1815a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi
1915a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggiimport android.content.Context;
2015a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggiimport android.view.View;
2115a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggiimport android.view.animation.AnimationUtils;
2215a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggiimport android.view.animation.Interpolator;
2315a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi
2415a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi/**
2515a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi * A class to make nice appear transitions for views in a tabular layout.
2615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi */
273018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinekpublic class AppearAnimationUtils implements AppearAnimationCreator<View> {
2815a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi
2998f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi    public static final long DEFAULT_APPEAR_DURATION = 220;
3015a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi
3198f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi    private final Interpolator mInterpolator;
3215a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi    private final float mStartTranslation;
333018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek    private final AppearAnimationProperties mProperties = new AppearAnimationProperties();
34f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek    protected final float mDelayScale;
3598f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi    private final long mDuration;
36f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek    protected boolean mScaleTranslationWithRow;
37f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek    protected boolean mAppearing;
3815a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi
3915a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi    public AppearAnimationUtils(Context ctx) {
4098f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        this(ctx, DEFAULT_APPEAR_DURATION,
4176a1623afc170a13923b68f3256057d8adeb7937Jorim Jaggi                1.0f, 1.0f,
4298f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi                AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in));
433018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek    }
443018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek
4598f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi    public AppearAnimationUtils(Context ctx, long duration, float translationScaleFactor,
4698f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            float delayScaleFactor, Interpolator interpolator) {
4798f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        mInterpolator = interpolator;
483018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        mStartTranslation = ctx.getResources().getDimensionPixelOffset(
493018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                R.dimen.appear_y_translation_start) * translationScaleFactor;
503018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        mDelayScale = delayScaleFactor;
5198f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        mDuration = duration;
52f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek        mScaleTranslationWithRow = false;
53f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek        mAppearing = true;
5415a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi    }
5515a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi
56f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek    public void startAnimation(View[][] objects, final Runnable finishListener) {
57f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek        startAnimation(objects, finishListener, this);
583018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek    }
593018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek
60f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek    public void startAnimation(View[] objects, final Runnable finishListener) {
61f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek        startAnimation(objects, finishListener, this);
6298f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi    }
6398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi
64f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek    public <T> void startAnimation(T[][] objects, final Runnable finishListener,
653018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            AppearAnimationCreator<T> creator) {
663018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        AppearAnimationProperties properties = getDelays(objects);
673018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        startAnimations(properties, objects, finishListener, creator);
683018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek    }
693018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek
70f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek    public <T> void startAnimation(T[] objects, final Runnable finishListener,
7198f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            AppearAnimationCreator<T> creator) {
7298f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        AppearAnimationProperties properties = getDelays(objects);
7398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        startAnimations(properties, objects, finishListener, creator);
7498f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi    }
7598f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi
7698f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi    private <T> void startAnimations(AppearAnimationProperties properties, T[] objects,
7798f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            final Runnable finishListener, AppearAnimationCreator<T> creator) {
7898f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) {
7998f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            finishListener.run();
8098f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            return;
8198f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        }
8298f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        for (int row = 0; row < properties.delays.length; row++) {
8398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            long[] columns = properties.delays[row];
8498f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            long delay = columns[0];
8598f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            Runnable endRunnable = null;
8698f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == 0) {
8798f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi                endRunnable = finishListener;
8898f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            }
8998f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            creator.createAnimation(objects[row], delay, mDuration,
90f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek                    mStartTranslation, true /* appearing */, mInterpolator, endRunnable);
9198f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        }
9298f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi    }
9398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi
943018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek    private <T> void startAnimations(AppearAnimationProperties properties, T[][] objects,
9598f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            final Runnable finishListener, AppearAnimationCreator<T> creator) {
963018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) {
973018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            finishListener.run();
983018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            return;
993018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        }
1003018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        for (int row = 0; row < properties.delays.length; row++) {
1013018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            long[] columns = properties.delays[row];
102f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek            float translation = mScaleTranslationWithRow
103f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek                    ? (float) (Math.pow((properties.delays.length - row), 2)
104f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek                    / properties.delays.length * mStartTranslation)
105f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek                    : mStartTranslation;
10615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi            for (int col = 0; col < columns.length; col++) {
1073018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                long delay = columns[col];
1083018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                Runnable endRunnable = null;
1093018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == col) {
1103018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                    endRunnable = finishListener;
11115a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi                }
11298f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi                creator.createAnimation(objects[row][col], delay, mDuration,
113f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek                        mAppearing ? translation : -translation,
114f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek                        mAppearing, mInterpolator, endRunnable);
11515a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi            }
11615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi        }
11798f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi    }
1183018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek
11998f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi    private <T> AppearAnimationProperties getDelays(T[] items) {
12098f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        long maxDelay = -1;
12198f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        mProperties.maxDelayColIndex = -1;
12298f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        mProperties.maxDelayRowIndex = -1;
12398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        mProperties.delays = new long[items.length][];
12498f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        for (int row = 0; row < items.length; row++) {
12598f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            mProperties.delays[row] = new long[1];
12698f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            long delay = calculateDelay(row, 0);
12798f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            mProperties.delays[row][0] = delay;
12898f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            if (items[row] != null && delay > maxDelay) {
12998f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi                maxDelay = delay;
13098f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi                mProperties.maxDelayColIndex = 0;
13198f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi                mProperties.maxDelayRowIndex = row;
13298f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi            }
13398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        }
13498f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        return mProperties;
13515a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi    }
13615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi
1373018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek    private <T> AppearAnimationProperties getDelays(T[][] items) {
13898f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        long maxDelay = -1;
1393018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        mProperties.maxDelayColIndex = -1;
1403018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        mProperties.maxDelayRowIndex = -1;
1413018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        mProperties.delays = new long[items.length][];
1423018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        for (int row = 0; row < items.length; row++) {
1433018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            T[] columns = items[row];
1443018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            mProperties.delays[row] = new long[columns.length];
1453018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            for (int col = 0; col < columns.length; col++) {
1463018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                long delay = calculateDelay(row, col);
1473018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                mProperties.delays[row][col] = delay;
1483018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                if (items[row][col] != null && delay > maxDelay) {
1493018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                    maxDelay = delay;
1503018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                    mProperties.maxDelayColIndex = col;
1513018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                    mProperties.maxDelayRowIndex = row;
1523018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                }
1533018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            }
15415a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi        }
1553018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        return mProperties;
15615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi    }
15715a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi
158f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek    protected long calculateDelay(int row, int col) {
1593018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        return (long) ((row * 40 + col * (Math.pow(row, 0.4) + 0.4) * 20) * mDelayScale);
16015a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi    }
16115a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi
1623018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek    public Interpolator getInterpolator() {
16398f8530af3bb8636b7b173443c90686c485205d6Jorim Jaggi        return mInterpolator;
16415a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi    }
16515a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi
16615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi    public float getStartTranslation() {
16715a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi        return mStartTranslation;
16815a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi    }
1693018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek
1703018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek    @Override
171f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek    public void createAnimation(View view, long delay, long duration, float translationY,
172f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek            boolean appearing, Interpolator interpolator, Runnable endRunnable) {
1733018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        if (view != null) {
174f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek            view.setAlpha(appearing ? 0f : 1.0f);
175f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek            view.setTranslationY(appearing ? translationY : 0);
1763018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            view.animate()
177f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek                    .alpha(appearing ? 1f : 0f)
178f9c0e8f02f3483d6aa9e762c97a2c02ea50eeb02Selim Cinek                    .translationY(appearing ? 0 : translationY)
1793018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                    .setInterpolator(interpolator)
1803018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                    .setDuration(duration)
1813018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                    .setStartDelay(delay);
1823018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            if (view.hasOverlappingRendering()) {
1833018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                view.animate().withLayer();
1843018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            }
1853018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            if (endRunnable != null) {
1863018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek                view.animate().withEndAction(endRunnable);
1873018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek            }
1883018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        }
1893018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek    }
1903018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek
1913018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek    public class AppearAnimationProperties {
1923018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        public long[][] delays;
1933018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        public int maxDelayRowIndex;
1943018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek        public int maxDelayColIndex;
1953018197cf0dff5a9061f6065a8ecc108a0866dabSelim Cinek    }
19615a77f7da856cbed19cb67c75268505a333352f1Jorim Jaggi}
197