blob: 79f71d9649db34866ec7fd6b7fb778f65109c28c [file] [log] [blame]
Garfield, Tan804133e2016-04-20 15:13:56 -07001/*
2 * Copyright (C) 2016 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.documentsui;
18
19import android.content.ClipData;
Garfield, Tan57facaf72016-05-27 15:02:35 -070020import android.graphics.drawable.Drawable;
Garfield, Tan804133e2016-04-20 15:13:56 -070021import android.util.Log;
22import android.view.DragEvent;
23import android.view.View;
24import android.view.View.OnDragListener;
Garfield, Tan804133e2016-04-20 15:13:56 -070025
26import com.android.documentsui.ItemDragListener.DragHost;
27import com.android.internal.annotations.VisibleForTesting;
28
29import java.util.Timer;
30import java.util.TimerTask;
31
Ben Lin5a305b42016-09-08 11:33:07 -070032import javax.annotation.Nullable;
33
Garfield, Tan804133e2016-04-20 15:13:56 -070034/**
35 * An {@link OnDragListener} that adds support for "spring loading views". Use this when you want
36 * items to pop-open when user hovers on them during a drag n drop.
37 */
38public class ItemDragListener<H extends DragHost> implements OnDragListener {
39
40 private static final String TAG = "ItemDragListener";
41
42 @VisibleForTesting
Ben Lin7f72a3c2016-09-27 16:37:28 -070043 static final int SPRING_TIMEOUT = 1500;
Garfield, Tan804133e2016-04-20 15:13:56 -070044
45 protected final H mDragHost;
46 private final Timer mHoverTimer;
47
48 public ItemDragListener(H dragHost) {
49 this(dragHost, new Timer());
50 }
51
52 @VisibleForTesting
53 protected ItemDragListener(H dragHost, Timer timer) {
54 mDragHost = dragHost;
55 mHoverTimer = timer;
56 }
57
58 @Override
59 public boolean onDrag(final View v, DragEvent event) {
60 switch (event.getAction()) {
61 case DragEvent.ACTION_DRAG_STARTED:
62 return true;
63 case DragEvent.ACTION_DRAG_ENTERED:
Ben Lin5a305b42016-09-08 11:33:07 -070064 handleEnteredEvent(v, event);
Garfield, Tan804133e2016-04-20 15:13:56 -070065 return true;
66 case DragEvent.ACTION_DRAG_LOCATION:
Garfield, Tan57facaf72016-05-27 15:02:35 -070067 handleLocationEvent(v, event.getX(), event.getY());
Garfield, Tan804133e2016-04-20 15:13:56 -070068 return true;
69 case DragEvent.ACTION_DRAG_EXITED:
70 case DragEvent.ACTION_DRAG_ENDED:
71 handleExitedEndedEvent(v);
72 return true;
73 case DragEvent.ACTION_DROP:
74 return handleDropEvent(v, event);
75 }
76
77 return false;
78 }
79
Ben Lin5a305b42016-09-08 11:33:07 -070080 private void handleEnteredEvent(View v, DragEvent event) {
Ben Lin1c456292016-10-07 16:43:18 -070081 mDragHost.onDragEntered(v, event.getLocalState());
Ben Lin5a305b42016-09-08 11:33:07 -070082 @Nullable TimerTask task = createOpenTask(v, event);
83 if (task == null) {
84 return;
85 }
Garfield, Tan804133e2016-04-20 15:13:56 -070086 mDragHost.setDropTargetHighlight(v, true);
Garfield, Tan804133e2016-04-20 15:13:56 -070087 v.setTag(R.id.drag_hovering_tag, task);
Garfield, Tana5588b62016-07-13 09:23:04 -070088 mHoverTimer.schedule(task, SPRING_TIMEOUT);
Garfield, Tan804133e2016-04-20 15:13:56 -070089 }
90
Garfield, Tan57facaf72016-05-27 15:02:35 -070091 private void handleLocationEvent(View v, float x, float y) {
92 Drawable background = v.getBackground();
93 if (background != null) {
94 background.setHotspot(x, y);
95 }
96 }
97
Garfield, Tan804133e2016-04-20 15:13:56 -070098 private void handleExitedEndedEvent(View v) {
99 mDragHost.setDropTargetHighlight(v, false);
100
101 TimerTask task = (TimerTask) v.getTag(R.id.drag_hovering_tag);
102 if (task != null) {
103 task.cancel();
104 }
105 }
106
107 private boolean handleDropEvent(View v, DragEvent event) {
108 ClipData clipData = event.getClipData();
109 if (clipData == null) {
110 Log.w(TAG, "Received invalid drop event with null clipdata. Ignoring.");
111 return false;
112 }
113
114 return handleDropEventChecked(v, event);
115 }
116
Ben Lin5a305b42016-09-08 11:33:07 -0700117 /**
118 * Sub-classes such as {@link DirectoryDragListener} can override this method and return null.
119 */
120 public @Nullable TimerTask createOpenTask(final View v, DragEvent event) {
Garfield, Tan804133e2016-04-20 15:13:56 -0700121 TimerTask task = new TimerTask() {
122 @Override
123 public void run() {
124 mDragHost.runOnUiThread(() -> {
125 mDragHost.onViewHovered(v);
126 });
127 }
128 };
129 return task;
130 }
131
132 /**
133 * Handles a drop event. Override it if you want to do something on drop event. It's called when
134 * {@link DragEvent#ACTION_DROP} happens. ClipData in DragEvent is guaranteed not null.
135 *
136 * @param v The view where user drops.
137 * @param event the drag event.
138 * @return true if this event is consumed; false otherwise
139 */
140 public boolean handleDropEventChecked(View v, DragEvent event) {
141 return false; // we didn't handle the drop
142 }
143
144 /**
145 * An interface {@link ItemDragListener} uses to make some callbacks.
146 */
147 public interface DragHost {
148
149 /**
150 * Runs this runnable in main thread.
151 */
152 void runOnUiThread(Runnable runnable);
153
154 /**
155 * Highlights/unhighlights the view to visually indicate this view is being hovered.
156 * @param v the view being hovered
157 * @param highlight true if highlight the view; false if unhighlight it
158 */
159 void setDropTargetHighlight(View v, boolean highlight);
160
161 /**
162 * Notifies hovering timeout has elapsed
163 * @param v the view being hovered
164 */
165 void onViewHovered(View v);
Ben Lin7f72a3c2016-09-27 16:37:28 -0700166
167 /**
168 * Notifies right away when drag shadow enters the view
169 * @param v the view which drop shadow just entered
Ben Lin1c456292016-10-07 16:43:18 -0700170 * @param localState the Local state object given by DragEvent
Ben Lin7f72a3c2016-09-27 16:37:28 -0700171 */
Ben Lin1c456292016-10-07 16:43:18 -0700172 void onDragEntered(View v, Object localState);
Garfield, Tan804133e2016-04-20 15:13:56 -0700173 }
174}