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.view.View; 28 import android.view.View.OnLongClickListener; 29 30 import com.android.launcher3.CellLayout; 31 import com.android.launcher3.DropTarget; 32 import com.android.launcher3.Launcher; 33 import com.android.launcher3.dragndrop.DragController; 34 import com.android.launcher3.dragndrop.DragOptions; 35 import com.android.launcher3.folder.Folder; 36 import com.android.launcher3.logging.StatsLogManager.StatsLogger; 37 import com.android.launcher3.model.data.ItemInfo; 38 import com.android.launcher3.testing.TestLogging; 39 import com.android.launcher3.testing.shared.TestProtocol; 40 import com.android.launcher3.views.BubbleTextHolder; 41 import com.android.launcher3.widget.LauncherAppWidgetHostView; 42 43 /** 44 * Class to handle long-clicks on workspace items and start drag as a result. 45 */ 46 public class ItemLongClickListener { 47 48 public static final OnLongClickListener INSTANCE_WORKSPACE = 49 ItemLongClickListener::onWorkspaceItemLongClick; 50 51 public static final OnLongClickListener INSTANCE_ALL_APPS = 52 ItemLongClickListener::onAllAppsItemLongClick; 53 onWorkspaceItemLongClick(View v)54 private static boolean onWorkspaceItemLongClick(View v) { 55 if (v instanceof LauncherAppWidgetHostView) { 56 TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick"); 57 } else { 58 TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onWorkspaceItemLongClick"); 59 } 60 Launcher launcher = Launcher.getLauncher(v.getContext()); 61 if (!canStartDrag(launcher)) return false; 62 if (!launcher.isInState(NORMAL) 63 && !launcher.isInState(OVERVIEW) 64 && !launcher.isInState(EDIT_MODE)) { 65 return false; 66 } 67 if (!(v.getTag() instanceof ItemInfo)) return false; 68 69 launcher.setWaitingForResult(null); 70 beginDrag(v, launcher, (ItemInfo) v.getTag(), new DragOptions()); 71 return true; 72 } 73 beginDrag(View v, Launcher launcher, ItemInfo info, DragOptions dragOptions)74 public static void beginDrag(View v, Launcher launcher, ItemInfo info, 75 DragOptions dragOptions) { 76 if (info.container >= 0) { 77 Folder folder = Folder.getOpen(launcher); 78 if (folder != null) { 79 if (!folder.getIconsInReadingOrder().contains(v)) { 80 folder.close(true); 81 } else { 82 folder.startDrag(v, dragOptions); 83 return; 84 } 85 } 86 } 87 88 CellLayout.CellInfo longClickCellInfo = new CellLayout.CellInfo(v, info, 89 launcher.getCellPosMapper().mapModelToPresenter(info)); 90 launcher.getWorkspace().startDrag(longClickCellInfo, dragOptions); 91 } 92 onAllAppsItemLongClick(View view)93 private static boolean onAllAppsItemLongClick(View view) { 94 TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onAllAppsItemLongClick"); 95 view.cancelLongPress(); 96 View v = (view instanceof BubbleTextHolder) 97 ? ((BubbleTextHolder) view).getBubbleText() 98 : view; 99 Launcher launcher = Launcher.getLauncher(v.getContext()); 100 if (!canStartDrag(launcher)) return false; 101 // When we have exited all apps or are in transition, disregard long clicks 102 if (!launcher.isInState(ALL_APPS) && !launcher.isInState(OVERVIEW)) return false; 103 if (launcher.getWorkspace().isSwitchingState()) return false; 104 105 StatsLogger logger = launcher.getStatsLogManager().logger(); 106 if (v.getTag() instanceof ItemInfo) { 107 logger.withItemInfo((ItemInfo) v.getTag()); 108 } 109 logger.log(LAUNCHER_ALLAPPS_ITEM_LONG_PRESSED); 110 111 // Start the drag 112 final DragController dragController = launcher.getDragController(); 113 dragController.addDragListener(new DragController.DragListener() { 114 @Override 115 public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { 116 v.setVisibility(INVISIBLE); 117 } 118 119 @Override 120 public void onDragEnd() { 121 v.setVisibility(VISIBLE); 122 dragController.removeDragListener(this); 123 } 124 }); 125 126 launcher.getWorkspace().beginDragShared(v, launcher.getAppsView(), new DragOptions()); 127 return false; 128 } 129 canStartDrag(Launcher launcher)130 public static boolean canStartDrag(Launcher launcher) { 131 if (launcher == null) { 132 return false; 133 } 134 // We prevent dragging when we are loading the workspace as it is possible to pick up a view 135 // that is subsequently removed from the workspace in startBinding(). 136 if (launcher.isWorkspaceLocked()) return false; 137 // Return early if an item is already being dragged (e.g. when long-pressing two shortcuts) 138 if (launcher.getDragController().isDragging()) return false; 139 140 return true; 141 } 142 } 143