11f8c01181bcdef6e7e7e359ecde003939523b718George Mount/*
21f8c01181bcdef6e7e7e359ecde003939523b718George Mount * Copyright (C) 2014 The Android Open Source Project
31f8c01181bcdef6e7e7e359ecde003939523b718George Mount *
41f8c01181bcdef6e7e7e359ecde003939523b718George Mount * Licensed under the Apache License, Version 2.0 (the "License");
51f8c01181bcdef6e7e7e359ecde003939523b718George Mount * you may not use this file except in compliance with the License.
61f8c01181bcdef6e7e7e359ecde003939523b718George Mount * You may obtain a copy of the License at
71f8c01181bcdef6e7e7e359ecde003939523b718George Mount *
81f8c01181bcdef6e7e7e359ecde003939523b718George Mount *      http://www.apache.org/licenses/LICENSE-2.0
91f8c01181bcdef6e7e7e359ecde003939523b718George Mount *
101f8c01181bcdef6e7e7e359ecde003939523b718George Mount * Unless required by applicable law or agreed to in writing, software
111f8c01181bcdef6e7e7e359ecde003939523b718George Mount * distributed under the License is distributed on an "AS IS" BASIS,
121f8c01181bcdef6e7e7e359ecde003939523b718George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131f8c01181bcdef6e7e7e359ecde003939523b718George Mount * See the License for the specific language governing permissions and
141f8c01181bcdef6e7e7e359ecde003939523b718George Mount * limitations under the License.
151f8c01181bcdef6e7e7e359ecde003939523b718George Mount */
161f8c01181bcdef6e7e7e359ecde003939523b718George Mountpackage android.transition;
171f8c01181bcdef6e7e7e359ecde003939523b718George Mount
181f8c01181bcdef6e7e7e359ecde003939523b718George Mountimport com.android.internal.R;
191f8c01181bcdef6e7e7e359ecde003939523b718George Mount
201f8c01181bcdef6e7e7e359ecde003939523b718George Mountimport android.animation.Animator;
211f8c01181bcdef6e7e7e359ecde003939523b718George Mountimport android.animation.AnimatorListenerAdapter;
221f8c01181bcdef6e7e7e359ecde003939523b718George Mountimport android.animation.ObjectAnimator;
231f8c01181bcdef6e7e7e359ecde003939523b718George Mountimport android.animation.TimeInterpolator;
241f8c01181bcdef6e7e7e359ecde003939523b718George Mountimport android.graphics.Path;
25727a6cf6ad06bbb43c0c309c33776394a0012895George Mountimport android.transition.Transition.TransitionListener;
261f8c01181bcdef6e7e7e359ecde003939523b718George Mountimport android.view.View;
271f8c01181bcdef6e7e7e359ecde003939523b718George Mount
281f8c01181bcdef6e7e7e359ecde003939523b718George Mount/**
291f8c01181bcdef6e7e7e359ecde003939523b718George Mount * This class is used by Slide and Explode to create an animator that goes from the start
301f8c01181bcdef6e7e7e359ecde003939523b718George Mount * position to the end position. It takes into account the canceled position so that it
311f8c01181bcdef6e7e7e359ecde003939523b718George Mount * will not blink out or shift suddenly when the transition is interrupted.
321f8c01181bcdef6e7e7e359ecde003939523b718George Mount */
331f8c01181bcdef6e7e7e359ecde003939523b718George Mountclass TranslationAnimationCreator {
341f8c01181bcdef6e7e7e359ecde003939523b718George Mount
351f8c01181bcdef6e7e7e359ecde003939523b718George Mount    /**
361f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * Creates an animator that can be used for x and/or y translations. When interrupted,
371f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * it sets a tag to keep track of the position so that it may be continued from position.
381f8c01181bcdef6e7e7e359ecde003939523b718George Mount     *
391f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * @param view The view being moved. This may be in the overlay for onDisappear.
401f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * @param values The values containing the view in the view hierarchy.
411f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * @param viewPosX The x screen coordinate of view
421f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * @param viewPosY The y screen coordinate of view
431f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * @param startX The start translation x of view
441f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * @param startY The start translation y of view
451f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * @param endX The end translation x of view
461f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * @param endY The end translation y of view
471f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * @param interpolator The interpolator to use with this animator.
481f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * @return An animator that moves from (startX, startY) to (endX, endY) unless there was
491f8c01181bcdef6e7e7e359ecde003939523b718George Mount     * a previous interruption, in which case it moves from the current position to (endX, endY).
501f8c01181bcdef6e7e7e359ecde003939523b718George Mount     */
511f8c01181bcdef6e7e7e359ecde003939523b718George Mount    static Animator createAnimation(View view, TransitionValues values, int viewPosX, int viewPosY,
52727a6cf6ad06bbb43c0c309c33776394a0012895George Mount            float startX, float startY, float endX, float endY, TimeInterpolator interpolator,
53727a6cf6ad06bbb43c0c309c33776394a0012895George Mount            Transition transition) {
541f8c01181bcdef6e7e7e359ecde003939523b718George Mount        float terminalX = view.getTranslationX();
551f8c01181bcdef6e7e7e359ecde003939523b718George Mount        float terminalY = view.getTranslationY();
561f8c01181bcdef6e7e7e359ecde003939523b718George Mount        int[] startPosition = (int[]) values.view.getTag(R.id.transitionPosition);
571f8c01181bcdef6e7e7e359ecde003939523b718George Mount        if (startPosition != null) {
581f8c01181bcdef6e7e7e359ecde003939523b718George Mount            startX = startPosition[0] - viewPosX + terminalX;
591f8c01181bcdef6e7e7e359ecde003939523b718George Mount            startY = startPosition[1] - viewPosY + terminalY;
601f8c01181bcdef6e7e7e359ecde003939523b718George Mount        }
611f8c01181bcdef6e7e7e359ecde003939523b718George Mount        // Initial position is at translation startX, startY, so position is offset by that amount
621f8c01181bcdef6e7e7e359ecde003939523b718George Mount        int startPosX = viewPosX + Math.round(startX - terminalX);
631f8c01181bcdef6e7e7e359ecde003939523b718George Mount        int startPosY = viewPosY + Math.round(startY - terminalY);
641f8c01181bcdef6e7e7e359ecde003939523b718George Mount
651f8c01181bcdef6e7e7e359ecde003939523b718George Mount        view.setTranslationX(startX);
661f8c01181bcdef6e7e7e359ecde003939523b718George Mount        view.setTranslationY(startY);
671f8c01181bcdef6e7e7e359ecde003939523b718George Mount        if (startX == endX && startY == endY) {
681f8c01181bcdef6e7e7e359ecde003939523b718George Mount            return null;
691f8c01181bcdef6e7e7e359ecde003939523b718George Mount        }
701f8c01181bcdef6e7e7e359ecde003939523b718George Mount        Path path = new Path();
711f8c01181bcdef6e7e7e359ecde003939523b718George Mount        path.moveTo(startX, startY);
721f8c01181bcdef6e7e7e359ecde003939523b718George Mount        path.lineTo(endX, endY);
731f8c01181bcdef6e7e7e359ecde003939523b718George Mount        ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, View.TRANSLATION_Y,
741f8c01181bcdef6e7e7e359ecde003939523b718George Mount                path);
751f8c01181bcdef6e7e7e359ecde003939523b718George Mount
761f8c01181bcdef6e7e7e359ecde003939523b718George Mount        TransitionPositionListener listener = new TransitionPositionListener(view, values.view,
771f8c01181bcdef6e7e7e359ecde003939523b718George Mount                startPosX, startPosY, terminalX, terminalY);
78727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        transition.addListener(listener);
791f8c01181bcdef6e7e7e359ecde003939523b718George Mount        anim.addListener(listener);
801f8c01181bcdef6e7e7e359ecde003939523b718George Mount        anim.addPauseListener(listener);
811f8c01181bcdef6e7e7e359ecde003939523b718George Mount        anim.setInterpolator(interpolator);
821f8c01181bcdef6e7e7e359ecde003939523b718George Mount        return anim;
831f8c01181bcdef6e7e7e359ecde003939523b718George Mount    }
841f8c01181bcdef6e7e7e359ecde003939523b718George Mount
85727a6cf6ad06bbb43c0c309c33776394a0012895George Mount    private static class TransitionPositionListener extends AnimatorListenerAdapter implements
86727a6cf6ad06bbb43c0c309c33776394a0012895George Mount            TransitionListener {
871f8c01181bcdef6e7e7e359ecde003939523b718George Mount
881f8c01181bcdef6e7e7e359ecde003939523b718George Mount        private final View mViewInHierarchy;
891f8c01181bcdef6e7e7e359ecde003939523b718George Mount        private final View mMovingView;
901f8c01181bcdef6e7e7e359ecde003939523b718George Mount        private final int mStartX;
911f8c01181bcdef6e7e7e359ecde003939523b718George Mount        private final int mStartY;
921f8c01181bcdef6e7e7e359ecde003939523b718George Mount        private int[] mTransitionPosition;
931f8c01181bcdef6e7e7e359ecde003939523b718George Mount        private float mPausedX;
941f8c01181bcdef6e7e7e359ecde003939523b718George Mount        private float mPausedY;
951f8c01181bcdef6e7e7e359ecde003939523b718George Mount        private final float mTerminalX;
961f8c01181bcdef6e7e7e359ecde003939523b718George Mount        private final float mTerminalY;
971f8c01181bcdef6e7e7e359ecde003939523b718George Mount
981f8c01181bcdef6e7e7e359ecde003939523b718George Mount        private TransitionPositionListener(View movingView, View viewInHierarchy,
991f8c01181bcdef6e7e7e359ecde003939523b718George Mount                int startX, int startY, float terminalX, float terminalY) {
1001f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mMovingView = movingView;
1011f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mViewInHierarchy = viewInHierarchy;
1021f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mStartX = startX - Math.round(mMovingView.getTranslationX());
1031f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mStartY = startY - Math.round(mMovingView.getTranslationY());
1041f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mTerminalX = terminalX;
1051f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mTerminalY = terminalY;
1061f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mTransitionPosition = (int[]) mViewInHierarchy.getTag(R.id.transitionPosition);
1071f8c01181bcdef6e7e7e359ecde003939523b718George Mount            if (mTransitionPosition != null) {
1081f8c01181bcdef6e7e7e359ecde003939523b718George Mount                mViewInHierarchy.setTagInternal(R.id.transitionPosition, null);
1091f8c01181bcdef6e7e7e359ecde003939523b718George Mount            }
1101f8c01181bcdef6e7e7e359ecde003939523b718George Mount        }
1111f8c01181bcdef6e7e7e359ecde003939523b718George Mount
1121f8c01181bcdef6e7e7e359ecde003939523b718George Mount        @Override
1131f8c01181bcdef6e7e7e359ecde003939523b718George Mount        public void onAnimationCancel(Animator animation) {
1141f8c01181bcdef6e7e7e359ecde003939523b718George Mount            if (mTransitionPosition == null) {
1151f8c01181bcdef6e7e7e359ecde003939523b718George Mount                mTransitionPosition = new int[2];
1161f8c01181bcdef6e7e7e359ecde003939523b718George Mount            }
1171f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mTransitionPosition[0] = Math.round(mStartX + mMovingView.getTranslationX());
1181f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mTransitionPosition[1] = Math.round(mStartY + mMovingView.getTranslationY());
1191f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mViewInHierarchy.setTagInternal(R.id.transitionPosition, mTransitionPosition);
1201f8c01181bcdef6e7e7e359ecde003939523b718George Mount        }
1211f8c01181bcdef6e7e7e359ecde003939523b718George Mount
1221f8c01181bcdef6e7e7e359ecde003939523b718George Mount        @Override
1231f8c01181bcdef6e7e7e359ecde003939523b718George Mount        public void onAnimationEnd(Animator animator) {
1241f8c01181bcdef6e7e7e359ecde003939523b718George Mount        }
1251f8c01181bcdef6e7e7e359ecde003939523b718George Mount
1261f8c01181bcdef6e7e7e359ecde003939523b718George Mount        @Override
1271f8c01181bcdef6e7e7e359ecde003939523b718George Mount        public void onAnimationPause(Animator animator) {
1281f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mPausedX = mMovingView.getTranslationX();
1291f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mPausedY = mMovingView.getTranslationY();
1301f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mMovingView.setTranslationX(mTerminalX);
1311f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mMovingView.setTranslationY(mTerminalY);
1321f8c01181bcdef6e7e7e359ecde003939523b718George Mount        }
1331f8c01181bcdef6e7e7e359ecde003939523b718George Mount
1341f8c01181bcdef6e7e7e359ecde003939523b718George Mount        @Override
1351f8c01181bcdef6e7e7e359ecde003939523b718George Mount        public void onAnimationResume(Animator animator) {
1361f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mMovingView.setTranslationX(mPausedX);
1371f8c01181bcdef6e7e7e359ecde003939523b718George Mount            mMovingView.setTranslationY(mPausedY);
1381f8c01181bcdef6e7e7e359ecde003939523b718George Mount        }
139727a6cf6ad06bbb43c0c309c33776394a0012895George Mount
140727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        @Override
141727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        public void onTransitionStart(Transition transition) {
142727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        }
143727a6cf6ad06bbb43c0c309c33776394a0012895George Mount
144727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        @Override
145727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        public void onTransitionEnd(Transition transition) {
146727a6cf6ad06bbb43c0c309c33776394a0012895George Mount            mMovingView.setTranslationX(mTerminalX);
147727a6cf6ad06bbb43c0c309c33776394a0012895George Mount            mMovingView.setTranslationY(mTerminalY);
148727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        }
149727a6cf6ad06bbb43c0c309c33776394a0012895George Mount
150727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        @Override
151727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        public void onTransitionCancel(Transition transition) {
152727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        }
153727a6cf6ad06bbb43c0c309c33776394a0012895George Mount
154727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        @Override
155727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        public void onTransitionPause(Transition transition) {
156727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        }
157727a6cf6ad06bbb43c0c309c33776394a0012895George Mount
158727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        @Override
159727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        public void onTransitionResume(Transition transition) {
160727a6cf6ad06bbb43c0c309c33776394a0012895George Mount        }
1611f8c01181bcdef6e7e7e359ecde003939523b718George Mount    }
1621f8c01181bcdef6e7e7e359ecde003939523b718George Mount
1631f8c01181bcdef6e7e7e359ecde003939523b718George Mount}
164