summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleDropTargetBoundsProvider.kt29
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java74
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt43
6 files changed, 138 insertions, 33 deletions
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleDropTargetBoundsProvider.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleDropTargetBoundsProvider.kt
new file mode 100644
index 000000000000..9bee11a92430
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleDropTargetBoundsProvider.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.shared.bubbles
+
+import android.graphics.Rect
+
+/**
+ * Provide bounds for Bubbles drop targets that are shown when dragging over drag zones
+ */
+interface BubbleDropTargetBoundsProvider {
+ /**
+ * Get bubble bar expanded view visual drop target bounds on screen
+ */
+ fun getBubbleBarExpandedViewDropTargetBounds(onLeft: Boolean): Rect
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 436e479796ac..2c81945ffdbe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -116,6 +116,7 @@ import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import com.android.wm.shell.shared.bubbles.BubbleBarUpdate;
+import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider;
import com.android.wm.shell.shared.bubbles.DeviceConfig;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
import com.android.wm.shell.sysui.ShellCommandHandler;
@@ -925,6 +926,11 @@ public class BubbleController implements ConfigurationChangeListener,
return mBubblePositioner;
}
+ /** Provides bounds for drag zone drop targets */
+ public BubbleDropTargetBoundsProvider getBubbleDropTargetBoundsProvider() {
+ return mBubblePositioner;
+ }
+
BubbleIconFactory getIconFactory() {
return mBubbleIconFactory;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 8cf3f7afd46a..5273a7cf2432 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -27,19 +27,21 @@ import android.graphics.RectF;
import android.view.Surface;
import android.view.WindowManager;
+import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconNormalizer;
import com.android.wm.shell.R;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider;
import com.android.wm.shell.shared.bubbles.DeviceConfig;
/**
* Keeps track of display size, configuration, and specific bubble sizes. One place for all
* placement and positioning calculations to refer to.
*/
-public class BubblePositioner {
+public class BubblePositioner implements BubbleDropTargetBoundsProvider {
/** The screen edge the bubble stack is pinned to */
public enum StackPinnedEdge {
@@ -100,6 +102,7 @@ public class BubblePositioner {
private int mManageButtonHeight;
private int mOverflowHeight;
private int mMinimumFlyoutWidthLargeScreen;
+ private int mBubbleBarExpandedViewDropTargetPadding;
private PointF mRestingStackPosition;
@@ -164,6 +167,8 @@ public class BubblePositioner {
res.getDimensionPixelSize(R.dimen.bubble_bar_expanded_view_width),
mPositionRect.width() - 2 * mExpandedViewPadding
);
+ mBubbleBarExpandedViewDropTargetPadding = res.getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_drop_target_padding);
if (mShowingInBubbleBar) {
mExpandedViewLargeScreenWidth = mExpandedViewBubbleBarWidth;
@@ -965,4 +970,14 @@ public class BubblePositioner {
int top = getExpandedViewBottomForBubbleBar() - height;
out.offsetTo(left, top);
}
+
+ @NonNull
+ @Override
+ public Rect getBubbleBarExpandedViewDropTargetBounds(boolean onLeft) {
+ Rect bounds = new Rect();
+ getBubbleBarExpandedViewBounds(onLeft, false, bounds);
+ bounds.inset(mBubbleBarExpandedViewDropTargetPadding,
+ mBubbleBarExpandedViewDropTargetPadding);
+ return bounds;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index 27ccb8bc71fe..27aed17762ff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -60,6 +60,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
+import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
/**
@@ -119,6 +120,7 @@ public class DesktopModeVisualIndicator {
private final RootTaskDisplayAreaOrganizer mRootTdaOrganizer;
private final ActivityManager.RunningTaskInfo mTaskInfo;
private final SurfaceControl mTaskSurface;
+ private final @Nullable BubbleDropTargetBoundsProvider mBubbleBoundsProvider;
private SurfaceControl mLeash;
private final SyncTransactionQueue mSyncQueue;
@@ -133,13 +135,15 @@ public class DesktopModeVisualIndicator {
ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController,
Context context, SurfaceControl taskSurface,
RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer,
- DragStartState dragStartState) {
+ DragStartState dragStartState,
+ @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) {
mSyncQueue = syncQueue;
mTaskInfo = taskInfo;
mDisplayController = displayController;
mContext = context;
mTaskSurface = taskSurface;
mRootTdaOrganizer = taskDisplayAreaOrganizer;
+ mBubbleBoundsProvider = bubbleBoundsProvider;
mCurrentType = NO_INDICATOR;
mDragStartState = dragStartState;
}
@@ -329,6 +333,11 @@ public class DesktopModeVisualIndicator {
});
}
+ @VisibleForTesting
+ Rect getIndicatorBounds() {
+ return mView.getBackground().getBounds();
+ }
+
/**
* Fade indicator in as provided type. Animator fades it in while expanding the bounds outwards.
*/
@@ -336,7 +345,8 @@ public class DesktopModeVisualIndicator {
mView.setBackgroundResource(R.drawable.desktop_windowing_transition_background);
final VisualIndicatorAnimator animator = VisualIndicatorAnimator
.fadeBoundsIn(mView, type,
- mDisplayController.getDisplayLayout(mTaskInfo.displayId));
+ mDisplayController.getDisplayLayout(mTaskInfo.displayId),
+ mBubbleBoundsProvider);
animator.start();
mCurrentType = type;
}
@@ -355,7 +365,8 @@ public class DesktopModeVisualIndicator {
}
final VisualIndicatorAnimator animator = VisualIndicatorAnimator
.fadeBoundsOut(mView, mCurrentType,
- mDisplayController.getDisplayLayout(mTaskInfo.displayId));
+ mDisplayController.getDisplayLayout(mTaskInfo.displayId),
+ mBubbleBoundsProvider);
animator.start();
if (finishCallback != null) {
animator.addListener(new AnimatorListenerAdapter() {
@@ -383,7 +394,7 @@ public class DesktopModeVisualIndicator {
} else {
final VisualIndicatorAnimator animator = VisualIndicatorAnimator.animateIndicatorType(
mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId), mCurrentType,
- newType);
+ newType, mBubbleBoundsProvider);
mCurrentType = newType;
animator.start();
}
@@ -438,8 +449,9 @@ public class DesktopModeVisualIndicator {
}
private static VisualIndicatorAnimator fadeBoundsIn(
- @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout) {
- final Rect endBounds = getIndicatorBounds(displayLayout, type);
+ @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout,
+ @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) {
+ final Rect endBounds = getIndicatorBounds(displayLayout, type, bubbleBoundsProvider);
final Rect startBounds = getMinBounds(endBounds);
view.getBackground().setBounds(startBounds);
@@ -451,8 +463,9 @@ public class DesktopModeVisualIndicator {
}
private static VisualIndicatorAnimator fadeBoundsOut(
- @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout) {
- final Rect startBounds = getIndicatorBounds(displayLayout, type);
+ @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout,
+ @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) {
+ final Rect startBounds = getIndicatorBounds(displayLayout, type, bubbleBoundsProvider);
final Rect endBounds = getMinBounds(startBounds);
view.getBackground().setBounds(startBounds);
@@ -467,16 +480,19 @@ public class DesktopModeVisualIndicator {
* Create animator for visual indicator changing type (i.e., fullscreen to freeform,
* freeform to split, etc.)
*
- * @param view the view for this indicator
- * @param displayLayout information about the display the transitioning task is currently on
- * @param origType the original indicator type
- * @param newType the new indicator type
+ * @param view the view for this indicator
+ * @param displayLayout information about the display the transitioning task is
+ * currently on
+ * @param origType the original indicator type
+ * @param newType the new indicator type
+ * @param bubbleBoundsProvider provides bounds for bubbles indicators
*/
private static VisualIndicatorAnimator animateIndicatorType(@NonNull View view,
- @NonNull DisplayLayout displayLayout, IndicatorType origType,
- IndicatorType newType) {
- final Rect startBounds = getIndicatorBounds(displayLayout, origType);
- final Rect endBounds = getIndicatorBounds(displayLayout, newType);
+ @NonNull DisplayLayout displayLayout, IndicatorType origType, IndicatorType newType,
+ @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) {
+ final Rect startBounds = getIndicatorBounds(displayLayout, origType,
+ bubbleBoundsProvider);
+ final Rect endBounds = getIndicatorBounds(displayLayout, newType, bubbleBoundsProvider);
final VisualIndicatorAnimator animator = new VisualIndicatorAnimator(
view, startBounds, endBounds);
animator.setInterpolator(new DecelerateInterpolator());
@@ -485,7 +501,8 @@ public class DesktopModeVisualIndicator {
}
/** Calculates the bounds the indicator should have when fully faded in. */
- private static Rect getIndicatorBounds(DisplayLayout layout, IndicatorType type) {
+ private static Rect getIndicatorBounds(DisplayLayout layout, IndicatorType type,
+ @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) {
final Rect desktopStableBounds = new Rect();
layout.getStableBounds(desktopStableBounds);
final int padding = desktopStableBounds.top;
@@ -514,20 +531,17 @@ public class DesktopModeVisualIndicator {
desktopStableBounds.width() - padding,
desktopStableBounds.height());
case TO_BUBBLE_LEFT_INDICATOR:
- // TODO(b/388851898): define based on bubble size on the device
- return new Rect(
- padding,
- desktopStableBounds.height() / 2 - padding,
- desktopStableBounds.width() / 2 - padding,
- desktopStableBounds.height());
+ if (bubbleBoundsProvider == null) {
+ return new Rect();
+ }
+ return bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(
+ /* onLeft= */ true);
case TO_BUBBLE_RIGHT_INDICATOR:
- // TODO(b/388851898): define based on bubble size on the device
- return new Rect(
- desktopStableBounds.width() / 2 + padding,
- desktopStableBounds.height() / 2 - padding,
- desktopStableBounds.width() - padding,
- desktopStableBounds.height()
- );
+ if (bubbleBoundsProvider == null) {
+ return new Rect();
+ }
+ return bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(
+ /* onLeft= */ false);
default:
throw new IllegalArgumentException("Invalid indicator type provided.");
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index cf724f5031a6..0d32acd6b068 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -150,6 +150,7 @@ import java.util.Optional
import java.util.concurrent.Executor
import java.util.concurrent.TimeUnit
import java.util.function.Consumer
+import kotlin.jvm.optionals.getOrNull
/** Handles moving tasks in and out of desktop */
class DesktopTasksController(
@@ -2706,6 +2707,7 @@ class DesktopTasksController(
taskSurface,
rootTaskDisplayAreaOrganizer,
dragStartState,
+ bubbleController.getOrNull()?.bubbleDropTargetBoundsProvider,
)
if (visualIndicator == null) visualIndicator = indicator
return indicator.updateIndicatorType(PointF(inputX, taskTop))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
index c5db2c592aa0..a6575535faee 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
@@ -16,11 +16,11 @@
package com.android.wm.shell.desktopmode
+import android.animation.AnimatorTestRule
import android.app.ActivityManager.RunningTaskInfo
import android.graphics.PointF
import android.graphics.Rect
import android.platform.test.annotations.EnableFlags
-import android.platform.test.flag.junit.SetFlagsRule
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.SurfaceControl
@@ -34,6 +34,7 @@ import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -56,7 +57,7 @@ import org.mockito.kotlin.whenever
@EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
class DesktopModeVisualIndicatorTest : ShellTestCase() {
- @JvmField @Rule val setFlagsRule = SetFlagsRule()
+ @JvmField @Rule val animatorTestRule = AnimatorTestRule(this)
@JvmField
@Rule
@@ -69,6 +70,7 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
@Mock private lateinit var taskSurface: SurfaceControl
@Mock private lateinit var taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
@Mock private lateinit var displayLayout: DisplayLayout
+ @Mock private lateinit var bubbleBoundsProvider: BubbleDropTargetBoundsProvider
private lateinit var visualIndicator: DesktopModeVisualIndicator
@@ -80,6 +82,8 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
whenever(displayLayout.stableInsets()).thenReturn(STABLE_INSETS)
whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout)
whenever(displayController.getDisplay(anyInt())).thenReturn(mContext.display)
+ whenever(bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(any()))
+ .thenReturn(Rect())
taskInfo = DesktopTestHelpers.createFullscreenTask()
}
@@ -292,6 +296,40 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
assertThat(result).isEqualTo(DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR)
}
+ @Test
+ @EnableFlags(
+ com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_TO_FULLSCREEN,
+ com.android.wm.shell.Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE,
+ )
+ fun testBubbleLeftVisualIndicatorSize() {
+ val dropTargetBounds = Rect(100, 100, 500, 1500)
+ whenever(bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(/* onLeft= */ true))
+ .thenReturn(dropTargetBounds)
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN)
+ visualIndicator.updateIndicatorType(PointF(100f, 1500f))
+
+ animatorTestRule.advanceTimeBy(200)
+
+ assertThat(visualIndicator.indicatorBounds).isEqualTo(dropTargetBounds)
+ }
+
+ @Test
+ @EnableFlags(
+ com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_TO_FULLSCREEN,
+ com.android.wm.shell.Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE,
+ )
+ fun testBubbleRightVisualIndicatorSize() {
+ val dropTargetBounds = Rect(1900, 100, 2300, 1500)
+ whenever(bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(/* onLeft= */ false))
+ .thenReturn(dropTargetBounds)
+ createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN)
+ visualIndicator.updateIndicatorType(PointF(2300f, 1500f))
+
+ animatorTestRule.advanceTimeBy(200)
+
+ assertThat(visualIndicator.indicatorBounds).isEqualTo(dropTargetBounds)
+ }
+
private fun createVisualIndicator(dragStartState: DesktopModeVisualIndicator.DragStartState) {
visualIndicator =
DesktopModeVisualIndicator(
@@ -302,6 +340,7 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
taskSurface,
taskDisplayAreaOrganizer,
dragStartState,
+ bubbleBoundsProvider,
)
}