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.times; 23 import static org.mockito.Mockito.verify; 24 25 import android.animation.Animator; 26 import android.animation.ObjectAnimator; 27 import android.app.Instrumentation; 28 import android.support.test.InstrumentationRegistry; 29 import android.support.test.rule.ActivityTestRule; 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.widget.FrameLayout; 38 39 import com.android.compatibility.common.util.WidgetTestUtils; 40 41 import org.junit.Before; 42 import org.junit.Rule; 43 44 import java.util.ArrayList; 45 46 public abstract class BaseTransitionTest { 47 protected Instrumentation mInstrumentation; 48 protected TransitionActivity mActivity; 49 protected FrameLayout mSceneRoot; 50 private float mAnimatedValue; 51 protected ArrayList<View> mTargets = new ArrayList<>(); 52 protected Transition mTransition; 53 protected Transition.TransitionListener mListener; 54 55 @Rule 56 public ActivityTestRule<TransitionActivity> mActivityRule = 57 new ActivityTestRule<>(TransitionActivity.class); 58 59 @Before 60 public void setup() { 61 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 62 mInstrumentation.setInTouchMode(false); 63 mActivity = mActivityRule.getActivity(); 64 mSceneRoot = (FrameLayout) mActivity.findViewById(R.id.container); 65 mTargets.clear(); 66 mTransition = new TestTransition(); 67 mListener = mock(Transition.TransitionListener.class); 68 mTransition.addListener(mListener); 69 } 70 71 protected void waitForStart() throws InterruptedException { 72 waitForStart(mListener); 73 } 74 75 protected static void waitForStart(Transition.TransitionListener listener) { 76 verify(listener, within(4000)).onTransitionStart(any()); 77 } 78 79 protected void waitForEnd(long waitMillis) { 80 waitForEnd(mListener, waitMillis); 81 mInstrumentation.waitForIdleSync(); 82 } 83 84 protected static void waitForEnd(Transition.TransitionListener listener, long waitMillis) { 85 if (waitMillis == 0) { 86 verify(listener, times(1)).onTransitionEnd(any()); 87 } else { 88 verify(listener, within(waitMillis)).onTransitionEnd(any()); 89 } 90 } 91 92 protected View loadLayout(final int layout) throws Throwable { 93 View[] root = new View[1]; 94 95 mActivityRule.runOnUiThread( 96 () -> root[0] = mActivity.getLayoutInflater().inflate(layout, mSceneRoot, false)); 97 98 return root[0]; 99 } 100 101 protected Scene loadScene(final View layout) throws Throwable { 102 final Scene[] scene = new Scene[1]; 103 mActivityRule.runOnUiThread(() -> scene[0] = new Scene(mSceneRoot, layout)); 104 105 return scene[0]; 106 } 107 108 protected Scene loadScene(final int layoutId) throws Throwable { 109 final Scene scene[] = new Scene[1]; 110 mActivityRule.runOnUiThread( 111 () -> scene[0] = Scene.getSceneForLayout(mSceneRoot, layoutId, mActivity)); 112 return scene[0]; 113 } 114 115 protected void startTransition(final int layoutId) throws Throwable { 116 startTransition(loadScene(layoutId)); 117 } 118 119 protected void startTransition(final Scene scene) throws Throwable { 120 mActivityRule.runOnUiThread(() -> TransitionManager.go(scene, mTransition)); 121 waitForStart(); 122 } 123 124 protected void endTransition() throws Throwable { 125 mActivityRule.runOnUiThread(() -> TransitionManager.endTransitions(mSceneRoot)); 126 } 127 128 protected void enterScene(final int layoutId) throws Throwable { 129 enterScene(loadScene(layoutId)); 130 } 131 132 protected void enterScene(final Scene scene) throws Throwable { 133 WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule, scene::enter, false); 134 } 135 136 protected void exitScene(final Scene scene) throws Throwable { 137 mActivityRule.runOnUiThread(scene::exit); 138 mInstrumentation.waitForIdleSync(); 139 } 140 141 protected void resetListener() { 142 mTransition.removeListener(mListener); 143 mListener = mock(Transition.TransitionListener.class); 144 mTransition.addListener(mListener); 145 } 146 147 public void setAnimatedValue(float animatedValue) { 148 mAnimatedValue = animatedValue; 149 } 150 151 public class TestTransition extends Visibility { 152 153 public TestTransition() { 154 } 155 156 @Override 157 public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, 158 TransitionValues endValues) { 159 mTargets.add(endValues.view); 160 return ObjectAnimator.ofFloat(BaseTransitionTest.this, "animatedValue", 0, 1); 161 } 162 163 @Override 164 public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, 165 TransitionValues endValues) { 166 mTargets.add(startValues.view); 167 return ObjectAnimator.ofFloat(BaseTransitionTest.this, "animatedValue", 1, 0); 168 } 169 } 170 } 171