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