diff options
author | 2024-02-05 09:30:03 -0800 | |
---|---|---|
committer | 2024-08-08 21:23:13 +0000 | |
commit | 1cc100844cec75e827aa787f8ba9932f36d2d2e4 (patch) | |
tree | deae331d197011fc161197703ff620d5e45271c7 | |
parent | a5fa9bc9115c1ec8d212b0690b0f87acb865d404 (diff) |
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
8 files changed, 179 insertions, 8 deletions
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<OnDeviceProfileChangeListener> 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<BaseTaskbarContext> APP_INFO = SystemShortcut.AppInfo::new; + private static final SystemShortcut.Factory<BaseTaskbarContext> + 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<SystemShortcut.Factory> 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<SystemShortcut.Factory> 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<QuickstepLauncher> { 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="20dp" + android:height="20dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M23,5v8h-2V5H3v14h10v2v0H3c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h18C22.1,3 23,3.9 23,5zM10,8v2.59L5.71,6.29L4.29,7.71L8.59,12H6v2h6V8H10zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/> +</vector> 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 @@ <string name="dismiss_prediction_label">Don\'t suggest app</string> <!-- Label for pinning predicted app. --> <string name="pin_prediction">Pin Prediction</string> - + <!-- Label for bubbling a launcher item. [CHAR_LIMIT=20] --> + <string name="bubble">Bubble</string> <!-- Permissions: --> <skip /> 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<T extends ActivityContext> 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<T extends ActivityContext> extends ItemInfo mAbstractFloatingViewHelper.closeOpenViews(mTarget, true, AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE); } + + public static final Factory<ActivityContext> 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<T extends ActivityContext> extends SystemShortcut<T> { + + 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); + } + } + } } |