• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 com.android.mechanics.debug
18 
19 import androidx.compose.runtime.getValue
20 import androidx.compose.runtime.mutableStateOf
21 import androidx.compose.runtime.setValue
22 import com.android.mechanics.MotionValue
23 import com.android.mechanics.impl.DiscontinuityAnimation
24 import com.android.mechanics.spec.InputDirection
25 import com.android.mechanics.spec.SegmentData
26 import com.android.mechanics.spec.SegmentKey
27 import com.android.mechanics.spring.SpringParameters
28 import com.android.mechanics.spring.SpringState
29 import kotlinx.coroutines.DisposableHandle
30 
31 /** Utility to gain inspection access to internal [MotionValue] state. */
32 class DebugInspector
33 internal constructor(
34     initialFrameData: FrameData,
35     initialIsActive: Boolean,
36     initialIsAnimating: Boolean,
37     disposableHandle: DisposableHandle,
<lambda>null38 ) : DisposableHandle by disposableHandle {
39 
40     /** The last completed frame's data. */
41     var frame: FrameData by mutableStateOf(initialFrameData)
42         internal set
43 
44     /** Whether a [MotionValue.keepRunning] coroutine is active currently. */
45     var isActive: Boolean by mutableStateOf(initialIsActive)
46         internal set
47 
48     /**
49      * `false` whenever the [MotionValue.keepRunning] coroutine internally is suspended while no
50      * animation is running and the input is not changing.
51      */
52     var isAnimating: Boolean by mutableStateOf(initialIsAnimating)
53         internal set
54 }
55 
56 /** The input, output and internal state of a [MotionValue] for the frame. */
57 data class FrameData
58 internal constructor(
59     val input: Float,
60     val gestureDirection: InputDirection,
61     val gestureDragOffset: Float,
62     val frameTimeNanos: Long,
63     val springState: SpringState,
64     private val segment: SegmentData,
65     private val animation: DiscontinuityAnimation,
66 ) {
67     val isStable: Boolean
68         get() = springState == SpringState.AtRest
69 
70     val springParameters: SpringParameters
71         get() = animation.springParameters
72 
73     val segmentKey: SegmentKey
74         get() = segment.key
75 
76     val output: Float
77         get() = currentDirectMapped + (animation.targetValue + springState.displacement)
78 
79     val outputTarget: Float
80         get() = currentDirectMapped + animation.targetValue
81 
82     private val currentDirectMapped: Float
83         get() = segment.mapping.map(input) - animation.targetValue
84 }
85