diff options
2 files changed, 164 insertions, 15 deletions
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 1a103d345ca7..d72ec90957fc 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.graphics.Rect 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 @@ constructor( ) { 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 @@ constructor( 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 @@ constructor( (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 @@ constructor( } 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 16a234b9e2f2..5b028371be2b 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.WINDOWING_MODE_MULTI_WINDOW 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 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_END_DRAG 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 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { 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 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { transactionSupplier, ) .apply { setSplitScreenController(splitScreenController) } - springHandler = SpringDragToDesktopTransitionHandler( + springHandler = + SpringDragToDesktopTransitionHandler( context, transitions, taskDisplayAreaOrganizer, @@ -80,6 +90,16 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { 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 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { 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 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { ) } } + + private fun systemPropertiesKey(name: String) = + "${SpringDragToDesktopTransitionHandler.SYSTEM_PROPERTIES_GROUP}.$name" } |