Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d1c9281 authored by Jeff DeCew's avatar Jeff DeCew Committed by Android (Google) Code Review
Browse files

Merge "Remove AnimatorTestRule2" into udc-dev

parents 047b5680 de64e967
Loading
Loading
Loading
Loading
+0 −174
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 androidx.core.animation;

import android.os.Looper;
import android.os.SystemClock;
import android.util.AndroidRuntimeException;

import androidx.annotation.NonNull;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

import java.util.ArrayList;
import java.util.List;

/**
 * NOTE: this is a copy of the {@link androidx.core.animation.AnimatorTestRule} which attempts to
 * circumvent the problems with {@link androidx.core.animation.AnimationHandler} having a static
 * list of callbacks.
 *
 * TODO(b/275602127): remove this and use the original rule once we have the updated androidx code.
 */
public final class AnimatorTestRule2 implements TestRule {

    class TestAnimationHandler extends AnimationHandler {
        TestAnimationHandler() {
            super(new TestProvider());
        }

        List<AnimationFrameCallback> animationCallbacks = new ArrayList<>();

        @Override
        void addAnimationFrameCallback(AnimationFrameCallback callback) {
            animationCallbacks.add(callback);
            callback.doAnimationFrame(getCurrentTime());
        }

        @Override
        public void removeCallback(AnimationFrameCallback callback) {
            int id = animationCallbacks.indexOf(callback);
            if (id >= 0) {
                animationCallbacks.set(id, null);
            }
        }

        void onAnimationFrame(long frameTime) {
            for (int i = 0; i < animationCallbacks.size(); i++) {
                final AnimationFrameCallback callback = animationCallbacks.get(i);
                if (callback == null) {
                    continue;
                }
                callback.doAnimationFrame(frameTime);
            }
        }

        @Override
        void autoCancelBasedOn(ObjectAnimator objectAnimator) {
            for (int i = animationCallbacks.size() - 1; i >= 0; i--) {
                AnimationFrameCallback cb = animationCallbacks.get(i);
                if (cb == null) {
                    continue;
                }
                if (objectAnimator.shouldAutoCancel(cb)) {
                    ((Animator) animationCallbacks.get(i)).cancel();
                }
            }
        }
    }

    final TestAnimationHandler mTestHandler;
    final long mStartTime;
    private long mTotalTimeDelta = 0;
    private final Object mLock = new Object();

    public AnimatorTestRule2() {
        mStartTime = SystemClock.uptimeMillis();
        mTestHandler = new TestAnimationHandler();
    }

    @NonNull
    @Override
    public Statement apply(@NonNull final Statement base, @NonNull Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                AnimationHandler.setTestHandler(mTestHandler);
                try {
                    base.evaluate();
                } finally {
                    AnimationHandler.setTestHandler(null);
                }
            }
        };
    }

    /**
     * Advances the animation clock by the given amount of delta in milliseconds. This call will
     * produce an animation frame to all the ongoing animations. This method needs to be
     * called on the same thread as {@link Animator#start()}.
     *
     * @param timeDelta the amount of milliseconds to advance
     */
    public void advanceTimeBy(long timeDelta) {
        if (Looper.myLooper() == null) {
            // Throw an exception
            throw new AndroidRuntimeException("AnimationTestRule#advanceTimeBy(long) may only be"
                    + "called on Looper threads");
        }
        synchronized (mLock) {
            // Advance time & pulse a frame
            mTotalTimeDelta += timeDelta < 0 ? 0 : timeDelta;
        }
        // produce a frame
        mTestHandler.onAnimationFrame(getCurrentTime());
    }


    /**
     * Returns the current time in milliseconds tracked by AnimationHandler. Note that this is a
     * different time than the time tracked by {@link SystemClock} This method needs to be called on
     * the same thread as {@link Animator#start()}.
     */
    public long getCurrentTime() {
        if (Looper.myLooper() == null) {
            // Throw an exception
            throw new AndroidRuntimeException("AnimationTestRule#getCurrentTime() may only be"
                    + "called on Looper threads");
        }
        synchronized (mLock) {
            return mStartTime + mTotalTimeDelta;
        }
    }


    private class TestProvider implements AnimationHandler.AnimationFrameCallbackProvider {
        TestProvider() {
        }

        @Override
        public void onNewCallbackAdded(AnimationHandler.AnimationFrameCallback callback) {
            callback.doAnimationFrame(getCurrentTime());
        }

        @Override
        public void postFrameCallback() {
        }

        @Override
        public void setFrameDelay(long delay) {
        }

        @Override
        public long getFrameDelay() {
            return 0;
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ import org.junit.runner.RunWith
@RunWithLooper(setAsMainLooper = true)
class AnimatorTestRuleTest : SysuiTestCase() {

    @get:Rule val animatorTestRule = AnimatorTestRule2()
    @get:Rule val animatorTestRule = AnimatorTestRule()

    @Test
    fun testA() {
+2 −2
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.View
import android.widget.FrameLayout
import androidx.core.animation.AnimatorTestRule2
import androidx.core.animation.AnimatorTestRule
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -70,7 +70,7 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() {
    private lateinit var systemStatusAnimationScheduler: SystemStatusAnimationScheduler
    private val fakeFeatureFlags = FakeFeatureFlags()

    @get:Rule val animatorTestRule = AnimatorTestRule2()
    @get:Rule val animatorTestRule = AnimatorTestRule()

    @Before
    fun setup() {
+2 −2
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification

import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.core.animation.AnimatorTestRule2
import androidx.core.animation.AnimatorTestRule
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -51,7 +51,7 @@ import org.mockito.Mockito.verifyNoMoreInteractions
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class NotificationWakeUpCoordinatorTest : SysuiTestCase() {

    @get:Rule val animatorTestRule = AnimatorTestRule2()
    @get:Rule val animatorTestRule = AnimatorTestRule()

    private val dumpManager: DumpManager = mock()
    private val headsUpManager: HeadsUpManager = mock()
+2 −2
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ import android.window.OnBackInvokedDispatcher;
import android.window.WindowOnBackInvokedDispatcher;

import androidx.annotation.NonNull;
import androidx.core.animation.AnimatorTestRule2;
import androidx.core.animation.AnimatorTestRule;
import androidx.test.filters.SmallTest;

import com.android.internal.logging.UiEventLogger;
@@ -110,7 +110,7 @@ public class RemoteInputViewTest extends SysuiTestCase {
    private final UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();

    @ClassRule
    public static AnimatorTestRule2 mAnimatorTestRule = new AnimatorTestRule2();
    public static AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();

    @Before
    public void setUp() throws Exception {