Loading libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt +25 −1 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ class DropTargetManager( private var morphRect: RectF = RectF(0f, 0f, 0f, 0f) private val isLayoutRtl = container.isLayoutRtl private val viewAnimatorsMap = mutableMapOf<View, ValueAnimator>() private var onDropTargetsRemovedAction: Runnable? = null private companion object { const val MORPH_ANIM_DURATION = 250L Loading Loading @@ -111,15 +112,29 @@ class DropTargetManager( /** Called when the drag ended. */ fun onDragEnded() { val dropState = state ?: return startFadeAnimation(dropTargetView, to = 0f) { container.removeView(dropTargetView) } startFadeAnimation(dropTargetView, to = 0f) { container.removeView(dropTargetView) onDropTargetRemoved() } startFadeAnimation(secondDropTargetView, to = 0f) { container.removeView(secondDropTargetView) secondDropTargetView = null onDropTargetRemoved() } dragZoneChangedListener.onDragEnded(dropState.currentDragZone) state = null } /** * Runs the provided action once all drop target views are removed from the container. * If there are no drop target views currently present or being animated, the action will be * executed immediately. */ fun onDropTargetRemoved(action: Runnable) { onDropTargetsRemovedAction = action onDropTargetRemoved() } private fun updateDropTarget() { val dropState = state ?: return val currentDragZone = dropState.currentDragZone Loading Loading @@ -191,6 +206,15 @@ class DropTargetManager( animator.start() } private fun onDropTargetRemoved() { val action = onDropTargetsRemovedAction ?: return if ((0 until container.childCount).any { container.getChildAt(it) is DropTargetView }) { return } onDropTargetsRemovedAction = null action.run() } /** Stores the current drag state. */ private inner class DragState( private val dragZones: List<DragZone>, Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt +46 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.shared.bubbles import android.content.Context import android.graphics.Rect import android.view.View import android.widget.FrameLayout import androidx.core.animation.AnimatorTestRule import androidx.test.core.app.ApplicationProvider.getApplicationContext Loading Loading @@ -469,6 +470,51 @@ class DropTargetManagerTest { ) } @Test fun runOnDropTargetsRemoved_dropTargetViewsAdded_notExecutedUntilAllViewsRemoved() { var runnableExecuted = false val action = Runnable { runnableExecuted = true } dropTargetManager.onDragStarted( DraggedObject.LauncherIcon(bubbleBarHasBubbles = false) {}, listOf(bubbleLeftDragZoneWithSecondDropTarget, bubbleRightDragZoneWithSecondDropTarget) ) assertThat(container.childCount).isEqualTo(DROP_VIEWS_COUNT_FOR_LAUNCHER_ICON) dropTargetManager.onDropTargetRemoved(action) assertThat(runnableExecuted).isFalse() InstrumentationRegistry.getInstrumentation().runOnMainSync { dropTargetManager.onDragEnded() } assertThat(container.childCount).isEqualTo(DROP_VIEWS_COUNT_FOR_LAUNCHER_ICON) assertThat(runnableExecuted).isFalse() InstrumentationRegistry.getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(200) } assertThat(container.childCount).isEqualTo(0) assertThat(runnableExecuted).isTrue() } @Test fun onDropTargetsRemoved_dropTargetViewsAbsent_actionExecuted() { var runnableExecuted = false val action = Runnable { runnableExecuted = true } assertThat(container.childCount).isEqualTo(0) dropTargetManager.onDropTargetRemoved(action) assertThat(runnableExecuted).isTrue() } @Test fun onDropTargetsRemoved_NonDropTargetViewPresent_actionExecuted() { var runnableExecuted = false val action = Runnable { runnableExecuted = true } container.addView(View(context)) assertThat(container.childCount).isEqualTo(1) dropTargetManager.onDropTargetRemoved(action) assertThat(runnableExecuted).isTrue() } private fun verifyDropTargetPosition(rect: Rect) { verifyDropTargetPosition(dropTargetView, rect) } Loading Loading
libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt +25 −1 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ class DropTargetManager( private var morphRect: RectF = RectF(0f, 0f, 0f, 0f) private val isLayoutRtl = container.isLayoutRtl private val viewAnimatorsMap = mutableMapOf<View, ValueAnimator>() private var onDropTargetsRemovedAction: Runnable? = null private companion object { const val MORPH_ANIM_DURATION = 250L Loading Loading @@ -111,15 +112,29 @@ class DropTargetManager( /** Called when the drag ended. */ fun onDragEnded() { val dropState = state ?: return startFadeAnimation(dropTargetView, to = 0f) { container.removeView(dropTargetView) } startFadeAnimation(dropTargetView, to = 0f) { container.removeView(dropTargetView) onDropTargetRemoved() } startFadeAnimation(secondDropTargetView, to = 0f) { container.removeView(secondDropTargetView) secondDropTargetView = null onDropTargetRemoved() } dragZoneChangedListener.onDragEnded(dropState.currentDragZone) state = null } /** * Runs the provided action once all drop target views are removed from the container. * If there are no drop target views currently present or being animated, the action will be * executed immediately. */ fun onDropTargetRemoved(action: Runnable) { onDropTargetsRemovedAction = action onDropTargetRemoved() } private fun updateDropTarget() { val dropState = state ?: return val currentDragZone = dropState.currentDragZone Loading Loading @@ -191,6 +206,15 @@ class DropTargetManager( animator.start() } private fun onDropTargetRemoved() { val action = onDropTargetsRemovedAction ?: return if ((0 until container.childCount).any { container.getChildAt(it) is DropTargetView }) { return } onDropTargetsRemovedAction = null action.run() } /** Stores the current drag state. */ private inner class DragState( private val dragZones: List<DragZone>, Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt +46 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.shared.bubbles import android.content.Context import android.graphics.Rect import android.view.View import android.widget.FrameLayout import androidx.core.animation.AnimatorTestRule import androidx.test.core.app.ApplicationProvider.getApplicationContext Loading Loading @@ -469,6 +470,51 @@ class DropTargetManagerTest { ) } @Test fun runOnDropTargetsRemoved_dropTargetViewsAdded_notExecutedUntilAllViewsRemoved() { var runnableExecuted = false val action = Runnable { runnableExecuted = true } dropTargetManager.onDragStarted( DraggedObject.LauncherIcon(bubbleBarHasBubbles = false) {}, listOf(bubbleLeftDragZoneWithSecondDropTarget, bubbleRightDragZoneWithSecondDropTarget) ) assertThat(container.childCount).isEqualTo(DROP_VIEWS_COUNT_FOR_LAUNCHER_ICON) dropTargetManager.onDropTargetRemoved(action) assertThat(runnableExecuted).isFalse() InstrumentationRegistry.getInstrumentation().runOnMainSync { dropTargetManager.onDragEnded() } assertThat(container.childCount).isEqualTo(DROP_VIEWS_COUNT_FOR_LAUNCHER_ICON) assertThat(runnableExecuted).isFalse() InstrumentationRegistry.getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(200) } assertThat(container.childCount).isEqualTo(0) assertThat(runnableExecuted).isTrue() } @Test fun onDropTargetsRemoved_dropTargetViewsAbsent_actionExecuted() { var runnableExecuted = false val action = Runnable { runnableExecuted = true } assertThat(container.childCount).isEqualTo(0) dropTargetManager.onDropTargetRemoved(action) assertThat(runnableExecuted).isTrue() } @Test fun onDropTargetsRemoved_NonDropTargetViewPresent_actionExecuted() { var runnableExecuted = false val action = Runnable { runnableExecuted = true } container.addView(View(context)) assertThat(container.childCount).isEqualTo(1) dropTargetManager.onDropTargetRemoved(action) assertThat(runnableExecuted).isTrue() } private fun verifyDropTargetPosition(rect: Rect) { verifyDropTargetPosition(dropTargetView, rect) } Loading