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