Merge "Add drag to desktop transition params customization" into main
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index 1a103d3..d72ec90 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -22,13 +22,15 @@
import android.os.Bundle
import android.os.IBinder
import android.os.SystemClock
+import android.os.SystemProperties
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CLOSE
import android.window.TransitionInfo
import android.window.TransitionInfo.Change
import android.window.TransitionRequestInfo
import android.window.WindowContainerTransaction
-import androidx.dynamicanimation.animation.SpringForce
+import com.android.internal.annotations.VisibleForTesting
+import com.android.internal.dynamicanimation.animation.SpringForce
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE
import com.android.internal.jank.InteractionJankMonitor
@@ -893,13 +895,10 @@
) {
private val positionSpringConfig =
- PhysicsAnimator.SpringConfig(
- SpringForce.STIFFNESS_LOW,
- SpringForce.DAMPING_RATIO_LOW_BOUNCY
- )
+ PhysicsAnimator.SpringConfig(POSITION_SPRING_STIFFNESS, POSITION_SPRING_DAMPING_RATIO)
private val sizeSpringConfig =
- PhysicsAnimator.SpringConfig(SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_NO_BOUNCY)
+ PhysicsAnimator.SpringConfig(SIZE_SPRING_STIFFNESS, SIZE_SPRING_DAMPING_RATIO)
/**
* @return layers in order:
@@ -929,7 +928,7 @@
finishTransaction.hide(homeLeash)
// Setup freeform tasks before animation
state.freeformTaskChanges.forEach { change ->
- val startScale = DRAG_TO_DESKTOP_FREEFORM_TASK_INITIAL_SCALE
+ val startScale = FREEFORM_TASKS_INITIAL_SCALE
val startX =
change.endAbsBounds.left + change.endAbsBounds.width() * (1 - startScale) / 2
val startY =
@@ -994,9 +993,22 @@
(animBounds.width() - startBounds.width()).toFloat() /
(endBounds.width() - startBounds.width())
val animScale = startScale + animFraction * (1 - startScale)
- // Freeform animation starts 50% in the animation
- val freeformAnimFraction = max(animFraction - 0.5f, 0f) * 2f
- val freeformStartScale = DRAG_TO_DESKTOP_FREEFORM_TASK_INITIAL_SCALE
+ // Freeform animation starts with freeform animation offset relative to the commit
+ // animation and plays until the commit animation ends. For instance:
+ // - if the freeform animation offset is `0.0` the freeform tasks animate alongside
+ // - if the freeform animation offset is `0.6` the freeform tasks will
+ // start animating at 60% fraction of the commit animation and will complete when
+ // the commit animation fraction is 100%.
+ // - if the freeform animation offset is `1.0` then freeform tasks will appear
+ // without animation after commit animation finishes.
+ val freeformAnimFraction =
+ if (FREEFORM_TASKS_ANIM_OFFSET != 1f) {
+ max(animFraction - FREEFORM_TASKS_ANIM_OFFSET, 0f) /
+ (1f - FREEFORM_TASKS_ANIM_OFFSET)
+ } else {
+ 0f
+ }
+ val freeformStartScale = FREEFORM_TASKS_INITIAL_SCALE
val freeformAnimScale =
freeformStartScale + freeformAnimFraction * (1 - freeformStartScale)
tx.apply {
@@ -1032,10 +1044,53 @@
}
companion object {
+ /** The freeform tasks initial scale when committing the drag-to-desktop gesture. */
+ private val FREEFORM_TASKS_INITIAL_SCALE =
+ propertyValue("freeform_tasks_initial_scale", scale = 100f, default = 0.9f)
+
+ /** The freeform tasks animation offset relative to the whole animation duration. */
+ private val FREEFORM_TASKS_ANIM_OFFSET =
+ propertyValue("freeform_tasks_anim_offset", scale = 100f, default = 0.5f)
+
+ /** The spring force stiffness used to place the window into the final position. */
+ private val POSITION_SPRING_STIFFNESS =
+ propertyValue("position_stiffness", default = SpringForce.STIFFNESS_LOW)
+
+ /** The spring force damping ratio used to place the window into the final position. */
+ private val POSITION_SPRING_DAMPING_RATIO =
+ propertyValue(
+ "position_damping_ratio",
+ scale = 100f,
+ default = SpringForce.DAMPING_RATIO_LOW_BOUNCY
+ )
+
+ /** The spring force stiffness used to resize the window into the final bounds. */
+ private val SIZE_SPRING_STIFFNESS =
+ propertyValue("size_stiffness", default = SpringForce.STIFFNESS_LOW)
+
+ /** The spring force damping ratio used to resize the window into the final bounds. */
+ private val SIZE_SPRING_DAMPING_RATIO =
+ propertyValue(
+ "size_damping_ratio",
+ scale = 100f,
+ default = SpringForce.DAMPING_RATIO_NO_BOUNCY
+ )
+
+ /** Drag to desktop transition system properties group. */
+ @VisibleForTesting
+ const val SYSTEM_PROPERTIES_GROUP = "persist.wm.debug.desktop_transitions.drag_to_desktop"
+
/**
- * The initial scale of the freeform tasks in the animation to commit the drag-to-desktop
- * gesture.
+ * Drag to desktop transition system property value with [name].
+ *
+ * @param scale an optional scale to apply to the value read from the system property.
+ * @param default a default value to return if the system property isn't set.
*/
- private const val DRAG_TO_DESKTOP_FREEFORM_TASK_INITIAL_SCALE = 0.9f
+ @VisibleForTesting
+ fun propertyValue(name: String, scale: Float = 1f, default: Float = 0f): Float =
+ SystemProperties.getInt(
+ /* key= */ "$SYSTEM_PROPERTIES_GROUP.$name",
+ /* def= */ (default * scale).toInt()
+ ) / scale
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index 16a234b..5b02837 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -8,6 +8,7 @@
import android.app.WindowConfiguration.WindowingMode
import android.graphics.PointF
import android.os.IBinder
+import android.os.SystemProperties
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.SurfaceControl
@@ -16,6 +17,7 @@
import android.window.TransitionInfo.FLAG_IS_WALLPAPER
import android.window.WindowContainerTransaction
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.internal.jank.InteractionJankMonitor
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTestCase
@@ -29,19 +31,24 @@
import com.android.wm.shell.transition.Transitions.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP
import com.android.wm.shell.windowdecor.MoveToDesktopAnimator
import java.util.function.Supplier
+import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
+import org.mockito.MockitoSession
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyZeroInteractions
import org.mockito.kotlin.whenever
+import org.mockito.quality.Strictness
/** Tests of [DragToDesktopTransitionHandler]. */
@SmallTest
@@ -61,10 +68,12 @@
private lateinit var defaultHandler: DragToDesktopTransitionHandler
private lateinit var springHandler: SpringDragToDesktopTransitionHandler
+ private lateinit var mockitoSession: MockitoSession
@Before
fun setUp() {
- defaultHandler = DefaultDragToDesktopTransitionHandler(
+ defaultHandler =
+ DefaultDragToDesktopTransitionHandler(
context,
transitions,
taskDisplayAreaOrganizer,
@@ -72,7 +81,8 @@
transactionSupplier,
)
.apply { setSplitScreenController(splitScreenController) }
- springHandler = SpringDragToDesktopTransitionHandler(
+ springHandler =
+ SpringDragToDesktopTransitionHandler(
context,
transitions,
taskDisplayAreaOrganizer,
@@ -80,6 +90,16 @@
transactionSupplier,
)
.apply { setSplitScreenController(splitScreenController) }
+ mockitoSession =
+ ExtendedMockito.mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .mockStatic(SystemProperties::class.java)
+ .startMocking()
+ }
+
+ @After
+ fun tearDown() {
+ mockitoSession.finishMocking()
}
@Test
@@ -357,6 +377,77 @@
verify(finishCallback).onTransitionFinished(null)
}
+ @Test
+ fun propertyValue_returnsSystemPropertyValue() {
+ val name = "property_name"
+ val value = 10f
+
+ whenever(SystemProperties.getInt(eq(systemPropertiesKey(name)), anyInt()))
+ .thenReturn(value.toInt())
+
+ assertEquals(
+ "Expects to return system properties stored value",
+ /* expected= */ value,
+ /* actual= */ SpringDragToDesktopTransitionHandler.propertyValue(name)
+ )
+ }
+
+ @Test
+ fun propertyValue_withScale_returnsScaledSystemPropertyValue() {
+ val name = "property_name"
+ val value = 10f
+ val scale = 100f
+
+ whenever(SystemProperties.getInt(eq(systemPropertiesKey(name)), anyInt()))
+ .thenReturn(value.toInt())
+
+ assertEquals(
+ "Expects to return scaled system properties stored value",
+ /* expected= */ value / scale,
+ /* actual= */ SpringDragToDesktopTransitionHandler.propertyValue(name, scale = scale)
+ )
+ }
+
+ @Test
+ fun propertyValue_notSet_returnsDefaultValue() {
+ val name = "property_name"
+ val defaultValue = 50f
+
+ whenever(SystemProperties.getInt(eq(systemPropertiesKey(name)), eq(defaultValue.toInt())))
+ .thenReturn(defaultValue.toInt())
+
+ assertEquals(
+ "Expects to return the default value",
+ /* expected= */ defaultValue,
+ /* actual= */ SpringDragToDesktopTransitionHandler.propertyValue(
+ name,
+ default = defaultValue
+ )
+ )
+ }
+
+ @Test
+ fun propertyValue_withScaleNotSet_returnsDefaultValue() {
+ val name = "property_name"
+ val defaultValue = 0.5f
+ val scale = 100f
+ // Default value is multiplied when provided as a default value for [SystemProperties]
+ val scaledDefault = (defaultValue * scale).toInt()
+
+ whenever(SystemProperties.getInt(eq(systemPropertiesKey(name)), eq(scaledDefault)))
+ .thenReturn(scaledDefault)
+
+ assertEquals(
+ "Expects to return the default value",
+ /* expected= */ defaultValue,
+ /* actual= */ SpringDragToDesktopTransitionHandler.propertyValue(
+ name,
+ default = defaultValue,
+ scale = scale
+ )
+ )
+ }
+
private fun startDrag(
handler: DragToDesktopTransitionHandler,
task: RunningTaskInfo = createTask(),
@@ -462,4 +553,7 @@
)
}
}
+
+ private fun systemPropertiesKey(name: String) =
+ "${SpringDragToDesktopTransitionHandler.SYSTEM_PROPERTIES_GROUP}.$name"
}