1 /*
2  * Copyright (C) 2022 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 
17 package com.android.launcher3.secondarydisplay;
18 
19 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
20 
21 import android.content.res.Resources;
22 import android.graphics.Rect;
23 import android.graphics.drawable.Drawable;
24 import android.view.HapticFeedbackConstants;
25 import android.view.View;
26 
27 import androidx.annotation.Nullable;
28 
29 import com.android.launcher3.AbstractFloatingView;
30 import com.android.launcher3.DragSource;
31 import com.android.launcher3.DropTarget;
32 import com.android.launcher3.R;
33 import com.android.launcher3.accessibility.DragViewStateAnnouncer;
34 import com.android.launcher3.dragndrop.DragController;
35 import com.android.launcher3.dragndrop.DragDriver;
36 import com.android.launcher3.dragndrop.DragOptions;
37 import com.android.launcher3.dragndrop.DragView;
38 import com.android.launcher3.dragndrop.DraggableView;
39 import com.android.launcher3.model.data.ItemInfo;
40 
41 /**
42  * Drag controller for Secondary Launcher activity
43  */
44 public class SecondaryDragController extends DragController<SecondaryDisplayLauncher> {
45 
46     private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
47 
SecondaryDragController(SecondaryDisplayLauncher secondaryLauncher)48     public SecondaryDragController(SecondaryDisplayLauncher secondaryLauncher) {
49         super(secondaryLauncher);
50     }
51 
52     @Override
startDrag(@ullable Drawable drawable, @Nullable View view, DraggableView originalView, int dragLayerX, int dragLayerY, DragSource source, ItemInfo dragInfo, Rect dragRegion, float initialDragViewScale, float dragViewScaleOnDrop, DragOptions options)53     protected DragView startDrag(@Nullable Drawable drawable, @Nullable View view,
54             DraggableView originalView, int dragLayerX, int dragLayerY, DragSource source,
55             ItemInfo dragInfo, Rect dragRegion, float initialDragViewScale,
56             float dragViewScaleOnDrop, DragOptions options) {
57         if (PROFILE_DRAWING_DURING_DRAG) {
58             android.os.Debug.startMethodTracing("Launcher");
59         }
60         mActivity.hideKeyboard();
61 
62         mOptions = options;
63         if (mOptions.simulatedDndStartPoint != null) {
64             mLastTouch.x = mMotionDown.x = mOptions.simulatedDndStartPoint.x;
65             mLastTouch.y = mMotionDown.y = mOptions.simulatedDndStartPoint.y;
66         }
67 
68         final int registrationX = mMotionDown.x - dragLayerX;
69         final int registrationY = mMotionDown.y - dragLayerY;
70 
71         final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
72         final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
73 
74         mLastDropTarget = null;
75 
76         mDragObject = new DropTarget.DragObject(mActivity.getApplicationContext());
77         mDragObject.originalView = originalView;
78 
79         mIsInPreDrag = mOptions.preDragCondition != null
80                 && !mOptions.preDragCondition.shouldStartDrag(0);
81 
82         final Resources res = mActivity.getResources();
83         final float scaleDps = mIsInPreDrag
84                 ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f;
85 
86         final DragView dragView = mDragObject.dragView = drawable != null
87                 ? new SecondaryDragView(
88                 mActivity,
89                 drawable,
90                 registrationX,
91                 registrationY,
92                 initialDragViewScale,
93                 dragViewScaleOnDrop,
94                 scaleDps)
95                 : new SecondaryDragView(
96                         mActivity,
97                         view,
98                         view.getMeasuredWidth(),
99                         view.getMeasuredHeight(),
100                         registrationX,
101                         registrationY,
102                         initialDragViewScale,
103                         dragViewScaleOnDrop,
104                         scaleDps);
105         dragView.setItemInfo(dragInfo);
106         mDragObject.dragComplete = false;
107 
108         mDragObject.xOffset = mMotionDown.x - (dragLayerX + dragRegionLeft);
109         mDragObject.yOffset = mMotionDown.y - (dragLayerY + dragRegionTop);
110 
111         mDragDriver = DragDriver.create(this, mOptions, ev -> {
112         });
113         if (!mOptions.isAccessibleDrag) {
114             mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView);
115         }
116 
117         mDragObject.dragSource = source;
118         mDragObject.dragInfo = dragInfo;
119         mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy();
120 
121         if (mOptions.preDragCondition != null) {
122             dragView.setHasDragOffset(mOptions.preDragCondition.getDragOffset().x != 0 ||
123                     mOptions.preDragCondition.getDragOffset().y != 0);
124         }
125 
126         if (dragRegion != null) {
127             dragView.setDragRegion(new Rect(dragRegion));
128         }
129 
130         mActivity.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
131         dragView.show(mLastTouch.x, mLastTouch.y);
132         mDistanceSinceScroll = 0;
133 
134         if (!isItemPinnable()) {
135             MAIN_EXECUTOR.post(this:: cancelDrag);
136         }
137 
138         if (!mIsInPreDrag) {
139             callOnDragStart();
140         } else if (mOptions.preDragCondition != null) {
141             mOptions.preDragCondition.onPreDragStart(mDragObject);
142         }
143 
144         handleMoveEvent(mLastTouch.x, mLastTouch.y);
145         return dragView;
146     }
147 
148     @Override
exitDrag()149     protected void exitDrag() { }
150 
151     @Override
getDefaultDropTarget(int[] dropCoordinates)152     protected DropTarget getDefaultDropTarget(int[] dropCoordinates) {
153         DropTarget target = new DropTarget() {
154             @Override
155             public boolean isDropEnabled() {
156                 return true;
157             }
158 
159             @Override
160             public void onDrop(DragObject dragObject, DragOptions options) {
161                 ((SecondaryDragLayer) mActivity.getDragLayer()).getPinnedAppsAdapter().addPinnedApp(
162                         dragObject.dragInfo);
163                 dragObject.dragView.remove();
164             }
165 
166             @Override
167             public void onDragEnter(DragObject dragObject) {
168                 if (getDistanceDragged() > mActivity.getResources().getDimensionPixelSize(
169                         R.dimen.drag_distanceThreshold)) {
170                     mActivity.showAppDrawer(false);
171                     AbstractFloatingView.closeAllOpenViews(mActivity);
172                 }
173             }
174 
175             @Override
176             public void onDragOver(DragObject dragObject) { }
177 
178             @Override
179             public void onDragExit(DragObject dragObject) { }
180 
181             @Override
182             public boolean acceptDrop(DragObject dragObject) {
183                 return true;
184             }
185 
186             @Override
187             public void prepareAccessibilityDrop() { }
188 
189             @Override
190             public void getHitRectRelativeToDragLayer(Rect outRect) { }
191         };
192         return target;
193     }
194 }
195