Added orientation utilities to convert: Offset/Velocity to/from Float

Note: this is a refactor that introduces no new logic

Test: atest SceneGestureHandlerTest
Bug: 291053278
Flag: NA
Change-Id: I1fb9a8fe64e9a7261e33b6ce61869770713c16c3
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
index 838cb3b..664b509 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
@@ -28,7 +28,6 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.unit.Velocity
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.round
 import com.android.compose.nestedscroll.PriorityNestedScrollConnection
@@ -541,24 +540,6 @@
 ) : NestedScrollHandler {
     override val connection: PriorityNestedScrollConnection = nestedScrollConnection()
 
-    private fun Offset.toAmount() =
-        when (gestureHandler.orientation) {
-            Orientation.Horizontal -> x
-            Orientation.Vertical -> y
-        }
-
-    private fun Velocity.toAmount() =
-        when (gestureHandler.orientation) {
-            Orientation.Horizontal -> x
-            Orientation.Vertical -> y
-        }
-
-    private fun Float.toOffset() =
-        when (gestureHandler.orientation) {
-            Orientation.Horizontal -> Offset(x = this, y = 0f)
-            Orientation.Vertical -> Offset(x = 0f, y = this)
-        }
-
     private fun nestedScrollConnection(): PriorityNestedScrollConnection {
         // If we performed a long gesture before entering priority mode, we would have to avoid
         // moving on to the next scene.
@@ -596,13 +577,12 @@
         }
 
         return PriorityNestedScrollConnection(
+            orientation = gestureHandler.orientation,
             canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
-                canChangeScene = offsetBeforeStart == Offset.Zero
+                canChangeScene = offsetBeforeStart == 0f
 
                 val canInterceptSwipeTransition =
-                    canChangeScene &&
-                        gestureHandler.isDrivingTransition &&
-                        offsetAvailable.toAmount() != 0f
+                    canChangeScene && gestureHandler.isDrivingTransition && offsetAvailable != 0f
                 if (!canInterceptSwipeTransition) return@PriorityNestedScrollConnection false
 
                 val progress = gestureHandler.swipeTransition.progress
@@ -623,15 +603,14 @@
                 !shouldSnapToIdle
             },
             canStartPostScroll = { offsetAvailable, offsetBeforeStart ->
-                val amount = offsetAvailable.toAmount()
                 val behavior: NestedScrollBehavior =
                     when {
-                        amount > 0 -> startBehavior
-                        amount < 0 -> endBehavior
+                        offsetAvailable > 0f -> startBehavior
+                        offsetAvailable < 0f -> endBehavior
                         else -> return@PriorityNestedScrollConnection false
                     }
 
-                val isZeroOffset = offsetBeforeStart == Offset.Zero
+                val isZeroOffset = offsetBeforeStart == 0f
 
                 when (behavior) {
                     NestedScrollBehavior.DuringTransitionBetweenScenes -> {
@@ -640,30 +619,29 @@
                     }
                     NestedScrollBehavior.EdgeNoOverscroll -> {
                         canChangeScene = isZeroOffset
-                        isZeroOffset && hasNextScene(amount)
+                        isZeroOffset && hasNextScene(offsetAvailable)
                     }
                     NestedScrollBehavior.EdgeWithOverscroll -> {
                         canChangeScene = isZeroOffset
-                        hasNextScene(amount)
+                        hasNextScene(offsetAvailable)
                     }
                     NestedScrollBehavior.Always -> {
                         canChangeScene = true
-                        hasNextScene(amount)
+                        hasNextScene(offsetAvailable)
                     }
                 }
             },
             canStartPostFling = { velocityAvailable ->
-                val amount = velocityAvailable.toAmount()
                 val behavior: NestedScrollBehavior =
                     when {
-                        amount > 0 -> startBehavior
-                        amount < 0 -> endBehavior
+                        velocityAvailable > 0f -> startBehavior
+                        velocityAvailable < 0f -> endBehavior
                         else -> return@PriorityNestedScrollConnection false
                     }
 
                 // We could start an overscroll animation
                 canChangeScene = false
-                behavior.canStartOnPostFling && hasNextScene(amount)
+                behavior.canStartOnPostFling && hasNextScene(velocityAvailable)
             },
             canContinueScroll = { true },
             onStart = {
@@ -676,24 +654,22 @@
             },
             onScroll = { offsetAvailable ->
                 if (gestureHandler.gestureWithPriority != this) {
-                    return@PriorityNestedScrollConnection Offset.Zero
+                    return@PriorityNestedScrollConnection 0f
                 }
 
-                val amount = offsetAvailable.toAmount()
-
                 // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
                 // initiated in a nested child.
-                gestureHandler.onDrag(amount)
+                gestureHandler.onDrag(offsetAvailable)
 
-                amount.toOffset()
+                offsetAvailable
             },
             onStop = { velocityAvailable ->
                 if (gestureHandler.gestureWithPriority != this) {
-                    return@PriorityNestedScrollConnection Velocity.Zero
+                    return@PriorityNestedScrollConnection 0f
                 }
 
                 gestureHandler.onDragStopped(
-                    velocity = velocityAvailable.toAmount(),
+                    velocity = velocityAvailable,
                     canChangeScene = canChangeScene
                 )
 
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
index 824c10b..a5fd1bf 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
@@ -16,10 +16,12 @@
 
 package com.android.compose.nestedscroll
 
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 import androidx.compose.ui.input.nestedscroll.NestedScrollSource
 import androidx.compose.ui.unit.Velocity
+import com.android.compose.ui.util.SpaceVectorConverter
 
 /**
  * This [NestedScrollConnection] waits for a child to scroll ([onPreScroll] or [onPostScroll]), and
@@ -147,3 +149,35 @@
         return onStop(velocity)
     }
 }
+
+fun PriorityNestedScrollConnection(
+    orientation: Orientation,
+    canStartPreScroll: (offsetAvailable: Float, offsetBeforeStart: Float) -> Boolean,
+    canStartPostScroll: (offsetAvailable: Float, offsetBeforeStart: Float) -> Boolean,
+    canStartPostFling: (velocityAvailable: Float) -> Boolean,
+    canContinueScroll: () -> Boolean,
+    onStart: () -> Unit,
+    onScroll: (offsetAvailable: Float) -> Float,
+    onStop: (velocityAvailable: Float) -> Float,
+) =
+    with(SpaceVectorConverter(orientation)) {
+        PriorityNestedScrollConnection(
+            canStartPreScroll = { offsetAvailable: Offset, offsetBeforeStart: Offset ->
+                canStartPreScroll(offsetAvailable.toFloat(), offsetBeforeStart.toFloat())
+            },
+            canStartPostScroll = { offsetAvailable: Offset, offsetBeforeStart: Offset ->
+                canStartPostScroll(offsetAvailable.toFloat(), offsetBeforeStart.toFloat())
+            },
+            canStartPostFling = { velocityAvailable: Velocity ->
+                canStartPostFling(velocityAvailable.toFloat())
+            },
+            canContinueScroll = canContinueScroll,
+            onStart = onStart,
+            onScroll = { offsetAvailable: Offset ->
+                onScroll(offsetAvailable.toFloat()).toOffset()
+            },
+            onStop = { velocityAvailable: Velocity ->
+                onStop(velocityAvailable.toFloat()).toVelocity()
+            },
+        )
+    }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/ui/util/SpaceVectorConverter.kt b/packages/SystemUI/compose/scene/src/com/android/compose/ui/util/SpaceVectorConverter.kt
new file mode 100644
index 0000000..a13e944
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/ui/util/SpaceVectorConverter.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.compose.ui.util
+
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.unit.Velocity
+
+interface SpaceVectorConverter {
+    fun Offset.toFloat(): Float
+    fun Velocity.toFloat(): Float
+    fun Float.toOffset(): Offset
+    fun Float.toVelocity(): Velocity
+}
+
+fun SpaceVectorConverter(orientation: Orientation) =
+    when (orientation) {
+        Orientation.Horizontal -> HorizontalConverter
+        Orientation.Vertical -> VerticalConverter
+    }
+
+private val HorizontalConverter =
+    object : SpaceVectorConverter {
+        override fun Offset.toFloat() = x
+        override fun Velocity.toFloat() = x
+        override fun Float.toOffset() = Offset(this, 0f)
+        override fun Float.toVelocity() = Velocity(this, 0f)
+    }
+
+private val VerticalConverter =
+    object : SpaceVectorConverter {
+        override fun Offset.toFloat() = y
+        override fun Velocity.toFloat() = y
+        override fun Float.toOffset() = Offset(0f, this)
+        override fun Float.toVelocity() = Velocity(0f, this)
+    }