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