diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index 8e70a2b835..7adba196cd 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -366,4 +366,9 @@ App title Close button + + + Pin to taskbar + + Unpin from taskbar diff --git a/quickstep/src/com/android/launcher3/taskbar/PinToTaskbarShortcut.kt b/quickstep/src/com/android/launcher3/taskbar/PinToTaskbarShortcut.kt new file mode 100644 index 0000000000..b9a211de05 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/PinToTaskbarShortcut.kt @@ -0,0 +1,42 @@ +/* + * 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.launcher3.taskbar + +import android.content.Context +import android.view.View +import com.android.launcher3.R +import com.android.launcher3.model.data.ItemInfo +import com.android.launcher3.popup.SystemShortcut +import com.android.launcher3.views.ActivityContext + +/** + * A single menu item shortcut to allow users to pin an item to the taskbar and unpin an item from + * the taskbar. + */ +class PinToTaskbarShortcut(target: T, itemInfo: ItemInfo?, originalView: View, isPin: Boolean) : + SystemShortcut( + if (isPin) R.drawable.ic_pin else R.drawable.ic_unpin, + if (isPin) R.string.pin_to_taskbar else R.string.unpin_from_taskbar, + target, + itemInfo, + originalView, + ) where T : Context?, T : ActivityContext? { + + override fun onClick(v: View?) { + // TODO(b/375648361): Pin/Unpin the item here. + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java index 6815f97e16..f2eeed5954 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java @@ -203,6 +203,7 @@ public class TaskbarModelCallbacks implements ItemInfo[] hotseatItemInfos, List recentTasks) { mContainer.updateItems(hotseatItemInfos, recentTasks); mControllers.taskbarViewController.updateIconViewsRunningStates(); + mControllers.taskbarPopupController.setHotseatInfosList(mHotseatItems); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java index 5d8b8212a8..80944bb91b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java @@ -16,18 +16,20 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT; import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR; -import static com.android.launcher3.popup.SystemShortcut.PIN_UNPIN_ITEM; import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition; import android.content.Intent; import android.content.pm.LauncherApps; import android.graphics.Point; import android.util.Pair; +import android.util.SparseArray; import android.view.MotionEvent; import android.view.View; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.internal.logging.InstanceId; import com.android.launcher3.AbstractFloatingView; @@ -88,6 +90,8 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba private TaskbarControllers mControllers; private boolean mAllowInitialSplitSelection; private AppInfo[] mAppInfosList; + // Saves the ItemInfos in the hotseat without the predicted items. + private SparseArray mHotseatInfosList; private ManageWindowsTaskbarShortcut mManageWindowsTaskbarShortcut; @@ -189,6 +193,14 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba .filter(Objects::nonNull) .collect(Collectors.toList()); + // TODO(b/375648361): Revisit to see if this can be implemented within getSystemShortcuts(). + if (Flags.enablePinningAppWithContextMenu()) { + SystemShortcut shortcut = createPinShortcut(context, item, icon); + if (shortcut != null) { + systemShortcuts.add(0, shortcut); + } + } + container = (PopupContainerWithArrow) context.getLayoutInflater().inflate( R.layout.popup_container, context.getDragLayer(), false); container.populateAndShowRows(icon, deepShortcutCount, systemShortcuts); @@ -212,9 +224,6 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba // append split options to APP_INFO shortcut if not in Desktop Windowing mode, the order // here will reflect in the popup ArrayList shortcuts = new ArrayList<>(); - if (Flags.enablePinningAppWithContextMenu()) { - shortcuts.add(PIN_UNPIN_ITEM); - } shortcuts.add(APP_INFO); if (!mControllers.taskbarDesktopModeController .isInDesktopModeAndNotInOverview(mContext.getDisplayId())) { @@ -233,6 +242,24 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba return shortcuts.stream(); } + @Nullable + private SystemShortcut createPinShortcut(BaseTaskbarContext target, ItemInfo itemInfo, + BubbleTextView originalView) { + // Predicted items use {@code HotseatPredictionController.PinPrediction} shortcut to pin. + if (itemInfo.isPredictedItem()) { + return null; + } + if (itemInfo.container == CONTAINER_HOTSEAT) { + return new PinToTaskbarShortcut<>(target, itemInfo, originalView, false); + } + if (mHotseatInfosList.size() + < mContext.getTaskbarSpecsEvaluator().getNumShownHotseatIcons()) { + return new PinToTaskbarShortcut<>(target, itemInfo, originalView, true); + } + + return null; + } + @Override public void dumpLogs(String prefix, PrintWriter pw) { pw.println(prefix + "TaskbarPopupController:"); @@ -316,6 +343,10 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba return index < 0 ? null : mAppInfosList[index]; } + public void setHotseatInfosList(SparseArray info) { + mHotseatInfosList = info; + } + /** * Returns a stream of Multi Instance menu options if an app supports it. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt index 822ca6460f..f1ed6c5ea0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt +++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt @@ -26,6 +26,8 @@ class TaskbarSpecsEvaluator( numColumns: Int = taskbarActivityContext.deviceProfile.inv.numColumns, ) { var taskbarIconSize: TaskbarIconSize = getIconSizeByGrid(numColumns, numRows) + val numShownHotseatIcons + get() = taskbarActivityContext.deviceProfile.numShownHotseatIcons // TODO(b/341146605) : initialize it to taskbar container in later cl. private var taskbarContainer: List = emptyList() diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 019e7466dd..cac49f0dd0 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -48,7 +48,6 @@ 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.PIN_UNPIN_ITEM; import static com.android.launcher3.popup.SystemShortcut.PRIVATE_PROFILE_INSTALL; import static com.android.launcher3.popup.SystemShortcut.UNINSTALL_APP; import static com.android.launcher3.popup.SystemShortcut.WIDGETS; @@ -475,9 +474,6 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, List shortcuts = new ArrayList(Arrays.asList( APP_INFO, WellbeingModel.SHORTCUT_FACTORY, mHotseatPredictionController)); - if (Flags.enablePinningAppWithContextMenu()) { - shortcuts.add(0, PIN_UNPIN_ITEM); - } shortcuts.addAll(getSplitShortcuts()); shortcuts.add(WIDGETS); shortcuts.add(INSTALL); diff --git a/res/drawable/ic_unpin.xml b/res/drawable/ic_unpin.xml new file mode 100644 index 0000000000..557b4f9d76 --- /dev/null +++ b/res/drawable/ic_unpin.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index a02516a44f..3acdb0d192 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -235,8 +235,6 @@ Pin Prediction Bubble - - Pin to taskbar diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index 7e08c6ec20..b7efdecb8d 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -210,30 +210,6 @@ public abstract class SystemShortcut extends ItemInfo } } - public static final Factory PIN_UNPIN_ITEM = - (context, itemInfo, originalView) -> { - // Predicted items use {@code HotseatPredictionController.PinPrediction} shortcut - // to pin. - if (itemInfo.isPredictedItem()) { - return null; - } - return new PinUnpinItem<>(context, itemInfo, originalView); - }; - - private static class PinUnpinItem extends SystemShortcut { - PinUnpinItem(T target, ItemInfo itemInfo, @NonNull View originalView) { - // TODO(b/375648361): Check the pin state of the item to determine if the pin or the - // unpin option should be used. - super(R.drawable.ic_pin, R.string.pin_to_taskbar, target, - itemInfo, originalView); - } - - @Override - public void onClick(View view) { - // TODO(b/375648361): Pin/Unpin the item here. - } - } - public static final Factory PRIVATE_PROFILE_INSTALL = (context, itemInfo, originalView) -> { if (originalView == null) {