Merge "Add new SystemUI AnimatorTestRule that wraps both platform and androidx versions of the same" into udc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9c9649e457
@@ -407,6 +407,7 @@ android_library {
|
||||
static_libs: [
|
||||
"SystemUI-tests-base",
|
||||
"androidx.test.uiautomator_uiautomator",
|
||||
"androidx.core_core-animation-testing",
|
||||
"mockito-target-extended-minus-junit4",
|
||||
"androidx.test.ext.junit",
|
||||
"androidx.test.ext.truth",
|
||||
@@ -476,6 +477,7 @@ android_robolectric_test {
|
||||
],
|
||||
static_libs: [
|
||||
"androidx.test.uiautomator_uiautomator",
|
||||
"androidx.core_core-animation-testing",
|
||||
"androidx.test.ext.junit",
|
||||
"inline-mockito-robolectric-prebuilt",
|
||||
],
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.junit.runner.RunWith
|
||||
*/
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
@RunWithLooper(setAsMainLooper = true)
|
||||
@RunWithLooper
|
||||
class AnimatorTestRuleIsolationTest : SysuiTestCase() {
|
||||
|
||||
@get:Rule val animatorTestRule = AnimatorTestRule()
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
@RunWithLooper(setAsMainLooper = true)
|
||||
@RunWithLooper
|
||||
class AnimatorTestRulePrecisionTest : SysuiTestCase() {
|
||||
|
||||
@get:Rule val animatorTestRule = AnimatorTestRule()
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.junit.runner.RunWith
|
||||
*/
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
@RunWithLooper(setAsMainLooper = true)
|
||||
@RunWithLooper
|
||||
class AnimatorTestRuleIsolationTest : SysuiTestCase() {
|
||||
|
||||
@get:Rule val animatorTestRule = AnimatorTestRule()
|
||||
|
||||
@@ -25,12 +25,12 @@ import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
|
||||
import androidx.core.animation.AnimatorTestRule;
|
||||
import androidx.core.animation.ObjectAnimator;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
import com.android.systemui.animation.AnimatorTestRule;
|
||||
import com.android.systemui.flags.FakeFeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.statusbar.NotificationMediaManager;
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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 com.android.systemui.animation
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.util.doOnEnd
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
@RunWithLooper
|
||||
class AnimatorTestRuleOrderTest : SysuiTestCase() {
|
||||
|
||||
@get:Rule val animatorTestRule = AnimatorTestRule()
|
||||
|
||||
var value1: Float = -1f
|
||||
var value2: Float = -1f
|
||||
|
||||
private inline fun animateThisX(
|
||||
propertyName: String,
|
||||
duration: Long,
|
||||
startDelay: Long = 0,
|
||||
crossinline onEndAction: () -> Unit,
|
||||
) {
|
||||
androidx.core.animation.ObjectAnimator.ofFloat(this, propertyName, 0f, 1f).also {
|
||||
it.interpolator = null
|
||||
it.duration = duration
|
||||
it.startDelay = startDelay
|
||||
it.doOnEnd { onEndAction() }
|
||||
it.start()
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun animateThisP(
|
||||
propertyName: String,
|
||||
duration: Long,
|
||||
startDelay: Long = 0,
|
||||
crossinline onEndAction: () -> Unit,
|
||||
) {
|
||||
android.animation.ObjectAnimator.ofFloat(this, propertyName, 0f, 1f).also {
|
||||
it.interpolator = null
|
||||
it.duration = duration
|
||||
it.startDelay = startDelay
|
||||
it.doOnEnd { onEndAction() }
|
||||
it.start()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTwoAnimators() {
|
||||
var ended1 = false
|
||||
var ended2 = false
|
||||
animateThisP("value1", duration = 100) { ended1 = true }
|
||||
animateThisX("value2", duration = 200) { ended2 = true }
|
||||
assertThat(value1).isEqualTo(0f)
|
||||
assertThat(value2).isEqualTo(0f)
|
||||
assertThat(ended1).isFalse()
|
||||
assertThat(ended2).isFalse()
|
||||
|
||||
animatorTestRule.advanceTimeBy(99)
|
||||
assertThat(value1).isEqualTo(0.99f)
|
||||
assertThat(value2).isEqualTo(0.495f)
|
||||
assertThat(ended1).isFalse()
|
||||
assertThat(ended2).isFalse()
|
||||
|
||||
animatorTestRule.advanceTimeBy(1)
|
||||
assertThat(value1).isEqualTo(1f)
|
||||
assertThat(value2).isEqualTo(0.5f)
|
||||
assertThat(ended1).isTrue()
|
||||
assertThat(ended2).isFalse()
|
||||
|
||||
animatorTestRule.advanceTimeBy(99)
|
||||
assertThat(value1).isEqualTo(1f)
|
||||
assertThat(value2).isEqualTo(0.995f)
|
||||
assertThat(ended1).isTrue()
|
||||
assertThat(ended2).isFalse()
|
||||
|
||||
animatorTestRule.advanceTimeBy(1)
|
||||
assertThat(value1).isEqualTo(1f)
|
||||
assertThat(value2).isEqualTo(1f)
|
||||
assertThat(ended1).isTrue()
|
||||
assertThat(ended2).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChainedAnimatorsPlatformThenX() {
|
||||
var ended1 = false
|
||||
var ended2 = false
|
||||
animateThisP("value1", duration = 100) {
|
||||
ended1 = true
|
||||
animateThisX("value2", duration = 100) { ended2 = true }
|
||||
}
|
||||
|
||||
assertThat(value1).isEqualTo(0f)
|
||||
assertThat(value2).isEqualTo(-1f)
|
||||
assertThat(ended1).isFalse()
|
||||
assertThat(ended2).isFalse()
|
||||
|
||||
animatorTestRule.advanceTimeBy(50)
|
||||
assertThat(value1).isEqualTo(0.5f)
|
||||
assertThat(value2).isEqualTo(-1f)
|
||||
assertThat(ended1).isFalse()
|
||||
assertThat(ended2).isFalse()
|
||||
|
||||
animatorTestRule.advanceTimeBy(50)
|
||||
assertThat(value1).isEqualTo(1f)
|
||||
assertThat(value2).isEqualTo(0f)
|
||||
assertThat(ended1).isTrue()
|
||||
assertThat(ended2).isFalse()
|
||||
|
||||
animatorTestRule.advanceTimeBy(50)
|
||||
assertThat(value1).isEqualTo(1f)
|
||||
assertThat(value2).isEqualTo(0.5f)
|
||||
assertThat(ended1).isTrue()
|
||||
assertThat(ended2).isFalse()
|
||||
|
||||
animatorTestRule.advanceTimeBy(50)
|
||||
assertThat(value1).isEqualTo(1f)
|
||||
assertThat(value2).isEqualTo(1f)
|
||||
assertThat(ended1).isTrue()
|
||||
assertThat(ended2).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChainedAnimatorsXThenPlatform() {
|
||||
var ended1 = false
|
||||
var ended2 = false
|
||||
animateThisX("value1", duration = 100) {
|
||||
ended1 = true
|
||||
animateThisP("value2", duration = 100) { ended2 = true }
|
||||
}
|
||||
|
||||
assertThat(value1).isEqualTo(0f)
|
||||
assertThat(value2).isEqualTo(-1f)
|
||||
assertThat(ended1).isFalse()
|
||||
assertThat(ended2).isFalse()
|
||||
|
||||
animatorTestRule.advanceTimeBy(50)
|
||||
assertThat(value1).isEqualTo(0.5f)
|
||||
assertThat(value2).isEqualTo(-1f)
|
||||
assertThat(ended1).isFalse()
|
||||
assertThat(ended2).isFalse()
|
||||
|
||||
animatorTestRule.advanceTimeBy(50)
|
||||
assertThat(value1).isEqualTo(1f)
|
||||
assertThat(value2).isEqualTo(0f)
|
||||
assertThat(ended1).isTrue()
|
||||
assertThat(ended2).isFalse()
|
||||
|
||||
animatorTestRule.advanceTimeBy(50)
|
||||
assertThat(value1).isEqualTo(1f)
|
||||
assertThat(value2).isEqualTo(0.5f)
|
||||
assertThat(ended1).isTrue()
|
||||
assertThat(ended2).isFalse()
|
||||
|
||||
animatorTestRule.advanceTimeBy(50)
|
||||
assertThat(value1).isEqualTo(1f)
|
||||
assertThat(value2).isEqualTo(1f)
|
||||
assertThat(ended1).isTrue()
|
||||
assertThat(ended2).isTrue()
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,10 @@ package com.android.systemui.keyguard.data.repository
|
||||
import android.graphics.Point
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import androidx.core.animation.AnimatorTestRule
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.RoboPilotTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.AnimatorTestRule
|
||||
import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
|
||||
import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
|
||||
|
||||
@@ -24,9 +24,9 @@ import android.util.Pair
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.animation.AnimatorTestRule
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.AnimatorTestRule
|
||||
import com.android.systemui.flags.FakeFeatureFlags
|
||||
import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener
|
||||
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
|
||||
|
||||
@@ -22,9 +22,9 @@ import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.animation.AnimatorTestRule
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.AnimatorTestRule
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.flags.FakeFeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
|
||||
@@ -18,9 +18,9 @@ package com.android.systemui.statusbar.notification
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import androidx.core.animation.AnimatorTestRule
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.AnimatorTestRule
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.dump.logcatLogBuffer
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
|
||||
@@ -45,12 +45,12 @@ import android.view.View;
|
||||
import android.view.ViewPropertyAnimator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.core.animation.AnimatorTestRule;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiBaseFragmentTest;
|
||||
import com.android.systemui.animation.AnimatorTestRule;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.log.LogBuffer;
|
||||
|
||||
@@ -19,9 +19,9 @@ package com.android.systemui.statusbar.phone.fragment
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import android.view.View
|
||||
import androidx.core.animation.AnimatorTestRule
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.AnimatorTestRule
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
|
||||
@@ -62,7 +62,6 @@ import android.window.OnBackInvokedDispatcher;
|
||||
import android.window.WindowOnBackInvokedDispatcher;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.animation.AnimatorTestRule;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
@@ -70,6 +69,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.animation.AnimatorTestRule;
|
||||
import com.android.systemui.flags.FakeFeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.animation;
|
||||
|
||||
import android.animation.AnimationHandler.AnimationFrameCallback;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.util.AndroidRuntimeException;
|
||||
@@ -31,6 +32,7 @@ import org.junit.runners.model.Statement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* JUnit {@link TestRule} that can be used to run {@link Animator}s without actually waiting for the
|
||||
@@ -125,14 +127,40 @@ public final class AnimatorTestRule implements TestRule {
|
||||
* @param timeDelta the amount of milliseconds to advance
|
||||
*/
|
||||
public void advanceTimeBy(long timeDelta) {
|
||||
advanceTimeBy(timeDelta, 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()}.
|
||||
* <p>
|
||||
* This method is not for test authors, but for rule authors to ensure that multiple animators
|
||||
* can be advanced in sync.
|
||||
*
|
||||
* @param timeDelta the amount of milliseconds to advance
|
||||
* @param preFrameAction a consumer to be passed the timeDelta following the time advancement
|
||||
* but prior to the frame production.
|
||||
*/
|
||||
public void advanceTimeBy(long timeDelta, @Nullable Consumer<Long> preFrameAction) {
|
||||
Preconditions.checkArgumentNonnegative(timeDelta, "timeDelta must not be negative");
|
||||
requireLooper("AnimationTestRule#advanceTimeBy(long)");
|
||||
// before advancing time, start new animators with the current time
|
||||
initNewAnimators();
|
||||
if (timeDelta == 0) {
|
||||
// If time is not being advanced, all animators will get a tick; don't double tick these
|
||||
mTestHandler.mNewCallbacks.clear();
|
||||
} else {
|
||||
// before advancing time, start new animators with the current time
|
||||
initNewAnimators();
|
||||
}
|
||||
synchronized (mLock) {
|
||||
// advance time
|
||||
mTotalTimeDelta += timeDelta;
|
||||
}
|
||||
if (preFrameAction != null) {
|
||||
preFrameAction.accept(timeDelta);
|
||||
// After letting other code run, clear any new callbacks to avoid double-ticking them
|
||||
mTestHandler.mNewCallbacks.clear();
|
||||
}
|
||||
// produce a frame
|
||||
mTestHandler.doFrame();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 com.android.systemui.animation
|
||||
|
||||
import java.util.function.Consumer
|
||||
import org.junit.rules.RuleChain
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.Description
|
||||
import org.junit.runners.model.Statement
|
||||
|
||||
/**
|
||||
* A rule that wraps both [androidx.core.animation.AnimatorTestRule] and
|
||||
* [android.animation.AnimatorTestRule] such that the clocks of the two animation handlers can be
|
||||
* advanced together.
|
||||
*/
|
||||
class AnimatorTestRule : TestRule {
|
||||
private val androidxRule = androidx.core.animation.AnimatorTestRule()
|
||||
private val platformRule = android.animation.AnimatorTestRule()
|
||||
private val advanceAndroidXTimeBy =
|
||||
Consumer<Long> { timeDelta -> androidxRule.advanceTimeBy(timeDelta) }
|
||||
|
||||
/**
|
||||
* Chain is for simplicity not to force a particular order; order should not matter, because
|
||||
* each rule affects a different AnimationHandler classes, and no callbacks to code under test
|
||||
* should be triggered by these rules
|
||||
*/
|
||||
private val ruleChain = RuleChain.emptyRuleChain().around(androidxRule).around(platformRule)
|
||||
|
||||
override fun apply(base: Statement, description: Description): Statement =
|
||||
ruleChain.apply(base, description)
|
||||
|
||||
/**
|
||||
* Advances the animation clock by the given amount of delta in milliseconds. This call will
|
||||
* produce an animation frame to all the ongoing animations.
|
||||
*
|
||||
* @param timeDelta the amount of milliseconds to advance
|
||||
*/
|
||||
fun advanceTimeBy(timeDelta: Long) {
|
||||
// NOTE: To avoid errors with order, we have to ensure that we advance the time within both
|
||||
// rules before either rule does its frame output. Failing to do this could cause the
|
||||
// animation from one to start later than the other.
|
||||
platformRule.advanceTimeBy(timeDelta, advanceAndroidXTimeBy)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user