• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 android.transition.cts;
17 
18 import static com.android.compatibility.common.util.CtsMockitoUtils.within;
19 
20 import static org.mockito.Matchers.any;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.timeout;
23 import static org.mockito.Mockito.times;
24 import static org.mockito.Mockito.verify;
25 
26 import android.animation.Animator;
27 import android.animation.ObjectAnimator;
28 import android.app.Instrumentation;
29 import android.graphics.PointF;
30 import android.transition.Scene;
31 import android.transition.Transition;
32 import android.transition.TransitionManager;
33 import android.transition.TransitionValues;
34 import android.transition.Visibility;
35 import android.view.View;
36 import android.view.ViewGroup;
37 import android.view.ViewTreeObserver;
38 import android.widget.FrameLayout;
39 
40 import androidx.test.InstrumentationRegistry;
41 import androidx.test.rule.ActivityTestRule;
42 
43 import com.android.compatibility.common.util.WidgetTestUtils;
44 
45 import org.junit.Before;
46 import org.junit.Rule;
47 import org.mockito.Mockito;
48 
49 import java.util.ArrayList;
50 import java.util.List;
51 
52 public abstract class BaseTransitionTest {
53     protected Instrumentation mInstrumentation;
54     protected TransitionActivity mActivity;
55     protected FrameLayout mSceneRoot;
56     private float mAnimatedValue;
57     protected ArrayList<View> mTargets = new ArrayList<>();
58     protected Transition mTransition;
59     protected Transition.TransitionListener mListener;
60 
61     @Rule
62     public ActivityTestRule<TransitionActivity> mActivityRule =
63             new ActivityTestRule<>(TransitionActivity.class);
64 
65     @Before
setup()66     public void setup() {
67         mInstrumentation = InstrumentationRegistry.getInstrumentation();
68         mInstrumentation.setInTouchMode(false);
69         mActivity = mActivityRule.getActivity();
70         mSceneRoot = (FrameLayout) mActivity.findViewById(R.id.container);
71         mTargets.clear();
72         mTransition = new TestTransition();
73         mListener = mock(Transition.TransitionListener.class);
74         mTransition.addListener(mListener);
75     }
76 
waitForStart()77     protected void waitForStart() throws InterruptedException {
78         waitForStart(mListener);
79     }
80 
waitForStart(Transition.TransitionListener listener)81     protected static void waitForStart(Transition.TransitionListener listener) {
82         verify(listener, within(4000)).onTransitionStart(any());
83     }
84 
waitForEnd(long waitMillis)85     protected void waitForEnd(long waitMillis) {
86         waitForEnd(mListener, waitMillis);
87         mInstrumentation.waitForIdleSync();
88     }
89 
waitForEnd(Transition.TransitionListener listener, long waitMillis)90     protected static void waitForEnd(Transition.TransitionListener listener, long waitMillis) {
91         if (waitMillis == 0) {
92             verify(listener, times(1)).onTransitionEnd(any());
93         } else {
94             verify(listener, within(waitMillis)).onTransitionEnd(any());
95         }
96     }
97 
loadLayout(final int layout)98     protected View loadLayout(final int layout) throws Throwable {
99         View[] root = new View[1];
100 
101         mActivityRule.runOnUiThread(
102                 () -> root[0] = mActivity.getLayoutInflater().inflate(layout, mSceneRoot, false));
103 
104         return root[0];
105     }
106 
loadScene(final View layout)107     protected Scene loadScene(final View layout) throws Throwable {
108         final Scene[] scene = new Scene[1];
109         mActivityRule.runOnUiThread(() -> scene[0] = new Scene(mSceneRoot, layout));
110 
111         return scene[0];
112     }
113 
loadScene(final int layoutId)114     protected Scene loadScene(final int layoutId) throws Throwable {
115         final Scene scene[] = new Scene[1];
116         mActivityRule.runOnUiThread(
117                 () -> scene[0] = Scene.getSceneForLayout(mSceneRoot, layoutId, mActivity));
118         return scene[0];
119     }
120 
startTransition(final int layoutId)121     protected void startTransition(final int layoutId) throws Throwable {
122         startTransition(loadScene(layoutId));
123     }
124 
startTransition(final Scene scene)125     protected void startTransition(final Scene scene) throws Throwable {
126         mActivityRule.runOnUiThread(() -> TransitionManager.go(scene, mTransition));
127         waitForStart();
128     }
129 
endTransition()130     protected void endTransition() throws Throwable {
131         mActivityRule.runOnUiThread(() -> TransitionManager.endTransitions(mSceneRoot));
132     }
133 
enterScene(final int layoutId)134     protected void enterScene(final int layoutId) throws Throwable {
135         enterScene(loadScene(layoutId));
136     }
137 
enterScene(final Scene scene)138     protected void enterScene(final Scene scene) throws Throwable {
139         WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule, scene::enter, false);
140     }
141 
exitScene(final Scene scene)142     protected void exitScene(final Scene scene) throws Throwable {
143         mActivityRule.runOnUiThread(scene::exit);
144         mInstrumentation.waitForIdleSync();
145     }
146 
resetListener()147     protected void resetListener() {
148         mTransition.removeListener(mListener);
149         mListener = mock(Transition.TransitionListener.class);
150         mTransition.addListener(mListener);
151     }
152 
setAnimatedValue(float animatedValue)153     public void setAnimatedValue(float animatedValue) {
154         mAnimatedValue = animatedValue;
155     }
156 
captureTranslations(View view)157     List<PointF> captureTranslations(View view) throws Throwable {
158         final ArrayList<PointF> points = Mockito.spy(new ArrayList<>());
159         mActivityRule.runOnUiThread(() -> {
160             ViewTreeObserver.OnDrawListener listener = new ViewTreeObserver.OnDrawListener() {
161                 @Override
162                 public void onDraw() {
163                     float x = view.getTranslationX();
164                     float y = view.getTranslationY();
165                     if (points.isEmpty() || !points.get(points.size() - 1).equals(x, y)) {
166                         points.add(new PointF(x, y));
167                     }
168                     if (points.size() > 3 && x == 0f && y == 0f) {
169                         view.post(() -> {
170                             view.getViewTreeObserver().removeOnDrawListener(this);
171                         });
172                     }
173                 }
174             };
175             view.getViewTreeObserver().addOnDrawListener(listener);
176             view.invalidate();
177         });
178         verify(points, timeout(1000).times(1)).add(any());
179         return points;
180     }
181 
182 
183     public class TestTransition extends Visibility {
184 
TestTransition()185         public TestTransition() {
186         }
187 
188         @Override
onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues)189         public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
190                 TransitionValues endValues) {
191             mTargets.add(endValues.view);
192             return ObjectAnimator.ofFloat(BaseTransitionTest.this, "animatedValue", 0, 1);
193         }
194 
195         @Override
onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues)196         public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
197                 TransitionValues endValues) {
198             mTargets.add(startValues.view);
199             return ObjectAnimator.ofFloat(BaseTransitionTest.this, "animatedValue", 1, 0);
200         }
201     }
202 }
203