1 /* 2 * Copyright 2021 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.compose.ui.platform 18 19 import androidx.compose.runtime.withFrameNanos 20 import androidx.compose.ui.internal.JvmDefaultWithCompatibility 21 import kotlin.coroutines.CoroutineContext 22 import kotlin.coroutines.coroutineContext 23 24 /** 25 * Provides a policy that will be applied to animations that get their frame time from 26 * [withInfiniteAnimationFrameNanos][androidx.compose.animation.core.withInfiniteAnimationFrameNanos] 27 * or 28 * [withInfiniteAnimationFrameMillis][androidx.compose.animation.core.withInfiniteAnimationFrameMillis] 29 * This can be used to intervene in infinite animations to make them finite, for example by 30 * cancelling such coroutines. 31 * 32 * By default no policy is installed, except in instrumented tests that use 33 * [androidx.compose.ui.test.junit4.ComposeTestRule]. 34 */ 35 @JvmDefaultWithCompatibility 36 interface InfiniteAnimationPolicy : CoroutineContext.Element { 37 /** 38 * Call this to apply the policy on the given suspending [block]. Execution of the block is 39 * determined by the policy implementation. For example, a test policy could decide not to run 40 * the block, or trace its execution. 41 * 42 * The block is intended to be part of and will therefore be treated as an infinite animation, 43 * one that after returning from [onInfiniteOperation] will call it again. If the block is not 44 * part of an infinite animation, the policy will still be applied. 45 */ onInfiniteOperationnull46 suspend fun <R> onInfiniteOperation(block: suspend () -> R): R 47 48 override val key: CoroutineContext.Key<*> 49 get() = Key 50 51 companion object Key : CoroutineContext.Key<InfiniteAnimationPolicy> 52 } 53 54 /** 55 * Like [withFrameNanos], but applies the [InfiniteAnimationPolicy] from the calling 56 * [CoroutineContext] if there is one. 57 * 58 * Note that this is an exact copy of the implementation in the `animation-core` module. We need 59 * access to it in this module, but other changes are being considered to this API so we don't want 60 * to go moving APIs around now if we might change them anyway. b/230369229 tracks cleaning up this 61 * clipboard inheritance. 62 */ 63 internal suspend fun <R> withInfiniteAnimationFrameNanos(onFrame: (frameTimeNanos: Long) -> R): R = 64 when (val policy = coroutineContext[InfiniteAnimationPolicy]) { 65 null -> withFrameNanos(onFrame) 66 else -> policy.onInfiniteOperation { withFrameNanos(onFrame) } 67 } 68