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