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