1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.launcher3.touch; 17 18 import static android.view.View.INVISIBLE; 19 import static android.view.View.VISIBLE; 20 21 import static com.android.launcher3.LauncherState.ALL_APPS; 22 import static com.android.launcher3.LauncherState.EDIT_MODE; 23 import static com.android.launcher3.LauncherState.NORMAL; 24 import static com.android.launcher3.LauncherState.OVERVIEW; 25 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_ITEM_LONG_PRESSED; 26 27 import android.graphics.Point; 28 import android.graphics.Rect; 29 import android.view.View; 30 import android.view.View.OnLongClickListener; 31 32 import com.android.launcher3.DragSource; 33 import com.android.launcher3.DropTarget; 34 import com.android.launcher3.Launcher; 35 import com.android.launcher3.celllayout.CellInfo; 36 import com.android.launcher3.config.FeatureFlags; 37 import com.android.launcher3.dragndrop.DragController; 38 import com.android.launcher3.dragndrop.DragOptions; 39 import com.android.launcher3.folder.Folder; 40 import com.android.launcher3.logging.StatsLogManager.StatsLogger; 41 import com.android.launcher3.model.data.ItemInfo; 42 import com.android.launcher3.model.data.PrivateSpaceInstallAppButtonInfo; 43 import com.android.launcher3.testing.TestLogging; 44 import com.android.launcher3.testing.shared.TestProtocol; 45 import com.android.launcher3.views.BubbleTextHolder; 46 import com.android.launcher3.widget.LauncherAppWidgetHostView; 47 import com.android.launcher3.widget.NavigableAppWidgetHostView; 48 import com.android.launcher3.widget.PendingItemDragHelper; 49 import com.android.launcher3.widget.WidgetCell; 50 import com.android.launcher3.widget.WidgetImageView; 51 52 /** 53 * Class to handle long-clicks on workspace items and start drag as a result. 54 */ 55 public class ItemLongClickListener { 56 57 public static final OnLongClickListener INSTANCE_WORKSPACE = 58 ItemLongClickListener::onWorkspaceItemLongClick; 59 60 public static final OnLongClickListener INSTANCE_ALL_APPS = 61 ItemLongClickListener::onAllAppsItemLongClick; 62 onWorkspaceItemLongClick(View v)63 private static boolean onWorkspaceItemLongClick(View v) { 64 if (v instanceof LauncherAppWidgetHostView) { 65 TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick"); 66 } else { 67 TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onWorkspaceItemLongClick"); 68 } 69 Launcher launcher = Launcher.getLauncher(v.getContext()); 70 if (!canStartDrag(launcher)) return false; 71 if (!launcher.isInState(NORMAL) 72 && !launcher.isInState(OVERVIEW) 73 && !launcher.isInState(EDIT_MODE)) { 74 return false; 75 } 76 if (!(v.getTag() instanceof ItemInfo)) return false; 77 78 launcher.setWaitingForResult(null); 79 beginDrag(v, launcher, (ItemInfo) v.getTag(), new DragOptions()); 80 return true; 81 } 82 beginDrag(View v, Launcher launcher, ItemInfo info, DragOptions dragOptions)83 public static void beginDrag(View v, Launcher launcher, ItemInfo info, 84 DragOptions dragOptions) { 85 if (info.container >= 0) { 86 Folder folder = Folder.getOpen(launcher); 87 if (folder != null) { 88 if (!folder.getIconsInReadingOrder().contains(v)) { 89 folder.close(true); 90 } else { 91 folder.startDrag(v, dragOptions); 92 return; 93 } 94 } 95 } 96 97 CellInfo longClickCellInfo = new CellInfo(v, info, 98 launcher.getCellPosMapper().mapModelToPresenter(info)); 99 launcher.getWorkspace().startDrag(longClickCellInfo, dragOptions); 100 } 101 onWidgetItemLongClick(WidgetCell v)102 private static boolean onWidgetItemLongClick(WidgetCell v) { 103 // Get the widget preview as the drag representation 104 WidgetImageView image = v.getWidgetView(); 105 Launcher launcher = Launcher.getLauncher(v.getContext()); 106 DragSource dragSource = (target, dragObject, success) -> { }; 107 108 // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and 109 // we abort the drag. 110 if (image.getDrawable() == null && v.getAppWidgetHostViewPreview() == null) { 111 return false; 112 } 113 114 PendingItemDragHelper dragHelper = new PendingItemDragHelper(v); 115 // RemoteViews are being rendered in AppWidgetHostView in WidgetCell. And thus, the scale of 116 // RemoteViews is equivalent to the AppWidgetHostView scale. 117 dragHelper.setRemoteViewsPreview(v.getRemoteViewsPreview(), v.getAppWidgetHostViewScale()); 118 dragHelper.setAppWidgetHostViewPreview(v.getAppWidgetHostViewPreview()); 119 120 if (image.getDrawable() != null) { 121 int[] loc = new int[2]; 122 launcher.getDragLayer().getLocationInDragLayer(image, loc); 123 124 dragHelper.startDrag(image.getBitmapBounds(), image.getDrawable().getIntrinsicWidth(), 125 image.getWidth(), new Point(loc[0], loc[1]), dragSource, new DragOptions()); 126 } else { 127 NavigableAppWidgetHostView preview = v.getAppWidgetHostViewPreview(); 128 int[] loc = new int[2]; 129 launcher.getDragLayer().getLocationInDragLayer(preview, loc); 130 Rect r = new Rect(); 131 preview.getWorkspaceVisualDragBounds(r); 132 dragHelper.startDrag(r, preview.getMeasuredWidth(), preview.getMeasuredWidth(), 133 new Point(loc[0], loc[1]), dragSource, new DragOptions()); 134 } 135 return true; 136 } 137 onAllAppsItemLongClick(View view)138 private static boolean onAllAppsItemLongClick(View view) { 139 if (view instanceof WidgetCell wc) { 140 return onWidgetItemLongClick(wc); 141 } 142 TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onAllAppsItemLongClick"); 143 view.cancelLongPress(); 144 View v = (view instanceof BubbleTextHolder) 145 ? ((BubbleTextHolder) view).getBubbleText() 146 : view; 147 Launcher launcher = Launcher.getLauncher(v.getContext()); 148 if (!canStartDrag(launcher)) return false; 149 // When we have exited all apps or are in transition, disregard long clicks 150 if (!launcher.isInState(ALL_APPS) && !launcher.isInState(OVERVIEW)) return false; 151 if (launcher.getWorkspace().isSwitchingState()) return false; 152 153 StatsLogger logger = launcher.getStatsLogManager().logger(); 154 if (v.getTag() instanceof ItemInfo itemInfo) { 155 if (itemInfo instanceof PrivateSpaceInstallAppButtonInfo) { 156 return false; 157 } 158 logger.withItemInfo((ItemInfo) v.getTag()); 159 } 160 logger.log(LAUNCHER_ALLAPPS_ITEM_LONG_PRESSED); 161 162 // Start the drag 163 final DragController dragController = launcher.getDragController(); 164 dragController.addDragListener(new DragController.DragListener() { 165 @Override 166 public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { 167 v.setVisibility(INVISIBLE); 168 } 169 170 @Override 171 public void onDragEnd() { 172 v.setVisibility(VISIBLE); 173 dragController.removeDragListener(this); 174 } 175 }); 176 177 launcher.getWorkspace().beginDragShared(v, launcher.getAppsView(), new DragOptions()); 178 return false; 179 } 180 canStartDrag(Launcher launcher)181 public static boolean canStartDrag(Launcher launcher) { 182 if (launcher == null) { 183 return false; 184 } 185 // We prevent dragging when we are loading the workspace as it is possible to pick up a view 186 // that is subsequently removed from the workspace in startBinding(). 187 if (launcher.isWorkspaceLocked()) return false; 188 // Return early if an item is already being dragged (e.g. when long-pressing two shortcuts) 189 if (launcher.getDragController().isDragging()) return false; 190 // Return early if user is in the middle of selecting split-screen apps 191 if (FeatureFlags.enableSplitContextually() && launcher.isSplitSelectionActive()) { 192 return false; 193 } 194 195 return true; 196 } 197 } 198