blob: 96aaee03b39c694dac3fa2ab8fe6a6029669459a [file] [log] [blame]
Sunny Goyal027fba32017-06-19 15:30:19 -07001/*
2 * Copyright (C) 2017 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
17package com.android.launcher3.dragndrop;
18
19import android.content.ClipDescription;
20import android.content.Intent;
21import android.graphics.Point;
22import android.graphics.Rect;
23import android.os.Handler;
24import android.os.Looper;
25import android.os.Parcel;
26import android.os.SystemClock;
27import android.util.Log;
28import android.view.DragEvent;
29import android.view.View;
30
Sunny Goyal027fba32017-06-19 15:30:19 -070031import com.android.launcher3.DragSource;
Sunny Goyal1797af42017-10-06 13:29:57 -070032import com.android.launcher3.DropTarget.DragObject;
Sunny Goyal027fba32017-06-19 15:30:19 -070033import com.android.launcher3.Launcher;
34import com.android.launcher3.R;
Sunny Goyal027fba32017-06-19 15:30:19 -070035import com.android.launcher3.widget.PendingItemDragHelper;
36
37import java.util.UUID;
38
39/**
40 * {@link DragSource} for handling drop from a different window.
41 */
42public abstract class BaseItemDragListener implements
43 View.OnDragListener, DragSource, DragOptions.PreDragCondition {
44
45 private static final String TAG = "BaseItemDragListener";
46
47 private static final String MIME_TYPE_PREFIX = "com.android.launcher3.drag_and_drop/";
48 public static final String EXTRA_PIN_ITEM_DRAG_LISTENER = "pin_item_drag_listener";
49
50 // Position of preview relative to the touch location
51 private final Rect mPreviewRect;
52
53 private final int mPreviewBitmapWidth;
54 private final int mPreviewViewWidth;
55
56 // Randomly generated id used to verify the drag event.
57 private final String mId;
58
59 protected Launcher mLauncher;
60 private DragController mDragController;
61 private long mDragStartTime;
62
63 public BaseItemDragListener(Rect previewRect, int previewBitmapWidth, int previewViewWidth) {
64 mPreviewRect = previewRect;
65 mPreviewBitmapWidth = previewBitmapWidth;
66 mPreviewViewWidth = previewViewWidth;
67 mId = UUID.randomUUID().toString();
68 }
69
70 protected BaseItemDragListener(Parcel parcel) {
71 mPreviewRect = Rect.CREATOR.createFromParcel(parcel);
72 mPreviewBitmapWidth = parcel.readInt();
73 mPreviewViewWidth = parcel.readInt();
74 mId = parcel.readString();
75 }
76
77 protected void writeToParcel(Parcel parcel, int i) {
78 mPreviewRect.writeToParcel(parcel, i);
79 parcel.writeInt(mPreviewBitmapWidth);
80 parcel.writeInt(mPreviewViewWidth);
81 parcel.writeString(mId);
82 }
83
84 public String getMimeType() {
85 return MIME_TYPE_PREFIX + mId;
86 }
87
88 public void setLauncher(Launcher launcher) {
89 mLauncher = launcher;
90 mDragController = launcher.getDragController();
91 }
92
93 @Override
94 public boolean onDrag(View view, DragEvent event) {
95 if (mLauncher == null || mDragController == null) {
96 postCleanup();
97 return false;
98 }
99 if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) {
100 if (onDragStart(event)) {
101 return true;
102 } else {
103 postCleanup();
104 return false;
105 }
106 }
107 return mDragController.onDragEvent(mDragStartTime, event);
108 }
109
110 protected boolean onDragStart(DragEvent event) {
111 ClipDescription desc = event.getClipDescription();
112 if (desc == null || !desc.hasMimeType(getMimeType())) {
113 Log.e(TAG, "Someone started a dragAndDrop before us.");
114 return false;
115 }
116
117 Point downPos = new Point((int) event.getX(), (int) event.getY());
118 DragOptions options = new DragOptions();
119 options.systemDndStartPoint = downPos;
120 options.preDragCondition = this;
121
122 // We use drag event position as the screenPos for the preview image. Since mPreviewRect
123 // already includes the view position relative to the drag event on the source window,
124 // and the absolute position (position relative to the screen) of drag event is same
125 // across windows, using drag position here give a good estimate for relative position
126 // to source window.
127 createDragHelper().startDrag(new Rect(mPreviewRect),
128 mPreviewBitmapWidth, mPreviewViewWidth, downPos, this, options);
129 mDragStartTime = SystemClock.uptimeMillis();
130 return true;
131 }
132
133 protected abstract PendingItemDragHelper createDragHelper();
134
135 @Override
136 public boolean shouldStartDrag(double distanceDragged) {
137 // Stay in pre-drag mode, if workspace is locked.
138 return !mLauncher.isWorkspaceLocked();
139 }
140
141 @Override
Sunny Goyal1797af42017-10-06 13:29:57 -0700142 public void onPreDragStart(DragObject dragObject) {
Sunny Goyal027fba32017-06-19 15:30:19 -0700143 // The predrag starts when the workspace is not yet loaded. In some cases we set
144 // the dragLayer alpha to 0 to have a nice fade-in animation. But that will prevent the
145 // dragView from being visible. Instead just skip the fade-in animation here.
146 mLauncher.getDragLayer().setAlpha(1);
147
148 dragObject.dragView.setColor(
149 mLauncher.getResources().getColor(R.color.delete_target_hover_tint));
150 }
151
152 @Override
Sunny Goyal1797af42017-10-06 13:29:57 -0700153 public void onPreDragEnd(DragObject dragObject, boolean dragStarted) {
Sunny Goyal027fba32017-06-19 15:30:19 -0700154 if (dragStarted) {
155 dragObject.dragView.setColor(0);
156 }
157 }
158
159 @Override
Sunny Goyal1797af42017-10-06 13:29:57 -0700160 public void onDropCompleted(View target, DragObject d, boolean success) {
Sunny Goyal027fba32017-06-19 15:30:19 -0700161 postCleanup();
162 }
163
164 private void postCleanup() {
165 if (mLauncher != null) {
166 // Remove any drag params from the launcher intent since the drag operation is complete.
167 Intent newIntent = new Intent(mLauncher.getIntent());
168 newIntent.removeExtra(EXTRA_PIN_ITEM_DRAG_LISTENER);
169 mLauncher.setIntent(newIntent);
170 }
171
172 new Handler(Looper.getMainLooper()).post(new Runnable() {
173 @Override
174 public void run() {
175 removeListener();
176 }
177 });
178 }
179
180 public void removeListener() {
181 if (mLauncher != null) {
182 mLauncher.getDragLayer().setOnDragListener(null);
183 }
184 }
185}