Loading libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt +19 −2 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.wm.shell.taskview.TaskView import com.android.wm.shell.taskview.TaskViewTaskController import com.google.common.truth.Truth.assertThat import com.google.common.util.concurrent.MoreExecutors.directExecutor Loading @@ -30,6 +29,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.verify @SmallTest @RunWith(AndroidJUnit4::class) Loading @@ -37,10 +38,11 @@ class BubbleTaskViewTest { private lateinit var bubbleTaskView: BubbleTaskView private val context = ApplicationProvider.getApplicationContext<Context>() private lateinit var taskView: TaskView @Before fun setUp() { val taskView = TaskView(context, mock<TaskViewTaskController>()) taskView = mock() bubbleTaskView = BubbleTaskView(taskView, directExecutor()) } Loading Loading @@ -72,4 +74,19 @@ class BubbleTaskViewTest { assertThat(actualTaskId).isEqualTo(123) assertThat(actualComponentName).isEqualTo(componentName) } @Test fun cleanup_invalidTaskId_doesNotRemoveTask() { bubbleTaskView.cleanup() verify(taskView, never()).removeTask() } @Test fun cleanup_validTaskId_removesTask() { val componentName = ComponentName(context, "TestClass") bubbleTaskView.listener.onTaskCreated(123, componentName) bubbleTaskView.cleanup() verify(taskView).removeTask() } } libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +44 −1 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ import com.android.launcher3.icons.BubbleIconFactory; import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView; import com.android.wm.shell.bubbles.bar.BubbleBarLayerView; import com.android.wm.shell.common.bubbles.BubbleInfo; import com.android.wm.shell.taskview.TaskView; import com.android.wm.shell.taskview.TaskViewTaskController; import java.io.PrintWriter; import java.util.List; Loading Loading @@ -105,6 +107,8 @@ public class Bubble implements BubbleViewProvider { private BubbleExpandedView mExpandedView; @Nullable private BubbleBarExpandedView mBubbleBarExpandedView; @Nullable private BubbleTaskView mBubbleTaskView; private BubbleViewInfoTask mInflationTask; private boolean mInflateSynchronously; Loading Loading @@ -393,6 +397,21 @@ public class Bubble implements BubbleViewProvider { return mTitle; } /** * Returns the existing {@link #mBubbleTaskView} if it's not {@code null}. Otherwise a new * instance of {@link BubbleTaskView} is created. */ public BubbleTaskView getOrCreateBubbleTaskView(Context context, BubbleController controller) { if (mBubbleTaskView == null) { TaskViewTaskController taskViewTaskController = new TaskViewTaskController(context, controller.getTaskOrganizer(), controller.getTaskViewTransitions(), controller.getSyncTransactionQueue()); TaskView taskView = new TaskView(context, taskViewTaskController); mBubbleTaskView = new BubbleTaskView(taskView, controller.getMainExecutor()); } return mBubbleTaskView; } /** * @return the ShortcutInfo id if it exists, or the metadata shortcut id otherwise. */ Loading @@ -415,6 +434,10 @@ public class Bubble implements BubbleViewProvider { * the bubble. */ void cleanupExpandedView() { cleanupExpandedView(true); } private void cleanupExpandedView(boolean cleanupTaskView) { if (mExpandedView != null) { mExpandedView.cleanUpExpandedState(); mExpandedView = null; Loading @@ -423,17 +446,37 @@ public class Bubble implements BubbleViewProvider { mBubbleBarExpandedView.cleanUpExpandedState(); mBubbleBarExpandedView = null; } if (cleanupTaskView) { cleanupTaskView(); } if (mIntent != null) { mIntent.unregisterCancelListener(mIntentCancelListener); } mIntentActive = false; } private void cleanupTaskView() { if (mBubbleTaskView != null) { mBubbleTaskView.cleanup(); mBubbleTaskView = null; } } /** * Call when all the views should be removed/cleaned up. */ void cleanupViews() { cleanupExpandedView(); cleanupViews(true); } /** * Call when all the views should be removed/cleaned up. * * <p>If we're switching between bar and floating modes, pass {@code false} on * {@code cleanupTaskView} to avoid recreating it in the new mode. */ void cleanupViews(boolean cleanupTaskView) { cleanupExpandedView(cleanupTaskView); mIconView = null; } Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +3 −33 Original line number Diff line number Diff line Loading @@ -1366,8 +1366,9 @@ public class BubbleController implements ConfigurationChangeListener, mStackView.resetOverflowView(); mStackView.removeAllViews(); } // cleanup existing bubble views so they can be recreated later if needed. mBubbleData.getBubbles().forEach(Bubble::cleanupViews); // cleanup existing bubble views so they can be recreated later if needed, but retain // TaskView. mBubbleData.getBubbles().forEach(b -> b.cleanupViews(/* cleanupTaskView= */ false)); // remove the current bubble container from window manager, null it out, and create a new // container based on the current mode. Loading Loading @@ -1478,7 +1479,6 @@ public class BubbleController implements ConfigurationChangeListener, * <p> * Must be called from the main thread. */ @VisibleForTesting @MainThread public void removeBubble(String key, int reason) { if (mBubbleData.hasAnyBubbleWithKey(key)) { Loading @@ -1486,36 +1486,6 @@ public class BubbleController implements ConfigurationChangeListener, } } // TODO(b/316358859): remove this method after task views are shared across modes /** * Removes the bubble with the given key after task removal, unless the task was removed as * a result of mode switching, in which case, the bubble isn't removed because it will be * re-inflated for the new mode. */ @MainThread public void removeFloatingBubbleAfterTaskRemoval(String key, int reason) { // if we're floating remove the bubble. otherwise, we're here because the task was removed // after switching modes. See b/316358859 if (!isShowingAsBubbleBar()) { removeBubble(key, reason); } } // TODO(b/316358859): remove this method after task views are shared across modes /** * Removes the bubble with the given key after task removal, unless the task was removed as * a result of mode switching, in which case, the bubble isn't removed because it will be * re-inflated for the new mode. */ @MainThread public void removeBarBubbleAfterTaskRemoval(String key, int reason) { // if we're showing as bubble bar remove the bubble. otherwise, we're here because the task // was removed after switching modes. See b/316358859 if (isShowingAsBubbleBar()) { removeBubble(key, reason); } } /** * Removes all the bubbles. * <p> Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +2 −27 Original line number Diff line number Diff line Loading @@ -27,12 +27,10 @@ import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPAND import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT; import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS; import android.annotation.NonNull; import android.annotation.SuppressLint; import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; Loading @@ -49,7 +47,6 @@ import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.ShapeDrawable; import android.os.RemoteException; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.IntProperty; Loading Loading @@ -311,8 +308,7 @@ public class BubbleExpandedView extends LinearLayout { + " bubble=" + getBubbleKey()); } if (mBubble != null) { mController.removeFloatingBubbleAfterTaskRemoval( mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED); mController.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED); } if (mTaskView != null) { // Release the surface Loading Loading @@ -1105,32 +1101,11 @@ public class BubbleExpandedView extends LinearLayout { return ((LinearLayout.LayoutParams) mManageButton.getLayoutParams()).getMarginStart(); } /** * Cleans up anything related to the task. The TaskView itself is released after the task * has been removed. * * If this view should be reused after this method is called, then * {@link #initialize(BubbleController, BubbleStackView, boolean, BubbleTaskView)} * must be invoked first. */ /** Hide the task view. */ public void cleanUpExpandedState() { if (DEBUG_BUBBLE_EXPANDED_VIEW) { Log.d(TAG, "cleanUpExpandedState: bubble=" + getBubbleKey() + " task=" + mTaskId); } if (getTaskId() != INVALID_TASK_ID) { // Ensure the task is removed from WM if (ENABLE_SHELL_TRANSITIONS) { if (mTaskView != null) { mTaskView.removeTask(); } } else { try { ActivityTaskManager.getService().removeTask(getTaskId()); } catch (RemoteException e) { Log.w(TAG, e.getMessage()); } } } if (mTaskView != null) { mTaskView.setVisibility(GONE); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt +28 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,14 @@ package com.android.wm.shell.bubbles import android.app.ActivityTaskManager import android.app.ActivityTaskManager.INVALID_TASK_ID import android.content.ComponentName import android.os.RemoteException import android.util.Log import androidx.annotation.VisibleForTesting import com.android.wm.shell.taskview.TaskView import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS import java.util.concurrent.Executor /** Loading Loading @@ -78,4 +82,28 @@ class BubbleTaskView(val taskView: TaskView, executor: Executor) { init { taskView.setListener(executor, listener) } /** * Removes the [TaskView] from window manager. * * This should be called after all other cleanup animations have finished. */ fun cleanup() { if (taskId != INVALID_TASK_ID) { // Ensure the task is removed from WM if (ENABLE_SHELL_TRANSITIONS) { taskView.removeTask() } else { try { ActivityTaskManager.getService().removeTask(taskId) } catch (e: RemoteException) { Log.w(TAG, e.message ?: "") } } } } private companion object { const val TAG = "BubbleTaskView" } } Loading
libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt +19 −2 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.wm.shell.taskview.TaskView import com.android.wm.shell.taskview.TaskViewTaskController import com.google.common.truth.Truth.assertThat import com.google.common.util.concurrent.MoreExecutors.directExecutor Loading @@ -30,6 +29,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.verify @SmallTest @RunWith(AndroidJUnit4::class) Loading @@ -37,10 +38,11 @@ class BubbleTaskViewTest { private lateinit var bubbleTaskView: BubbleTaskView private val context = ApplicationProvider.getApplicationContext<Context>() private lateinit var taskView: TaskView @Before fun setUp() { val taskView = TaskView(context, mock<TaskViewTaskController>()) taskView = mock() bubbleTaskView = BubbleTaskView(taskView, directExecutor()) } Loading Loading @@ -72,4 +74,19 @@ class BubbleTaskViewTest { assertThat(actualTaskId).isEqualTo(123) assertThat(actualComponentName).isEqualTo(componentName) } @Test fun cleanup_invalidTaskId_doesNotRemoveTask() { bubbleTaskView.cleanup() verify(taskView, never()).removeTask() } @Test fun cleanup_validTaskId_removesTask() { val componentName = ComponentName(context, "TestClass") bubbleTaskView.listener.onTaskCreated(123, componentName) bubbleTaskView.cleanup() verify(taskView).removeTask() } }
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +44 −1 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ import com.android.launcher3.icons.BubbleIconFactory; import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView; import com.android.wm.shell.bubbles.bar.BubbleBarLayerView; import com.android.wm.shell.common.bubbles.BubbleInfo; import com.android.wm.shell.taskview.TaskView; import com.android.wm.shell.taskview.TaskViewTaskController; import java.io.PrintWriter; import java.util.List; Loading Loading @@ -105,6 +107,8 @@ public class Bubble implements BubbleViewProvider { private BubbleExpandedView mExpandedView; @Nullable private BubbleBarExpandedView mBubbleBarExpandedView; @Nullable private BubbleTaskView mBubbleTaskView; private BubbleViewInfoTask mInflationTask; private boolean mInflateSynchronously; Loading Loading @@ -393,6 +397,21 @@ public class Bubble implements BubbleViewProvider { return mTitle; } /** * Returns the existing {@link #mBubbleTaskView} if it's not {@code null}. Otherwise a new * instance of {@link BubbleTaskView} is created. */ public BubbleTaskView getOrCreateBubbleTaskView(Context context, BubbleController controller) { if (mBubbleTaskView == null) { TaskViewTaskController taskViewTaskController = new TaskViewTaskController(context, controller.getTaskOrganizer(), controller.getTaskViewTransitions(), controller.getSyncTransactionQueue()); TaskView taskView = new TaskView(context, taskViewTaskController); mBubbleTaskView = new BubbleTaskView(taskView, controller.getMainExecutor()); } return mBubbleTaskView; } /** * @return the ShortcutInfo id if it exists, or the metadata shortcut id otherwise. */ Loading @@ -415,6 +434,10 @@ public class Bubble implements BubbleViewProvider { * the bubble. */ void cleanupExpandedView() { cleanupExpandedView(true); } private void cleanupExpandedView(boolean cleanupTaskView) { if (mExpandedView != null) { mExpandedView.cleanUpExpandedState(); mExpandedView = null; Loading @@ -423,17 +446,37 @@ public class Bubble implements BubbleViewProvider { mBubbleBarExpandedView.cleanUpExpandedState(); mBubbleBarExpandedView = null; } if (cleanupTaskView) { cleanupTaskView(); } if (mIntent != null) { mIntent.unregisterCancelListener(mIntentCancelListener); } mIntentActive = false; } private void cleanupTaskView() { if (mBubbleTaskView != null) { mBubbleTaskView.cleanup(); mBubbleTaskView = null; } } /** * Call when all the views should be removed/cleaned up. */ void cleanupViews() { cleanupExpandedView(); cleanupViews(true); } /** * Call when all the views should be removed/cleaned up. * * <p>If we're switching between bar and floating modes, pass {@code false} on * {@code cleanupTaskView} to avoid recreating it in the new mode. */ void cleanupViews(boolean cleanupTaskView) { cleanupExpandedView(cleanupTaskView); mIconView = null; } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +3 −33 Original line number Diff line number Diff line Loading @@ -1366,8 +1366,9 @@ public class BubbleController implements ConfigurationChangeListener, mStackView.resetOverflowView(); mStackView.removeAllViews(); } // cleanup existing bubble views so they can be recreated later if needed. mBubbleData.getBubbles().forEach(Bubble::cleanupViews); // cleanup existing bubble views so they can be recreated later if needed, but retain // TaskView. mBubbleData.getBubbles().forEach(b -> b.cleanupViews(/* cleanupTaskView= */ false)); // remove the current bubble container from window manager, null it out, and create a new // container based on the current mode. Loading Loading @@ -1478,7 +1479,6 @@ public class BubbleController implements ConfigurationChangeListener, * <p> * Must be called from the main thread. */ @VisibleForTesting @MainThread public void removeBubble(String key, int reason) { if (mBubbleData.hasAnyBubbleWithKey(key)) { Loading @@ -1486,36 +1486,6 @@ public class BubbleController implements ConfigurationChangeListener, } } // TODO(b/316358859): remove this method after task views are shared across modes /** * Removes the bubble with the given key after task removal, unless the task was removed as * a result of mode switching, in which case, the bubble isn't removed because it will be * re-inflated for the new mode. */ @MainThread public void removeFloatingBubbleAfterTaskRemoval(String key, int reason) { // if we're floating remove the bubble. otherwise, we're here because the task was removed // after switching modes. See b/316358859 if (!isShowingAsBubbleBar()) { removeBubble(key, reason); } } // TODO(b/316358859): remove this method after task views are shared across modes /** * Removes the bubble with the given key after task removal, unless the task was removed as * a result of mode switching, in which case, the bubble isn't removed because it will be * re-inflated for the new mode. */ @MainThread public void removeBarBubbleAfterTaskRemoval(String key, int reason) { // if we're showing as bubble bar remove the bubble. otherwise, we're here because the task // was removed after switching modes. See b/316358859 if (isShowingAsBubbleBar()) { removeBubble(key, reason); } } /** * Removes all the bubbles. * <p> Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +2 −27 Original line number Diff line number Diff line Loading @@ -27,12 +27,10 @@ import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPAND import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT; import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS; import android.annotation.NonNull; import android.annotation.SuppressLint; import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; Loading @@ -49,7 +47,6 @@ import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.ShapeDrawable; import android.os.RemoteException; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.IntProperty; Loading Loading @@ -311,8 +308,7 @@ public class BubbleExpandedView extends LinearLayout { + " bubble=" + getBubbleKey()); } if (mBubble != null) { mController.removeFloatingBubbleAfterTaskRemoval( mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED); mController.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED); } if (mTaskView != null) { // Release the surface Loading Loading @@ -1105,32 +1101,11 @@ public class BubbleExpandedView extends LinearLayout { return ((LinearLayout.LayoutParams) mManageButton.getLayoutParams()).getMarginStart(); } /** * Cleans up anything related to the task. The TaskView itself is released after the task * has been removed. * * If this view should be reused after this method is called, then * {@link #initialize(BubbleController, BubbleStackView, boolean, BubbleTaskView)} * must be invoked first. */ /** Hide the task view. */ public void cleanUpExpandedState() { if (DEBUG_BUBBLE_EXPANDED_VIEW) { Log.d(TAG, "cleanUpExpandedState: bubble=" + getBubbleKey() + " task=" + mTaskId); } if (getTaskId() != INVALID_TASK_ID) { // Ensure the task is removed from WM if (ENABLE_SHELL_TRANSITIONS) { if (mTaskView != null) { mTaskView.removeTask(); } } else { try { ActivityTaskManager.getService().removeTask(getTaskId()); } catch (RemoteException e) { Log.w(TAG, e.getMessage()); } } } if (mTaskView != null) { mTaskView.setVisibility(GONE); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt +28 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,14 @@ package com.android.wm.shell.bubbles import android.app.ActivityTaskManager import android.app.ActivityTaskManager.INVALID_TASK_ID import android.content.ComponentName import android.os.RemoteException import android.util.Log import androidx.annotation.VisibleForTesting import com.android.wm.shell.taskview.TaskView import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS import java.util.concurrent.Executor /** Loading Loading @@ -78,4 +82,28 @@ class BubbleTaskView(val taskView: TaskView, executor: Executor) { init { taskView.setListener(executor, listener) } /** * Removes the [TaskView] from window manager. * * This should be called after all other cleanup animations have finished. */ fun cleanup() { if (taskId != INVALID_TASK_ID) { // Ensure the task is removed from WM if (ENABLE_SHELL_TRANSITIONS) { taskView.removeTask() } else { try { ActivityTaskManager.getService().removeTask(taskId) } catch (e: RemoteException) { Log.w(TAG, e.message ?: "") } } } } private companion object { const val TAG = "BubbleTaskView" } }