1package android.support.v17.leanback.transition;
2
3import android.support.annotation.RestrictTo;
4import android.support.v17.leanback.R;
5
6import android.animation.Animator;
7import android.animation.AnimatorListenerAdapter;
8import android.animation.ObjectAnimator;
9import android.animation.TimeInterpolator;
10import android.graphics.Path;
11import android.transition.Transition;
12import android.transition.TransitionValues;
13import android.transition.Transition.TransitionListener;
14import android.view.View;
15
16import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
17
18/**
19 * This class is used by Slide and Explode to create an animator that goes from the start
20 * position to the end position. It takes into account the canceled position so that it
21 * will not blink out or shift suddenly when the transition is interrupted.
22 * @hide
23 */
24@RestrictTo(GROUP_ID)
25class TranslationAnimationCreator {
26
27    /**
28     * Creates an animator that can be used for x and/or y translations. When interrupted,
29     * it sets a tag to keep track of the position so that it may be continued from position.
30     *
31     * @param view The view being moved. This may be in the overlay for onDisappear.
32     * @param values The values containing the view in the view hierarchy.
33     * @param viewPosX The x screen coordinate of view
34     * @param viewPosY The y screen coordinate of view
35     * @param startX The start translation x of view
36     * @param startY The start translation y of view
37     * @param endX The end translation x of view
38     * @param endY The end translation y of view
39     * @param interpolator The interpolator to use with this animator.
40     * @return An animator that moves from (startX, startY) to (endX, endY) unless there was
41     * a previous interruption, in which case it moves from the current position to (endX, endY).
42     */
43    static Animator createAnimation(View view, TransitionValues values, int viewPosX, int viewPosY,
44            float startX, float startY, float endX, float endY, TimeInterpolator interpolator,
45            Transition transition) {
46        float terminalX = view.getTranslationX();
47        float terminalY = view.getTranslationY();
48        int[] startPosition = (int[]) values.view.getTag(R.id.transitionPosition);
49        if (startPosition != null) {
50            startX = startPosition[0] - viewPosX + terminalX;
51            startY = startPosition[1] - viewPosY + terminalY;
52        }
53        // Initial position is at translation startX, startY, so position is offset by that amount
54        int startPosX = viewPosX + Math.round(startX - terminalX);
55        int startPosY = viewPosY + Math.round(startY - terminalY);
56
57        view.setTranslationX(startX);
58        view.setTranslationY(startY);
59        if (startX == endX && startY == endY) {
60            return null;
61        }
62        Path path = new Path();
63        path.moveTo(startX, startY);
64        path.lineTo(endX, endY);
65        ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, View.TRANSLATION_Y,
66                path);
67
68        TransitionPositionListener listener = new TransitionPositionListener(view, values.view,
69                startPosX, startPosY, terminalX, terminalY);
70        transition.addListener(listener);
71        anim.addListener(listener);
72        anim.addPauseListener(listener);
73        anim.setInterpolator(interpolator);
74        return anim;
75    }
76
77    private static class TransitionPositionListener extends AnimatorListenerAdapter implements
78            TransitionListener {
79
80        private final View mViewInHierarchy;
81        private final View mMovingView;
82        private final int mStartX;
83        private final int mStartY;
84        private int[] mTransitionPosition;
85        private float mPausedX;
86        private float mPausedY;
87        private final float mTerminalX;
88        private final float mTerminalY;
89
90        TransitionPositionListener(View movingView, View viewInHierarchy,
91                int startX, int startY, float terminalX, float terminalY) {
92            mMovingView = movingView;
93            mViewInHierarchy = viewInHierarchy;
94            mStartX = startX - Math.round(mMovingView.getTranslationX());
95            mStartY = startY - Math.round(mMovingView.getTranslationY());
96            mTerminalX = terminalX;
97            mTerminalY = terminalY;
98            mTransitionPosition = (int[]) mViewInHierarchy.getTag(R.id.transitionPosition);
99            if (mTransitionPosition != null) {
100                mViewInHierarchy.setTag(R.id.transitionPosition, null);
101            }
102        }
103
104        @Override
105        public void onAnimationCancel(Animator animation) {
106            if (mTransitionPosition == null) {
107                mTransitionPosition = new int[2];
108            }
109            mTransitionPosition[0] = Math.round(mStartX + mMovingView.getTranslationX());
110            mTransitionPosition[1] = Math.round(mStartY + mMovingView.getTranslationY());
111            mViewInHierarchy.setTag(R.id.transitionPosition, mTransitionPosition);
112        }
113
114        @Override
115        public void onAnimationEnd(Animator animator) {
116        }
117
118        @Override
119        public void onAnimationPause(Animator animator) {
120            mPausedX = mMovingView.getTranslationX();
121            mPausedY = mMovingView.getTranslationY();
122            mMovingView.setTranslationX(mTerminalX);
123            mMovingView.setTranslationY(mTerminalY);
124        }
125
126        @Override
127        public void onAnimationResume(Animator animator) {
128            mMovingView.setTranslationX(mPausedX);
129            mMovingView.setTranslationY(mPausedY);
130        }
131
132        @Override
133        public void onTransitionStart(Transition transition) {
134        }
135
136        @Override
137        public void onTransitionEnd(Transition transition) {
138            mMovingView.setTranslationX(mTerminalX);
139            mMovingView.setTranslationY(mTerminalY);
140        }
141
142        @Override
143        public void onTransitionCancel(Transition transition) {
144        }
145
146        @Override
147        public void onTransitionPause(Transition transition) {
148        }
149
150        @Override
151        public void onTransitionResume(Transition transition) {
152        }
153    }
154
155}
156