1 /* 2 * Copyright (C) 2023 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 17 package androidx.core.animation 18 19 import com.android.systemui.util.test.TestExceptionDeferrer 20 import org.junit.rules.TestRule 21 import org.junit.runner.Description 22 import org.junit.runners.model.Statement 23 24 /** 25 * This rule is used by [com.android.systemui.SysuiTestCase] to fail any test which attempts to 26 * start an AndroidX [Animator] without using [androidx.core.animation.AnimatorTestRule]. 27 */ 28 class AndroidXAnimatorIsolationRule : TestRule { 29 30 private class IsolatingAnimationHandler(ruleThread: Thread) : AnimationHandler(null) { 31 private val exceptionDeferrer = TestExceptionDeferrer(TAG, ruleThread) 32 override fun addAnimationFrameCallback(callback: AnimationFrameCallback?) = onError() 33 override fun removeCallback(callback: AnimationFrameCallback?) = onError() 34 override fun onAnimationFrame(frameTime: Long) = onError() 35 override fun setFrameDelay(frameDelay: Long) = onError() 36 37 private fun onError() = 38 exceptionDeferrer.fail( 39 "Test's animations are not isolated! " + 40 "Did you forget to add an AnimatorTestRule to your test class?" 41 ) 42 43 fun throwDeferred() = exceptionDeferrer.throwDeferred() 44 } 45 46 override fun apply(base: Statement, description: Description): Statement { 47 return object : Statement() { 48 @Throws(Throwable::class) 49 override fun evaluate() { 50 val isolationHandler = IsolatingAnimationHandler(Thread.currentThread()) 51 AnimationHandler.setTestHandler(isolationHandler) 52 try { 53 base.evaluate() 54 } finally { 55 AnimationHandler.setTestHandler(null) 56 // Pass or fail, a deferred exception should be the failure reason 57 isolationHandler.throwDeferred() 58 } 59 } 60 } 61 } 62 63 private companion object { 64 private const val TAG = "AndroidXAnimatorIsolationRule" 65 } 66 } 67