blob: 2c018f882bd285f41e3117eb1aff348a761c2c0e [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;
20import android.util.Log;
21import android.view.DragEvent;
22import android.view.View;
23import android.view.View.OnDragListener;
24import android.view.ViewConfiguration;
25
26import com.android.documentsui.ItemDragListener.DragHost;
27import com.android.internal.annotations.VisibleForTesting;
28
29import java.util.Timer;
30import java.util.TimerTask;
31
32/**
33 * An {@link OnDragListener} that adds support for "spring loading views". Use this when you want
34 * items to pop-open when user hovers on them during a drag n drop.
35 */
36public class ItemDragListener<H extends DragHost> implements OnDragListener {
37
38 private static final String TAG = "ItemDragListener";
39
40 @VisibleForTesting
41 static final int SPRING_TIMEOUT = ViewConfiguration.getLongPressTimeout();
42
43 protected final H mDragHost;
44 private final Timer mHoverTimer;
45
46 public ItemDragListener(H dragHost) {
47 this(dragHost, new Timer());
48 }
49
50 @VisibleForTesting
51 protected ItemDragListener(H dragHost, Timer timer) {
52 mDragHost = dragHost;
53 mHoverTimer = timer;
54 }
55
56 @Override
57 public boolean onDrag(final View v, DragEvent event) {
58 switch (event.getAction()) {
59 case DragEvent.ACTION_DRAG_STARTED:
60 return true;
61 case DragEvent.ACTION_DRAG_ENTERED:
62 handleEnteredEvent(v);
63 return true;
64 case DragEvent.ACTION_DRAG_LOCATION:
65 return true;
66 case DragEvent.ACTION_DRAG_EXITED:
67 case DragEvent.ACTION_DRAG_ENDED:
68 handleExitedEndedEvent(v);
69 return true;
70 case DragEvent.ACTION_DROP:
71 return handleDropEvent(v, event);
72 }
73
74 return false;
75 }
76
77 private void handleEnteredEvent(View v) {
78 mDragHost.setDropTargetHighlight(v, true);
79
80 TimerTask task = createOpenTask(v);
81 assert (task != null);
82 v.setTag(R.id.drag_hovering_tag, task);
83 mHoverTimer.schedule(task, ViewConfiguration.getLongPressTimeout());
84 }
85
86 private void handleExitedEndedEvent(View v) {
87 mDragHost.setDropTargetHighlight(v, false);
88
89 TimerTask task = (TimerTask) v.getTag(R.id.drag_hovering_tag);
90 if (task != null) {
91 task.cancel();
92 }
93 }
94
95 private boolean handleDropEvent(View v, DragEvent event) {
96 ClipData clipData = event.getClipData();
97 if (clipData == null) {
98 Log.w(TAG, "Received invalid drop event with null clipdata. Ignoring.");
99 return false;
100 }
101
102 return handleDropEventChecked(v, event);
103 }
104
105 @VisibleForTesting
106 TimerTask createOpenTask(final View v) {
107 TimerTask task = new TimerTask() {
108 @Override
109 public void run() {
110 mDragHost.runOnUiThread(() -> {
111 mDragHost.onViewHovered(v);
112 });
113 }
114 };
115 return task;
116 }
117
118 /**
119 * Handles a drop event. Override it if you want to do something on drop event. It's called when
120 * {@link DragEvent#ACTION_DROP} happens. ClipData in DragEvent is guaranteed not null.
121 *
122 * @param v The view where user drops.
123 * @param event the drag event.
124 * @return true if this event is consumed; false otherwise
125 */
126 public boolean handleDropEventChecked(View v, DragEvent event) {
127 return false; // we didn't handle the drop
128 }
129
130 /**
131 * An interface {@link ItemDragListener} uses to make some callbacks.
132 */
133 public interface DragHost {
134
135 /**
136 * Runs this runnable in main thread.
137 */
138 void runOnUiThread(Runnable runnable);
139
140 /**
141 * Highlights/unhighlights the view to visually indicate this view is being hovered.
142 * @param v the view being hovered
143 * @param highlight true if highlight the view; false if unhighlight it
144 */
145 void setDropTargetHighlight(View v, boolean highlight);
146
147 /**
148 * Notifies hovering timeout has elapsed
149 * @param v the view being hovered
150 */
151 void onViewHovered(View v);
152 }
153}