DragEvent.java revision 855e4c98846a4264b7a27ad68cfa66c12ac0591c
1/* 2 * Copyright (C) 2010 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 android.view; 18 19import android.content.ClipData; 20import android.content.ClipDescription; 21import android.os.Parcel; 22import android.os.Parcelable; 23 24/** !!! TODO: real docs */ 25public class DragEvent implements Parcelable { 26 private static final boolean TRACK_RECYCLED_LOCATION = false; 27 28 int mAction; 29 float mX, mY; 30 ClipDescription mClipDescription; 31 ClipData mClipData; 32 boolean mDragResult; 33 34 private DragEvent mNext; 35 private RuntimeException mRecycledLocation; 36 private boolean mRecycled; 37 38 private static final int MAX_RECYCLED = 10; 39 private static final Object gRecyclerLock = new Object(); 40 private static int gRecyclerUsed = 0; 41 private static DragEvent gRecyclerTop = null; 42 43 /** 44 * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose 45 * action is ACTION_DRAG_STARTED means that a drag operation has been initiated. The 46 * view receiving this DragEvent should inspect the metadata of the dragged content, 47 * available via {@link #getClipDescription()}, and return {@code true} from 48 * {@link View#onDragEvent(DragEvent)} if the view is prepared to accept a drop of 49 * that clip data. If the view chooses to present a visual indication that it is 50 * a valid target of the ongoing drag, then it should draw that indication in response 51 * to this event. 52 * <p> 53 * A view will only receive ACTION_DRAG_ENTERED, ACTION_DRAG_LOCATION, ACTION_DRAG_EXITED, 54 * and ACTION_DRAG_LOCATION events if it returns {@code true} in response to the 55 * ACTION_DRAG_STARTED event. 56 */ 57 public static final int ACTION_DRAG_STARTED = 1; 58 59 /** 60 * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose 61 * action is ACTION_DRAG_LOCATION means that the drag operation is currently hovering 62 * over the view. The {@link #getX()} and {@link #getY()} methods supply the location 63 * of the drag point within the view's coordinate system. 64 * <p> 65 * A view will receive an ACTION_DRAG_ENTERED event before receiving any 66 * ACTION_DRAG_LOCATION events. If the drag point leaves the view, then an 67 * ACTION_DRAG_EXITED event is delivered to the view, after which no more 68 * ACTION_DRAG_LOCATION events will be sent (unless the drag re-enters the view, 69 * of course). 70 */ 71 public static final int ACTION_DRAG_LOCATION = 2; 72 73 /** 74 * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose 75 * action is ACTION_DROP means that the dragged content has been dropped on this view. 76 * The view should retrieve the content via {@link #getClipData()} and act on it 77 * appropriately. The {@link #getX()} and {@link #getY()} methods supply the location 78 * of the drop point within the view's coordinate system. 79 * <p> 80 * The view should return {@code true} from its {@link View#onDragEvent(DragEvent)} 81 * method in response to this event if it accepted the content, and {@code false} 82 * if it ignored the drop. 83 */ 84 public static final int ACTION_DROP = 3; 85 86 /** 87 * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose 88 * action is ACTION_DRAG_ENDED means that the drag operation has concluded. A view 89 * that is drawing a visual indication of drag acceptance should return to its usual 90 * drawing state in response to this event. 91 * <p> 92 * All views that received an ACTION_DRAG_STARTED event will receive the 93 * ACTION_DRAG_ENDED event even if they are not currently visible when the drag 94 * ends. 95 */ 96 public static final int ACTION_DRAG_ENDED = 4; 97 98 /** 99 * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose 100 * action is ACTION_DRAG_ENTERED means that the drag point has entered the view's 101 * bounds. If the view changed its visual state in response to the ACTION_DRAG_ENTERED 102 * event, it should return to its normal drag-in-progress visual state in response to 103 * this event. 104 * <p> 105 * A view will receive an ACTION_DRAG_ENTERED event before receiving any 106 * ACTION_DRAG_LOCATION events. If the drag point leaves the view, then an 107 * ACTION_DRAG_EXITED event is delivered to the view, after which no more 108 * ACTION_DRAG_LOCATION events will be sent (unless the drag re-enters the view, 109 * of course). 110 */ 111 public static final int ACTION_DRAG_ENTERED = 5; 112 113 /** 114 * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose 115 * action is ACTION_DRAG_ENTERED means that the drag point has entered the view's 116 * bounds. If the view chooses to present a visual indication that it will receive 117 * the drop if it occurs now, then it should draw that indication in response to 118 * this event. 119 * <p> 120 * A view will receive an ACTION_DRAG_ENTERED event before receiving any 121 * ACTION_DRAG_LOCATION events. If the drag point leaves the view, then an 122 * ACTION_DRAG_EXITED event is delivered to the view, after which no more 123 * ACTION_DRAG_LOCATION events will be sent (unless the drag re-enters the view, 124 * of course). 125 */ 126public static final int ACTION_DRAG_EXITED = 6; 127 128 private DragEvent() { 129 } 130 131 private void init(int action, float x, float y, ClipDescription description, ClipData data, 132 boolean result) { 133 mAction = action; 134 mX = x; 135 mY = y; 136 mClipDescription = description; 137 mClipData = data; 138 mDragResult = result; 139 } 140 141 static DragEvent obtain() { 142 return DragEvent.obtain(0, 0f, 0f, null, null, false); 143 } 144 145 /** @hide */ 146 public static DragEvent obtain(int action, float x, float y, 147 ClipDescription description, ClipData data, boolean result) { 148 final DragEvent ev; 149 synchronized (gRecyclerLock) { 150 if (gRecyclerTop == null) { 151 ev = new DragEvent(); 152 ev.init(action, x, y, description, data, result); 153 return ev; 154 } 155 ev = gRecyclerTop; 156 gRecyclerTop = ev.mNext; 157 gRecyclerUsed -= 1; 158 } 159 ev.mRecycledLocation = null; 160 ev.mRecycled = false; 161 ev.mNext = null; 162 163 ev.init(action, x, y, description, data, result); 164 165 return ev; 166 } 167 168 /** @hide */ 169 public static DragEvent obtain(DragEvent source) { 170 return obtain(source.mAction, source.mX, source.mY, 171 source.mClipDescription, source.mClipData, source.mDragResult); 172 } 173 174 /** 175 * Inspect the action value of this event. 176 * @return One of {@link #ACTION_DRAG_STARTED}, {@link #ACTION_DRAG_ENDED}, 177 * {@link #ACTION_DROP}, {@link #ACTION_DRAG_ENTERED}, {@link #ACTION_DRAG_EXITED}, 178 * or {@link #ACTION_DRAG_LOCATION}. 179 */ 180 public int getAction() { 181 return mAction; 182 } 183 184 /** 185 * For ACTION_DRAG_LOCATION and ACTION_DROP events, returns the x coordinate of the 186 * drag point. 187 * @return The current drag point's x coordinate, when relevant. 188 */ 189 public float getX() { 190 return mX; 191 } 192 193 /** 194 * For ACTION_DRAG_LOCATION and ACTION_DROP events, returns the y coordinate of the 195 * drag point. 196 * @return The current drag point's y coordinate, when relevant. 197 */ 198 public float getY() { 199 return mY; 200 } 201 202 /** 203 * Provides the data payload of the drag operation. This payload is only available 204 * for events whose action value is ACTION_DROP. 205 * @return The ClipData containing the data being dropped on the view. 206 */ 207 public ClipData getClipData() { 208 return mClipData; 209 } 210 211 /** 212 * Provides a description of the drag operation's data payload. This payload is 213 * available for all DragEvents other than ACTION_DROP. 214 * @return A ClipDescription describing the contents of the data being dragged. 215 */ 216 public ClipDescription getClipDescription() { 217 return mClipDescription; 218 } 219 220 /** 221 * Provides an indication of whether the drag operation concluded successfully. 222 * This method is only available on ACTION_DRAG_ENDED events. 223 * @return {@code true} if the drag operation ended with an accepted drop; {@code false} 224 * otherwise. 225 */ 226 public boolean getResult() { 227 return mDragResult; 228 } 229 230 /** 231 * Recycle the DragEvent, to be re-used by a later caller. After calling 232 * this function you must never touch the event again. 233 * 234 * @hide 235 */ 236 public final void recycle() { 237 // Ensure recycle is only called once! 238 if (TRACK_RECYCLED_LOCATION) { 239 if (mRecycledLocation != null) { 240 throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation); 241 } 242 mRecycledLocation = new RuntimeException("Last recycled here"); 243 } else { 244 if (mRecycled) { 245 throw new RuntimeException(toString() + " recycled twice!"); 246 } 247 mRecycled = true; 248 } 249 250 mClipData = null; 251 mClipDescription = null; 252 253 synchronized (gRecyclerLock) { 254 if (gRecyclerUsed < MAX_RECYCLED) { 255 gRecyclerUsed++; 256 mNext = gRecyclerTop; 257 gRecyclerTop = this; 258 } 259 } 260 } 261 262 @Override 263 public String toString() { 264 return "DragEvent{" + Integer.toHexString(System.identityHashCode(this)) 265 + " action=" + mAction + " @ (" + mX + ", " + mY + ") desc=" + mClipDescription 266 + " data=" + mClipData + " result=" + mDragResult 267 + "}"; 268 } 269 270 /* Parcelable interface */ 271 272 public int describeContents() { 273 return 0; 274 } 275 276 public void writeToParcel(Parcel dest, int flags) { 277 dest.writeInt(mAction); 278 dest.writeFloat(mX); 279 dest.writeFloat(mY); 280 dest.writeInt(mDragResult ? 1 : 0); 281 if (mClipData == null) { 282 dest.writeInt(0); 283 } else { 284 dest.writeInt(1); 285 mClipData.writeToParcel(dest, flags); 286 } 287 if (mClipDescription == null) { 288 dest.writeInt(0); 289 } else { 290 dest.writeInt(1); 291 mClipDescription.writeToParcel(dest, flags); 292 } 293 } 294 295 public static final Parcelable.Creator<DragEvent> CREATOR = 296 new Parcelable.Creator<DragEvent>() { 297 public DragEvent createFromParcel(Parcel in) { 298 DragEvent event = DragEvent.obtain(); 299 event.mAction = in.readInt(); 300 event.mX = in.readFloat(); 301 event.mY = in.readFloat(); 302 event.mDragResult = (in.readInt() != 0); 303 if (in.readInt() != 0) { 304 event.mClipData = ClipData.CREATOR.createFromParcel(in); 305 } 306 if (in.readInt() != 0) { 307 event.mClipDescription = ClipDescription.CREATOR.createFromParcel(in); 308 } 309 return event; 310 } 311 312 public DragEvent[] newArray(int size) { 313 return new DragEvent[size]; 314 } 315 }; 316} 317