| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package android.transition.cts; |
| |
| import static com.android.compatibility.common.util.CtsMockitoUtils.within; |
| |
| import static org.mockito.Matchers.any; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.timeout; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| |
| import android.animation.Animator; |
| import android.animation.ObjectAnimator; |
| import android.app.Instrumentation; |
| import android.graphics.PointF; |
| import android.transition.Scene; |
| import android.transition.Transition; |
| import android.transition.TransitionManager; |
| import android.transition.TransitionValues; |
| import android.transition.Visibility; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.ViewTreeObserver; |
| import android.widget.FrameLayout; |
| |
| import androidx.test.InstrumentationRegistry; |
| import androidx.test.rule.ActivityTestRule; |
| |
| import com.android.compatibility.common.util.WidgetTestUtils; |
| |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.mockito.Mockito; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| public abstract class BaseTransitionTest { |
| protected Instrumentation mInstrumentation; |
| protected TransitionActivity mActivity; |
| protected FrameLayout mSceneRoot; |
| private float mAnimatedValue; |
| protected ArrayList<View> mTargets = new ArrayList<>(); |
| protected Transition mTransition; |
| protected Transition.TransitionListener mListener; |
| |
| @Rule |
| public ActivityTestRule<TransitionActivity> mActivityRule = |
| new ActivityTestRule<>(TransitionActivity.class); |
| |
| @Before |
| public void setup() { |
| mInstrumentation = InstrumentationRegistry.getInstrumentation(); |
| mInstrumentation.setInTouchMode(false); |
| mActivity = mActivityRule.getActivity(); |
| mSceneRoot = (FrameLayout) mActivity.findViewById(R.id.container); |
| mTargets.clear(); |
| mTransition = new TestTransition(); |
| mListener = mock(Transition.TransitionListener.class); |
| mTransition.addListener(mListener); |
| } |
| |
| protected void waitForStart() throws InterruptedException { |
| waitForStart(mListener); |
| } |
| |
| protected static void waitForStart(Transition.TransitionListener listener) { |
| verify(listener, within(4000)).onTransitionStart(any()); |
| } |
| |
| protected void waitForEnd(long waitMillis) { |
| waitForEnd(mListener, waitMillis); |
| mInstrumentation.waitForIdleSync(); |
| } |
| |
| protected static void waitForEnd(Transition.TransitionListener listener, long waitMillis) { |
| if (waitMillis == 0) { |
| verify(listener, times(1)).onTransitionEnd(any()); |
| } else { |
| verify(listener, within(waitMillis)).onTransitionEnd(any()); |
| } |
| } |
| |
| protected View loadLayout(final int layout) throws Throwable { |
| View[] root = new View[1]; |
| |
| mActivityRule.runOnUiThread( |
| () -> root[0] = mActivity.getLayoutInflater().inflate(layout, mSceneRoot, false)); |
| |
| return root[0]; |
| } |
| |
| protected Scene loadScene(final View layout) throws Throwable { |
| final Scene[] scene = new Scene[1]; |
| mActivityRule.runOnUiThread(() -> scene[0] = new Scene(mSceneRoot, layout)); |
| |
| return scene[0]; |
| } |
| |
| protected Scene loadScene(final int layoutId) throws Throwable { |
| final Scene scene[] = new Scene[1]; |
| mActivityRule.runOnUiThread( |
| () -> scene[0] = Scene.getSceneForLayout(mSceneRoot, layoutId, mActivity)); |
| return scene[0]; |
| } |
| |
| protected void startTransition(final int layoutId) throws Throwable { |
| startTransition(loadScene(layoutId)); |
| } |
| |
| protected void startTransition(final Scene scene) throws Throwable { |
| mActivityRule.runOnUiThread(() -> TransitionManager.go(scene, mTransition)); |
| waitForStart(); |
| } |
| |
| protected void endTransition() throws Throwable { |
| mActivityRule.runOnUiThread(() -> TransitionManager.endTransitions(mSceneRoot)); |
| } |
| |
| protected void enterScene(final int layoutId) throws Throwable { |
| enterScene(loadScene(layoutId)); |
| } |
| |
| protected void enterScene(final Scene scene) throws Throwable { |
| WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule, scene::enter, false); |
| } |
| |
| protected void exitScene(final Scene scene) throws Throwable { |
| mActivityRule.runOnUiThread(scene::exit); |
| mInstrumentation.waitForIdleSync(); |
| } |
| |
| protected void resetListener() { |
| mTransition.removeListener(mListener); |
| mListener = mock(Transition.TransitionListener.class); |
| mTransition.addListener(mListener); |
| } |
| |
| public void setAnimatedValue(float animatedValue) { |
| mAnimatedValue = animatedValue; |
| } |
| |
| List<PointF> captureTranslations(View view) throws Throwable { |
| final ArrayList<PointF> points = Mockito.spy(new ArrayList<>()); |
| mActivityRule.runOnUiThread(() -> { |
| ViewTreeObserver.OnDrawListener listener = new ViewTreeObserver.OnDrawListener() { |
| @Override |
| public void onDraw() { |
| float x = view.getTranslationX(); |
| float y = view.getTranslationY(); |
| if (points.isEmpty() || !points.get(points.size() - 1).equals(x, y)) { |
| points.add(new PointF(x, y)); |
| } |
| if (points.size() > 3 && x == 0f && y == 0f) { |
| view.post(() -> { |
| view.getViewTreeObserver().removeOnDrawListener(this); |
| }); |
| } |
| } |
| }; |
| view.getViewTreeObserver().addOnDrawListener(listener); |
| view.invalidate(); |
| }); |
| verify(points, timeout(1000).times(1)).add(any()); |
| return points; |
| } |
| |
| |
| public class TestTransition extends Visibility { |
| |
| public TestTransition() { |
| } |
| |
| @Override |
| public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, |
| TransitionValues endValues) { |
| mTargets.add(endValues.view); |
| return ObjectAnimator.ofFloat(BaseTransitionTest.this, "animatedValue", 0, 1); |
| } |
| |
| @Override |
| public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, |
| TransitionValues endValues) { |
| mTargets.add(startValues.view); |
| return ObjectAnimator.ofFloat(BaseTransitionTest.this, "animatedValue", 1, 0); |
| } |
| } |
| } |