From ab63a991cdd33d4caa88d9871af4898cb7540ae4 Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Tue, 6 Aug 2024 12:29:37 -0700 Subject: [PATCH 1/6] Do not animate unfolded bar when folded on certain SysUI flag update Inspired by b/276864833 Test: https://android-build.corp.google.com/builds/abtd/run/L42600030005659107 Bug: 355973871 Flag: com.android.wm.shell.enable_taskbar_on_phones Change-Id: I1c06062a17f147c3252048373eedfa53db356572 --- .../com/android/launcher3/taskbar/TaskbarActivityContext.java | 2 +- .../taskbar/TaskbarForceVisibleImmersiveController.java | 3 +++ .../android/launcher3/taskbar/TaskbarScrimViewController.java | 4 ++++ .../com/android/launcher3/taskbar/TaskbarStashController.java | 4 ++++ .../launcher3/taskbar/VoiceInteractionWindowController.kt | 2 +- 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 9d394a81d7..9c954d13bb 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -927,7 +927,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags, fromInit); boolean isShadeVisible = (systemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0; - onNotificationShadeExpandChanged(isShadeVisible, fromInit); + onNotificationShadeExpandChanged(isShadeVisible, fromInit || isPhoneMode()); mControllers.taskbarViewController.setRecentsButtonDisabled( mControllers.navbarButtonsViewController.isRecentsDisabled() || isNavBarKidsModeActive()); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java index 6ac862e9e0..8a86402e7b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java @@ -85,6 +85,9 @@ public class TaskbarForceVisibleImmersiveController implements TouchController { /** Update values tracked via sysui flags. */ public void updateSysuiFlags(@SystemUiStateFlags long sysuiFlags) { + if (mContext.isPhoneMode()) { + return; + } mIsImmersiveMode = (sysuiFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) == 0; if (mContext.isNavBarForceVisible()) { if (mIsImmersiveMode) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java index 5e7c7cedf4..5ed9ed1b4d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java @@ -86,6 +86,10 @@ public class TaskbarScrimViewController implements TaskbarControllers.LoggableTa * Updates the scrim state based on the flags. */ public void updateStateForSysuiFlags(@SystemUiStateFlags long stateFlags, boolean skipAnim) { + if (mActivity.isPhoneMode()) { + // There is no scrim for the bar in the phone mode. + return; + } if (isBubbleBarEnabled() && DisplayController.isTransientTaskbar(mActivity)) { // These scrims aren't used if bubble bar & transient taskbar are active. return; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 5d6fdc145d..e33e29335b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -1022,6 +1022,10 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** Called when some system ui state has changed. (See SYSUI_STATE_... in QuickstepContract) */ public void updateStateForSysuiFlags(long systemUiStateFlags, boolean skipAnim) { + if (mActivity.isPhoneMode()) { + return; + } + long animDuration = TASKBAR_STASH_DURATION; long startDelay = 0; diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt index 619c9c4f6a..c380c8d6f1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt @@ -110,7 +110,7 @@ class VoiceInteractionWindowController(val context: TaskbarActivityContext) : } fun setIsVoiceInteractionWindowVisible(visible: Boolean, skipAnim: Boolean) { - if (isVoiceInteractionWindowVisible == visible) { + if (isVoiceInteractionWindowVisible == visible || context.isPhoneMode) { return } isVoiceInteractionWindowVisible = visible From 540af8a55aed1b0e7e3ec550f5dba9fb402f0c7e Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Thu, 8 Aug 2024 09:28:09 -0700 Subject: [PATCH 2/6] Fix jumping taskbar when tapping on nav handle. We can skip updating taskbar when home visibility changes due to recents transition animation. For this specific case it was a superfluous call anyways since taskbar unstashing would be handled by TaskbarUnstashInputConsumer. Fixes: 292108880 Bug: 345768019 Test: launch app, quickly tap on nav handle Flag: com.android.launcher3.enable_scaling_reveal_home_animation Change-Id: I822071d31d066503c27f527ade46e28a154df249 --- .../taskbar/LauncherTaskbarUIController.java | 9 ++++--- .../taskbar/TaskbarUIController.java | 10 ++++++++ .../quickstep/TaskAnimationManager.java | 24 +++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 3981e43c66..e5edd518b8 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -225,9 +225,12 @@ public class LauncherTaskbarUIController extends TaskbarUIController { // Launcher is resumed during the swipe-to-overview gesture under shell-transitions, so // avoid updating taskbar state in that situation (when it's non-interactive -- or // "background") to avoid premature animations. - if (ENABLE_SHELL_TRANSITIONS && isVisible - && mLauncher.getStateManager().getState().hasFlag(FLAG_NON_INTERACTIVE) - && !mLauncher.getStateManager().getState().isTaskbarAlignedWithHotseat(mLauncher)) { + LauncherState state = mLauncher.getStateManager().getState(); + boolean nonInteractiveState = state.hasFlag(FLAG_NON_INTERACTIVE) + && !state.isTaskbarAlignedWithHotseat(mLauncher); + if ((ENABLE_SHELL_TRANSITIONS + && isVisible + && (nonInteractiveState || mSkipLauncherVisibilityChange))) { return null; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index 2ada5bafd2..42bf8db7df 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -61,6 +61,8 @@ public class TaskbarUIController { // Initialized in init. protected TaskbarControllers mControllers; + protected boolean mSkipLauncherVisibilityChange; + @CallSuper protected void init(TaskbarControllers taskbarControllers) { mControllers = taskbarControllers; @@ -418,4 +420,12 @@ public class TaskbarUIController { public void setUserIsNotGoingHome(boolean isNotGoingHome) { mControllers.taskbarStashController.setUserIsNotGoingHome(isNotGoingHome); } + + /** + * Sets whether to prevent taskbar from reacting to launcher visibility during the recents + * transition animation. + */ + public void setSkipLauncherVisibilityChange(boolean skip) { + mSkipLauncherVisibilityChange = skip; + } } diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index f414399a0b..ab80a8c1b5 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -18,6 +18,7 @@ package com.android.quickstep; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks; +import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.util.NavigationMode.NO_BUTTON; @@ -44,6 +45,7 @@ import androidx.annotation.UiThread; import com.android.internal.util.ArrayUtils; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.taskbar.TaskbarUIController; import com.android.launcher3.util.DisplayController; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.SystemUiFlagUtils; @@ -334,6 +336,28 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn options.setTransientLaunch(); } options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime); + + // Notify taskbar that we should skip reacting to launcher visibility change to + // avoid a jumping taskbar. + TaskbarUIController taskbarUIController = containerInterface.getTaskbarController(); + if (enableScalingRevealHomeAnimation() && taskbarUIController != null) { + taskbarUIController.setSkipLauncherVisibilityChange(true); + + mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() { + @Override + public void onRecentsAnimationCanceled( + @NonNull HashMap thumbnailDatas) { + taskbarUIController.setSkipLauncherVisibilityChange(false); + } + + @Override + public void onRecentsAnimationFinished( + @NonNull RecentsAnimationController controller) { + taskbarUIController.setSkipLauncherVisibilityChange(false); + } + }); + } + mRecentsAnimationStartPending = getSystemUiProxy() .startRecentsActivity(intent, options, mCallbacks); if (enableHandleDelayedGestureCallbacks()) { From 1cc100844cec75e827aa787f8ba9932f36d2d2e4 Mon Sep 17 00:00:00 2001 From: Mady Mellor Date: Mon, 5 Feb 2024 09:30:03 -0800 Subject: [PATCH 3/6] Add a bubble option to launcher long press menus - Add a launcher "system shortcut" to bubble deep shortcuts or apps - For shortcuts, save the shortcut info to use to produce the bubble - Add an interface so that the system shortcut can call through to sysui proxy Flag: com.android.wm.shell.enable_bubble_anything Test: manual - enable the flag and try to bubble a shortcut via the longpress menu on launcher - try bubbling an app on launcher - try bubbling an app from the taskbar Bug: 342245211 Change-Id: I1ef49e1628ba0be9cea05073ecd9cd66bf67f88f --- .../launcher3/taskbar/BaseTaskbarContext.java | 19 +++++- .../taskbar/TaskbarPopupController.java | 15 +++-- .../uioverrides/QuickstepLauncher.java | 20 +++++- .../com/android/quickstep/SystemUiProxy.java | 31 ++++++++- res/drawable/ic_bubble_button.xml | 25 ++++++++ res/values/strings.xml | 3 +- .../model/data/WorkspaceItemInfo.java | 11 ++++ .../launcher3/popup/SystemShortcut.java | 63 +++++++++++++++++++ 8 files changed, 179 insertions(+), 8 deletions(-) create mode 100644 res/drawable/ic_bubble_button.xml diff --git a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java index c201236586..a833ccf9c4 100644 --- a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java @@ -16,19 +16,24 @@ package com.android.launcher3.taskbar; import android.content.Context; +import android.content.Intent; +import android.content.pm.ShortcutInfo; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; +import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.util.Themes; import com.android.launcher3.views.ActivityContext; +import com.android.quickstep.SystemUiProxy; import java.util.ArrayList; import java.util.List; // TODO(b/218912746): Share more behavior to avoid all apps context depending directly on taskbar. /** Base for common behavior between taskbar window contexts. */ -public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext { +public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext, + SystemShortcut.BubbleActivityStarter { protected final LayoutInflater mLayoutInflater; private final List mDPChangeListeners = new ArrayList<>(); @@ -48,6 +53,18 @@ public abstract class BaseTaskbarContext extends ContextThemeWrapper implements return mDPChangeListeners; } + @Override + public void showShortcutBubble(ShortcutInfo info) { + if (info == null) return; + SystemUiProxy.INSTANCE.get(this).showShortcutBubble(info); + } + + @Override + public void showAppBubble(Intent intent) { + if (intent == null || intent.getPackage() == null) return; + SystemUiProxy.INSTANCE.get(this).showAppBubble(intent); + } + /** Callback invoked when a drag is initiated within this context. */ public abstract void onDragStart(); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java index b69759039a..e80ad7a8a1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java @@ -53,6 +53,7 @@ import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.LogUtils; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Objects; @@ -69,6 +70,9 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba private static final SystemShortcut.Factory APP_INFO = SystemShortcut.AppInfo::new; + private static final SystemShortcut.Factory + BUBBLE = SystemShortcut.BubbleShortcut::new; + private final TaskbarActivityContext mContext; private final PopupDataProvider mPopupDataProvider; @@ -182,10 +186,13 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba // Create a Stream of all applicable system shortcuts private Stream getSystemShortcuts() { // append split options to APP_INFO shortcut, the order here will reflect in the popup - return Stream.concat( - Stream.of(APP_INFO), - mControllers.uiController.getSplitMenuOptions() - ); + ArrayList shortcuts = new ArrayList<>(); + shortcuts.add(APP_INFO); + shortcuts.addAll(mControllers.uiController.getSplitMenuOptions().toList()); + if (com.android.wm.shell.Flags.enableBubbleAnything()) { + shortcuts.add(BUBBLE); + } + return shortcuts.stream(); } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index b2cc369376..5a288b0336 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -45,6 +45,7 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition; import static com.android.launcher3.popup.SystemShortcut.APP_INFO; +import static com.android.launcher3.popup.SystemShortcut.BUBBLE_SHORTCUT; import static com.android.launcher3.popup.SystemShortcut.DONT_SUGGEST_APP; import static com.android.launcher3.popup.SystemShortcut.INSTALL; import static com.android.launcher3.popup.SystemShortcut.PRIVATE_PROFILE_INSTALL; @@ -75,6 +76,7 @@ import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.ShortcutInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.graphics.RectF; @@ -215,7 +217,8 @@ import java.util.function.BiConsumer; import java.util.function.Predicate; import java.util.stream.Stream; -public class QuickstepLauncher extends Launcher implements RecentsViewContainer { +public class QuickstepLauncher extends Launcher implements RecentsViewContainer, + SystemShortcut.BubbleActivityStarter { private static final boolean TRACE_LAYOUTS = SystemProperties.getBoolean("persist.debug.trace_layouts", false); private static final String TRACE_RELAYOUT_CLASS = @@ -466,6 +469,9 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer if (Flags.enablePrivateSpace()) { shortcuts.add(UNINSTALL_APP); } + if (com.android.wm.shell.Flags.enableBubbleAnything()) { + shortcuts.add(BUBBLE_SHORTCUT); + } return shortcuts.stream(); } @@ -1436,6 +1442,18 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer return true; } + @Override + public void showShortcutBubble(ShortcutInfo info) { + if (info == null) return; + SystemUiProxy.INSTANCE.get(this).showShortcutBubble(info); + } + + @Override + public void showAppBubble(Intent intent) { + if (intent == null || intent.getPackage() == null) return; + SystemUiProxy.INSTANCE.get(this).showAppBubble(intent); + } + private static final class LauncherTaskViewController extends TaskViewTouchController { diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index 0c2f29b8db..59e9f054c8 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -47,7 +47,6 @@ import android.view.IRecentsAnimationController; import android.view.IRecentsAnimationRunner; import android.view.IRemoteAnimationRunner; import android.view.MotionEvent; -import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.window.IOnBackInvokedCallback; @@ -894,6 +893,36 @@ public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable { } } + /** + * Tells SysUI to show a shortcut bubble. + * + * @param info the shortcut info used to create or identify the bubble. + */ + public void showShortcutBubble(ShortcutInfo info) { + try { + if (mBubbles != null) { + mBubbles.showShortcutBubble(info); + } + } catch (RemoteException e) { + Log.w(TAG, "Failed call show bubble for shortcut"); + } + } + + /** + * Tells SysUI to show a bubble of an app. + * + * @param intent the intent used to create the bubble. + */ + public void showAppBubble(Intent intent) { + try { + if (mBubbles != null) { + mBubbles.showAppBubble(intent); + } + } catch (RemoteException e) { + Log.w(TAG, "Failed call show bubble for app"); + } + } + // // Splitscreen // diff --git a/res/drawable/ic_bubble_button.xml b/res/drawable/ic_bubble_button.xml new file mode 100644 index 0000000000..1ed212e09a --- /dev/null +++ b/res/drawable/ic_bubble_button.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 3b458c2cff..fd724a5553 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -215,7 +215,8 @@ Don\'t suggest app Pin Prediction - + + Bubble diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java index 40e3813fe3..f31bf1e5fe 100644 --- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java +++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java @@ -25,6 +25,7 @@ import android.text.TextUtils; import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.launcher3.Flags; import com.android.launcher3.LauncherSettings; @@ -97,6 +98,8 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { public int options; + @Nullable + private ShortcutInfo mShortcutInfo = null; public WorkspaceItemInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; @@ -175,6 +178,9 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { public void updateFromDeepShortcutInfo(@NonNull final ShortcutInfo shortcutInfo, @NonNull final Context context) { + if (com.android.wm.shell.Flags.enableBubbleAnything()) { + mShortcutInfo = shortcutInfo; + } // {@link ShortcutInfo#getActivity} can change during an update. Recreate the intent intent = ShortcutKey.makeIntent(shortcutInfo); title = shortcutInfo.getShortLabel(); @@ -204,6 +210,11 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { : Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new); } + @Nullable + public ShortcutInfo getDeepShortcutInfo() { + return mShortcutInfo; + } + /** * {@code true} if the shortcut is disabled due to its app being a lower version. */ diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index f7e116819a..0c90eb904a 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -11,9 +11,11 @@ import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ShortcutInfo; import android.graphics.Rect; import android.os.Process; import android.os.UserHandle; +import android.util.Log; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.ImageView; @@ -25,6 +27,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.AbstractFloatingViewHelper; import com.android.launcher3.Flags; +import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; import com.android.launcher3.SecondaryDropTarget; import com.android.launcher3.Utilities; @@ -53,6 +56,7 @@ import java.util.Arrays; */ public abstract class SystemShortcut extends ItemInfo implements View.OnClickListener { + private static final String TAG = "SystemShortcut"; private final int mIconResId; protected final int mLabelResId; @@ -383,4 +387,63 @@ public abstract class SystemShortcut extends ItemInfo mAbstractFloatingViewHelper.closeOpenViews(mTarget, true, AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE); } + + public static final Factory BUBBLE_SHORTCUT = + (activity, itemInfo, originalView) -> { + if ((itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) + && (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) + && !(itemInfo instanceof WorkspaceItemInfo)) { + return null; + } + return new BubbleShortcut(activity, itemInfo, originalView); + }; + + public interface BubbleActivityStarter { + /** Tell SysUI to show the provided shortcut in a bubble. */ + void showShortcutBubble(ShortcutInfo info); + + /** Tell SysUI to show the provided intent in a bubble. */ + void showAppBubble(Intent intent); + } + + public static class BubbleShortcut extends SystemShortcut { + + private BubbleActivityStarter mStarter; + + public BubbleShortcut(T target, ItemInfo itemInfo, View originalView) { + super(R.drawable.ic_bubble_button, R.string.bubble, target, + itemInfo, originalView); + if (target instanceof BubbleActivityStarter) { + mStarter = (BubbleActivityStarter) target; + } + } + + @Override + public void onClick(View view) { + dismissTaskMenuView(); + if (mStarter == null) { + Log.w(TAG, "starter null!"); + return; + } + // TODO: handle GroupTask (single) items so that recent items in taskbar work + if (mItemInfo instanceof WorkspaceItemInfo) { + WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) mItemInfo; + ShortcutInfo shortcutInfo = workspaceItemInfo.getDeepShortcutInfo(); + if (shortcutInfo != null) { + mStarter.showShortcutBubble(shortcutInfo); + return; + } + } + // If we're here check for an intent + Intent intent = mItemInfo.getIntent(); + if (intent != null) { + if (intent.getPackage() == null) { + intent.setPackage(mItemInfo.getTargetPackage()); + } + mStarter.showAppBubble(intent); + } else { + Log.w(TAG, "unable to bubble, no intent: " + mItemInfo); + } + } + } } From 194768420dcf8bb511c607c822ca9d9746c620ff Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Thu, 8 Aug 2024 17:07:44 +0100 Subject: [PATCH 4/6] Mark TaplTestsOverviewDesktop.enterDesktopViaOverviewMenu as postsubmit only Fix: 358364342 Bug: 320313527 Test: TaplTestsOverviewDesktop Flag: EXEMPT TEST_ONLY Change-Id: I52f2db342ca75f66d5159a669cb8493caea0e88a --- .../src/com/android/quickstep/TaplTestsOverviewDesktop.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt index 694a3822fe..2122d9aff7 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt @@ -24,6 +24,9 @@ import com.android.launcher3.BuildConfig import com.android.launcher3.ui.AbstractLauncherUiTest import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape import com.android.launcher3.uioverrides.QuickstepLauncher +import com.android.launcher3.util.rule.TestStabilityRule +import com.android.launcher3.util.rule.TestStabilityRule.LOCAL +import com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT import com.google.common.truth.Truth.assertWithMessage import org.junit.Before import org.junit.Test @@ -42,6 +45,7 @@ class TaplTestsOverviewDesktop : AbstractLauncherUiTest() { mLauncher.goHome() } + @TestStabilityRule.Stability(flavors = LOCAL or PLATFORM_POSTSUBMIT) @Test @PortraitLandscape fun enterDesktopViaOverviewMenu() { From 6ba789a98fade3000e355e04acbc45b4c57f4bc8 Mon Sep 17 00:00:00 2001 From: mpodolian Date: Wed, 7 Aug 2024 15:52:16 -0700 Subject: [PATCH 5/6] Added taskbar in/out animation when the bubble bar is expanded/collapsed Added taskbar icon animation when the bubble bar expansion changes. If there is enough space to accommodate both bars with spacing in between, the taskbar remains. If there is not enough space, the taskbar is animated out and then animated in when the bubble bar is collapsed. Bug: 346391377 Flag: com.android.wm.shell.enable_bubble_bar Test: Manual. Set taskbar to persistent mode via 3-button navigation or through the taskbar itself. Have enough bubbles to cover the taskbar when the bubble bar is extended. Expand the bubble bar and observe the taskbar icons animating out. Remove a few bubbles so there is enough space to accommodate both bars. Expand the bubble bar and observe that both bars are visible. Change-Id: I0b03a010c1e49ab39a17934f6629d5496fd66978 --- .../taskbar/StashedHandleViewController.java | 2 +- .../taskbar/TaskbarScrimViewController.java | 13 ++++++- .../launcher3/taskbar/TaskbarView.java | 14 ++++++- .../taskbar/TaskbarViewController.java | 12 ++++-- .../taskbar/bubbles/BubbleBarView.java | 31 +++++++++++++--- .../bubbles/BubbleBarViewController.java | 37 ++++++++++++++++++- .../taskbar/bubbles/BubbleControllers.java | 22 ++++++++++- 7 files changed, 117 insertions(+), 14 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java index 266d0b9c98..475b51646b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java @@ -212,7 +212,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT * stashed handle to wrap around the hotseat items. */ public Animator createRevealAnimToIsStashed(boolean isStashed, Rect taskbarToHotseatOffsets) { - Rect visualBounds = new Rect(mControllers.taskbarViewController.getIconLayoutBounds()); + Rect visualBounds = mControllers.taskbarViewController.getIconLayoutVisualBounds(); float startRadius = mStashedHandleRadius; if (DisplayController.isTransientTaskbar(mActivity)) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java index 5e7c7cedf4..3b6f46bf2d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java @@ -28,6 +28,7 @@ import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import com.android.launcher3.anim.AnimatedFloat; +import com.android.launcher3.taskbar.bubbles.BubbleControllers; import com.android.launcher3.util.DisplayController; import com.android.quickstep.SystemUiProxy; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; @@ -97,10 +98,20 @@ public class TaskbarScrimViewController implements TaskbarControllers.LoggableTa private boolean shouldShowScrim() { final boolean bubblesExpanded = (mSysUiStateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0; boolean isShadeVisible = (mSysUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0; + BubbleControllers bubbleControllers = mActivity.getBubbleControllers(); + boolean isBubbleControllersPresented = bubbleControllers != null; + // when the taskbar is in persistent mode, we hide the task bar icons on bubble bar expand, + // which makes the taskbar invisible, so need to check if the bubble bar is not on home + // to show the scrim view + boolean showScrimForBubbles = bubblesExpanded + && !mTaskbarVisible + && isBubbleControllersPresented + && !DisplayController.isTransientTaskbar(mActivity) + && !bubbleControllers.bubbleStashController.isBubblesShowingOnHome(); return bubblesExpanded && !mControllers.navbarButtonsViewController.isImeVisible() && !isShadeVisible && !mControllers.taskbarStashController.isStashed() - && mTaskbarVisible; + && (mTaskbarVisible || showScrimForBubbles); } private float getScrimAlpha() { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index e58069a7e4..fc76972105 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -669,8 +669,20 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar return isShown() && mIconLayoutBounds.contains(xInOurCoordinates, yInOurCoorindates); } + /** + * Gets visual bounds of the taskbar view. The visual bounds correspond to the taskbar touch + * area, rather than layout placement in the parent view. + */ + public Rect getIconLayoutVisualBounds() { + return new Rect(mIconLayoutBounds); + } + + /** Gets taskbar layout bounds in parent view. */ public Rect getIconLayoutBounds() { - return mIconLayoutBounds; + Rect actualBounds = new Rect(mIconLayoutBounds); + actualBounds.top = getTop(); + actualBounds.bottom = getBottom(); + return actualBounds; } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index ffa481988f..b8b85d120a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -96,7 +96,9 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 4; public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 5; public static final int ALPHA_INDEX_SMALL_SCREEN = 6; - private static final int NUM_ALPHA_CHANNELS = 7; + + public static final int ALPHA_INDEX_BUBBLE_BAR = 7; + private static final int NUM_ALPHA_CHANNELS = 8; private static boolean sEnableModelLoadingForTests = true; @@ -272,6 +274,10 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar OneShotPreDrawListener.add(mTaskbarView, listener); } + public Rect getIconLayoutVisualBounds() { + return mTaskbarView.getIconLayoutVisualBounds(); + } + public Rect getIconLayoutBounds() { return mTaskbarView.getIconLayoutBounds(); } @@ -462,14 +468,14 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar if (mControllers.getSharedState().startTaskbarVariantIsTransient) { float transY = mTransientTaskbarDp.taskbarBottomMargin + (mTransientTaskbarDp.taskbarHeight - - mTaskbarView.getIconLayoutBounds().bottom) + - mTaskbarView.getIconLayoutVisualBounds().bottom) - (mPersistentTaskbarDp.taskbarHeight - mTransientTaskbarDp.taskbarIconSize) / 2f; taskbarIconTranslationYForPinningValue = mapRange(scale, 0f, transY); } else { float transY = -mTransientTaskbarDp.taskbarBottomMargin + (mPersistentTaskbarDp.taskbarHeight - - mTaskbarView.getIconLayoutBounds().bottom) + - mTaskbarView.getIconLayoutVisualBounds().bottom) - (mTransientTaskbarDp.taskbarHeight - mTransientTaskbarDp.taskbarIconSize) / 2f; taskbarIconTranslationYForPinningValue = mapRange(scale, transY, 0f); diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java index 4d0cad228e..a2746df3d9 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java @@ -661,13 +661,25 @@ public class BubbleBarView extends FrameLayout { return displayHeight - bubbleBarHeight + (int) mController.getBubbleBarTranslationY(); } - /** - * Updates the bounds with translation that may have been applied and returns the result. - */ + /** Returns the bounds with translation that may have been applied. */ public Rect getBubbleBarBounds() { - mBubbleBarBounds.top = getTop() + (int) getTranslationY() + mPointerSize; - mBubbleBarBounds.bottom = getBottom() + (int) getTranslationY(); - return mBubbleBarBounds; + Rect bounds = new Rect(mBubbleBarBounds); + bounds.top = getTop() + (int) getTranslationY() + mPointerSize; + bounds.bottom = getBottom() + (int) getTranslationY(); + return bounds; + } + + /** Returns the expanded bounds with translation that may have been applied. */ + public Rect getBubbleBarExpandedBounds() { + Rect expandedBounds = getBubbleBarBounds(); + if (!isExpanded() || isExpanding()) { + if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) { + expandedBounds.right = expandedBounds.left + (int) expandedWidth(); + } else { + expandedBounds.left = expandedBounds.right - (int) expandedWidth(); + } + } + return expandedBounds; } /** @@ -1279,6 +1291,13 @@ public class BubbleBarView extends FrameLayout { return mIsBarExpanded; } + /** + * Returns whether the bubble bar is expanding. + */ + public boolean isExpanding() { + return mWidthAnimator.isRunning() && mIsBarExpanded; + } + /** * Get width of the bubble bar as if it would be expanded. * diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index 2cdc0ced86..3e8cd50c77 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -72,6 +72,7 @@ public class BubbleBarViewController { private BubbleDragController mBubbleDragController; private TaskbarStashController mTaskbarStashController; private TaskbarInsetsController mTaskbarInsetsController; + private TaskbarViewPropertiesProvider mTaskbarViewPropertiesProvider; private View.OnClickListener mBubbleClickListener; private View.OnClickListener mBubbleBarClickListener; private BubbleView.Controller mBubbleViewController; @@ -110,13 +111,16 @@ public class BubbleBarViewController { R.dimen.bubblebar_icon_size); } - public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) { + /** Initializes controller. */ + public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers, + TaskbarViewPropertiesProvider taskbarViewPropertiesProvider) { mBubbleStashController = bubbleControllers.bubbleStashController; mBubbleBarController = bubbleControllers.bubbleBarController; mBubbleDragController = bubbleControllers.bubbleDragController; mTaskbarStashController = controllers.taskbarStashController; mTaskbarInsetsController = controllers.taskbarInsetsController; mBubbleBarViewAnimator = new BubbleBarViewAnimator(mBarView, mBubbleStashController); + mTaskbarViewPropertiesProvider = taskbarViewPropertiesProvider; onBubbleBarConfigurationChanged(/* animate= */ false); mActivity.addOnDeviceProfileChangeListener( dp -> onBubbleBarConfigurationChanged(/* animate= */ true)); @@ -347,6 +351,7 @@ public class BubbleBarViewController { if (hidden) { mBarView.setAlpha(0); mBarView.setExpanded(false); + updatePersistentTaskbar(/* isBubbleBarExpanded = */ false); } mActivity.bubbleBarVisibilityChanged(!hidden); } @@ -611,6 +616,7 @@ public class BubbleBarViewController { public void setExpanded(boolean isExpanded) { if (isExpanded != mBarView.isExpanded()) { mBarView.setExpanded(isExpanded); + updatePersistentTaskbar(isExpanded); if (!isExpanded) { mSystemUiProxy.collapseBubbles(); } else { @@ -621,6 +627,25 @@ public class BubbleBarViewController { } } + private void updatePersistentTaskbar(boolean isBubbleBarExpanded) { + if (mBubbleStashController.isTransientTaskBar()) return; + boolean hideTaskbar = isBubbleBarExpanded && isIntersectingTaskbar(); + mTaskbarViewPropertiesProvider + .getIconsAlpha() + .animateToValue(hideTaskbar ? 0 : 1) + .start(); + } + + /** Return {@code true} if expanded bubble bar would intersect the taskbar. */ + public boolean isIntersectingTaskbar() { + if (mBarView.isExpanding() || mBarView.isExpanded()) { + Rect taskbarViewBounds = mTaskbarViewPropertiesProvider.getTaskbarViewBounds(); + return mBarView.getBubbleBarExpandedBounds().intersect(taskbarViewBounds); + } else { + return false; + } + } + /** * Sets whether the bubble bar should be expanded. This method is used in response to UI events * from SystemUI. @@ -750,4 +775,14 @@ public class BubbleBarViewController { pw.println(" Bubble bar view is null!"); } } + + /** Interface for BubbleBarViewController to get the taskbar view properties. */ + public interface TaskbarViewPropertiesProvider { + + /** Returns the bounds of the taskbar. */ + Rect getTaskbarViewBounds(); + + /** Returns taskbar icons alpha */ + MultiPropertyFactory.MultiProperty getIconsAlpha(); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java index 8478dc2171..e00916af6c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java @@ -15,8 +15,15 @@ */ package com.android.launcher3.taskbar.bubbles; +import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_BUBBLE_BAR; + +import android.graphics.Rect; +import android.view.View; + import com.android.launcher3.taskbar.TaskbarControllers; +import com.android.launcher3.taskbar.bubbles.BubbleBarViewController.TaskbarViewPropertiesProvider; import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController; +import com.android.launcher3.util.MultiPropertyFactory; import com.android.launcher3.util.RunnableList; import java.io.PrintWriter; @@ -79,7 +86,20 @@ public class BubbleControllers { bubbleStashedHandleViewController.orElse(null), taskbarControllers::runAfterInit ); - bubbleBarViewController.init(taskbarControllers, /* bubbleControllers = */ this); + bubbleBarViewController.init(taskbarControllers, /* bubbleControllers = */ this, + new TaskbarViewPropertiesProvider() { + @Override + public Rect getTaskbarViewBounds() { + return taskbarControllers.taskbarViewController.getIconLayoutBounds(); + } + + @Override + public MultiPropertyFactory.MultiProperty getIconsAlpha() { + return taskbarControllers.taskbarViewController + .getTaskbarIconAlpha() + .get(ALPHA_INDEX_BUBBLE_BAR); + } + }); bubbleDragController.init(/* bubbleControllers = */ this); bubbleDismissController.init(/* bubbleControllers = */ this); bubbleBarPinController.init(this); From 08ef39c5ba027b6bbca4ce2dcee5ed5057b29291 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 9 Aug 2024 19:57:00 +0000 Subject: [PATCH 6/6] Explicitly release references to the controller - This is a workaround for lingering phantom references to binder stubs Flag: EXEMPT bugfix Bug: 332339792 Test: Presubmit Change-Id: I3e790f627d434760e87be1dc6c8643d03fceb400 --- .../DesktopVisibilityController.java | 63 +++++++++++++------ .../util/SplitSelectStateController.java | 44 ++++++++++--- 2 files changed, 78 insertions(+), 29 deletions(-) diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java index 62cc0bb90a..0dac388493 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java +++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java @@ -26,6 +26,7 @@ import android.os.SystemProperties; import android.util.Log; import android.view.View; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.Launcher; @@ -39,6 +40,7 @@ import com.android.wm.shell.desktopmode.IDesktopTaskListener; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.Executor; /** * Controls the visibility of the workspace and the resumed / paused state when desktop mode @@ -57,7 +59,7 @@ public class DesktopVisibilityController { private boolean mGestureInProgress; @Nullable - private IDesktopTaskListener mDesktopTaskListener; + private DesktopTaskListenerImpl mDesktopTaskListener; public DesktopVisibilityController(Launcher launcher) { mLauncher = launcher; @@ -67,24 +69,7 @@ public class DesktopVisibilityController { * Register a listener with System UI to receive updates about desktop tasks state */ public void registerSystemUiListener() { - mDesktopTaskListener = new IDesktopTaskListener.Stub() { - @Override - public void onTasksVisibilityChanged(int displayId, int visibleTasksCount) { - MAIN_EXECUTOR.execute(() -> { - if (displayId == mLauncher.getDisplayId()) { - if (DEBUG) { - Log.d(TAG, "desktop visible tasks count changed=" + visibleTasksCount); - } - setVisibleDesktopTasksCount(visibleTasksCount); - } - }); - } - - @Override - public void onStashedChanged(int displayId, boolean stashed) { - Log.w(TAG, "IDesktopTaskListener: onStashedChanged is deprecated"); - } - }; + mDesktopTaskListener = new DesktopTaskListenerImpl(this, mLauncher.getDisplayId()); SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(mDesktopTaskListener); } @@ -93,6 +78,7 @@ public class DesktopVisibilityController { */ public void unregisterSystemUiListener() { SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(null); + mDesktopTaskListener.release(); mDesktopTaskListener = null; } @@ -356,4 +342,43 @@ public class DesktopVisibilityController { */ void onDesktopVisibilityChanged(boolean visible); } + + /** + * Wrapper for the IDesktopTaskListener stub to prevent lingering references to the launcher + * activity via the controller. + */ + private static class DesktopTaskListenerImpl extends IDesktopTaskListener.Stub { + + private DesktopVisibilityController mController; + private final int mDisplayId; + + DesktopTaskListenerImpl(@NonNull DesktopVisibilityController controller, int displayId) { + mController = controller; + mDisplayId = displayId; + } + + /** + * Clears any references to the controller. + */ + void release() { + mController = null; + } + + @Override + public void onTasksVisibilityChanged(int displayId, int visibleTasksCount) { + MAIN_EXECUTOR.execute(() -> { + if (mController != null && displayId == mDisplayId) { + if (DEBUG) { + Log.d(TAG, "desktop visible tasks count changed=" + visibleTasksCount); + } + mController.setVisibleDesktopTasksCount(visibleTasksCount); + } + }); + } + + @Override + public void onStashedChanged(int displayId, boolean stashed) { + Log.w(TAG, "IDesktopTaskListener: onStashedChanged is deprecated"); + } + } } diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java index d906bb3fd3..5e6f7e94ff 100644 --- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java +++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java @@ -961,7 +961,7 @@ public class SplitSelectStateController { private final int mSplitPlaceholderSize; private final int mSplitPlaceholderInset; private ActivityManager.RunningTaskInfo mTaskInfo; - private ISplitSelectListener mSplitSelectListener; + private DesktopSplitSelectListenerImpl mSplitSelectListener; private Drawable mAppIcon; public SplitFromDesktopController(QuickstepLauncher launcher, @@ -972,21 +972,14 @@ public class SplitSelectStateController { R.dimen.split_placeholder_size); mSplitPlaceholderInset = mLauncher.getResources().getDimensionPixelSize( R.dimen.split_placeholder_inset); - mSplitSelectListener = new ISplitSelectListener.Stub() { - @Override - public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo, - int splitPosition, Rect taskBounds) { - MAIN_EXECUTOR.execute(() -> enterSplitSelect(taskInfo, splitPosition, - taskBounds)); - return true; - } - }; + mSplitSelectListener = new DesktopSplitSelectListenerImpl(this); SystemUiProxy.INSTANCE.get(mLauncher).registerSplitSelectListener(mSplitSelectListener); } void onDestroy() { SystemUiProxy.INSTANCE.get(mLauncher).unregisterSplitSelectListener( mSplitSelectListener); + mSplitSelectListener.release(); mSplitSelectListener = null; } @@ -1079,4 +1072,35 @@ public class SplitSelectStateController { } } } + + /** + * Wrapper for the ISplitSelectListener stub to prevent lingering references to the launcher + * activity via the controller. + */ + private static class DesktopSplitSelectListenerImpl extends ISplitSelectListener.Stub { + + private SplitFromDesktopController mController; + + DesktopSplitSelectListenerImpl(@NonNull SplitFromDesktopController controller) { + mController = controller; + } + + /** + * Clears any references to the controller. + */ + void release() { + mController = null; + } + + @Override + public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo, + int splitPosition, Rect taskBounds) { + MAIN_EXECUTOR.execute(() -> { + if (mController != null) { + mController.enterSplitSelect(taskInfo, splitPosition, taskBounds); + } + }); + return true; + } + } }