• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.view;
18 
19 import android.compat.annotation.UnsupportedAppUsage;
20 import android.content.ClipData;
21 import android.content.ClipDescription;
22 import android.os.Build;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 import com.android.internal.view.IDragAndDropPermissions;
27 
28 //TODO: Improve Javadoc
29 /**
30  * Represents an event that is sent out by the system at various times during a drag and drop
31  * operation. It is a data structure that contains several important pieces of data about
32  * the operation and the underlying data.
33  * <p>
34  *  View objects that receive a DragEvent call {@link #getAction()}, which returns
35  *  an action type that indicates the state of the drag and drop operation. This allows a View
36  *  object to react to a change in state by changing its appearance or performing other actions.
37  *  For example, a View can react to the {@link #ACTION_DRAG_ENTERED} action type by
38  *  by changing one or more colors in its displayed image.
39  * </p>
40  * <p>
41  *  During a drag and drop operation, the system displays an image that the user drags. This image
42  *  is called a drag shadow. Several action types reflect the position of the drag shadow relative
43  *  to the View receiving the event.
44  * </p>
45  * <p>
46  *  Most methods return valid data only for certain event actions. This is summarized in the
47  *  following table. Each possible {@link #getAction()} value is listed in the first column. The
48  *  other columns indicate which method or methods return valid data for that getAction() value:
49  * </p>
50  * <table>
51  *  <tr>
52  *      <th scope="col">getAction() Value</th>
53  *      <th scope="col">getClipDescription()</th>
54  *      <th scope="col">getLocalState()</th>
55  *      <th scope="col">getX()</th>
56  *      <th scope="col">getY()</th>
57  *      <th scope="col">getClipData()</th>
58  *      <th scope="col">getResult()</th>
59  *  </tr>
60  *  <tr>
61  *      <td>ACTION_DRAG_STARTED</td>
62  *      <td style="text-align: center;">X</td>
63  *      <td style="text-align: center;">X</td>
64  *      <td style="text-align: center;">X</td>
65  *      <td style="text-align: center;">X</td>
66  *      <td style="text-align: center;">&nbsp;</td>
67  *      <td style="text-align: center;">&nbsp;</td>
68  *  </tr>
69  *  <tr>
70  *      <td>ACTION_DRAG_ENTERED</td>
71  *      <td style="text-align: center;">X</td>
72  *      <td style="text-align: center;">X</td>
73  *      <td style="text-align: center;">&nbsp;</td>
74  *      <td style="text-align: center;">&nbsp;</td>
75  *      <td style="text-align: center;">&nbsp;</td>
76  *      <td style="text-align: center;">&nbsp;</td>
77  *  </tr>
78  *  <tr>
79  *      <td>ACTION_DRAG_LOCATION</td>
80  *      <td style="text-align: center;">X</td>
81  *      <td style="text-align: center;">X</td>
82  *      <td style="text-align: center;">X</td>
83  *      <td style="text-align: center;">X</td>
84  *      <td style="text-align: center;">&nbsp;</td>
85  *      <td style="text-align: center;">&nbsp;</td>
86  *  </tr>
87  *  <tr>
88  *      <td>ACTION_DRAG_EXITED</td>
89  *      <td style="text-align: center;">X</td>
90  *      <td style="text-align: center;">X</td>
91  *      <td style="text-align: center;">&nbsp;</td>
92  *      <td style="text-align: center;">&nbsp;</td>
93  *      <td style="text-align: center;">&nbsp;</td>
94  *      <td style="text-align: center;">&nbsp;</td>
95  *  </tr>
96  *  <tr>
97  *      <td>ACTION_DROP</td>
98  *      <td style="text-align: center;">X</td>
99  *      <td style="text-align: center;">X</td>
100  *      <td style="text-align: center;">X</td>
101  *      <td style="text-align: center;">X</td>
102  *      <td style="text-align: center;">X</td>
103  *      <td style="text-align: center;">&nbsp;</td>
104  *  </tr>
105  *  <tr>
106  *      <td>ACTION_DRAG_ENDED</td>
107  *      <td style="text-align: center;">&nbsp;</td>
108  *      <td style="text-align: center;">X</td>
109  *      <td style="text-align: center;">&nbsp;</td>
110  *      <td style="text-align: center;">&nbsp;</td>
111  *      <td style="text-align: center;">&nbsp;</td>
112  *      <td style="text-align: center;">X</td>
113  *  </tr>
114  * </table>
115  * <p>
116  *  The {@link android.view.DragEvent#getAction()},
117  *  {@link android.view.DragEvent#getLocalState()}
118  *  {@link android.view.DragEvent#describeContents()},
119  *  {@link android.view.DragEvent#writeToParcel(Parcel,int)}, and
120  *  {@link android.view.DragEvent#toString()} methods always return valid data.
121  * </p>
122  *
123  * <div class="special reference">
124  * <h3>Developer Guides</h3>
125  * <p>For a guide to implementing drag and drop features, read the
126  * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p>
127  * </div>
128  */
129 public class DragEvent implements Parcelable {
130     private static final boolean TRACK_RECYCLED_LOCATION = false;
131 
132     int mAction;
133     float mX, mY;
134     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
135     ClipDescription mClipDescription;
136     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
137     ClipData mClipData;
138     IDragAndDropPermissions mDragAndDropPermissions;
139 
140     Object mLocalState;
141     boolean mDragResult;
142     boolean mEventHandlerWasCalled;
143 
144     /**
145      * The drag surface containing the object being dragged. Only provided if the target window
146      * has the {@link WindowManager.LayoutParams#PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP} flag
147      * and is only sent with {@link #ACTION_DROP}.
148      */
149     private SurfaceControl mDragSurface;
150 
151     /**
152      * The offsets from the touch that the surface is adjusted by as the surface is moved around the
153      * screen. Necessary for the target using the drag surface to animate it properly once it takes
154      * ownership of the drag surface after the drop.
155      */
156     private float mOffsetX;
157     private float mOffsetY;
158 
159     /**
160      * The id of the display where the `mX` and `mY` of this event belongs to.
161      */
162     private int mDisplayId;
163 
164     /**
165      * The View#DRAG_FLAG_* flags used to start the current drag, only provided if the target window
166      * has the {@link WindowManager.LayoutParams#PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP} flag
167      * and is only sent with {@link #ACTION_DRAG_STARTED} and {@link #ACTION_DROP}.
168      */
169     private int mFlags;
170 
171     private DragEvent mNext;
172     private RuntimeException mRecycledLocation;
173     private boolean mRecycled;
174 
175     private static final int MAX_RECYCLED = 10;
176     private static final Object gRecyclerLock = new Object();
177     private static int gRecyclerUsed = 0;
178     private static DragEvent gRecyclerTop = null;
179 
180     /**
181      * Action constant returned by {@link #getAction()}: Signals the start of a
182      * drag and drop operation. The View should return {@code true} from its
183      * {@link View#onDragEvent(DragEvent) onDragEvent()} handler method or
184      * {@link View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()} listener
185      * if it can accept a drop. The onDragEvent() or onDrag() methods usually inspect the metadata
186      * from {@link #getClipDescription()} to determine if they can accept the data contained in
187      * this drag. For an operation that doesn't represent data transfer, these methods may
188      * perform other actions to determine whether or not the View should accept the data.
189      * If the View wants to indicate that it is a valid drop target, it can also react by
190      * changing its appearance.
191      * <p>
192      *  Views added or becoming visible for the first time during a drag operation receive this
193      *  event when they are added or becoming visible.
194      * </p>
195      * <p>
196      *  A View only receives further drag events for the drag operation if it returns {@code true}
197      *  in response to ACTION_DRAG_STARTED.
198      * </p>
199      * @see #ACTION_DRAG_ENDED
200      * @see #getX()
201      * @see #getY()
202      */
203     public static final int ACTION_DRAG_STARTED = 1;
204 
205     /**
206      * Action constant returned by {@link #getAction()}: Sent to a View after
207      * {@link #ACTION_DRAG_ENTERED} while the drag shadow is still within the View object's bounding
208      * box, but not within a descendant view that can accept the data. The {@link #getX()} and
209      * {@link #getY()} methods supply
210      * the X and Y position of the drag point within the View object's bounding box.
211      * <p>
212      * A View receives an {@link #ACTION_DRAG_ENTERED} event before receiving any
213      * ACTION_DRAG_LOCATION events.
214      * </p>
215      * <p>
216      * The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
217      * drag shadow out of the View object's bounding box or into a descendant view that can accept
218      * the data. If the user moves the drag shadow back into the View object's bounding box or out
219      * of a descendant view that can accept the data, the View receives an ACTION_DRAG_ENTERED again
220      * before receiving any more ACTION_DRAG_LOCATION events.
221      * </p>
222      * @see #ACTION_DRAG_ENTERED
223      * @see #getX()
224      * @see #getY()
225      */
226     public static final int ACTION_DRAG_LOCATION = 2;
227 
228     /**
229      * Action constant returned by {@link #getAction()}: Signals to a View that the user
230      * has released the drag shadow, and the drag point is within the bounding box of the View and
231      * not within a descendant view that can accept the data.
232      * The View should retrieve the data from the DragEvent by calling {@link #getClipData()}.
233      * The methods {@link #getX()} and {@link #getY()} return the X and Y position of the drop point
234      * within the View object's bounding box.
235      * <p>
236      * The View should return {@code true} from its {@link View#onDragEvent(DragEvent)}
237      * handler or {@link View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()}
238      * listener if it accepted the drop, and {@code false} if it ignored the drop.
239      * </p>
240      * <p>
241      * The View can also react to this action by changing its appearance.
242      * </p>
243      * @see #getClipData()
244      * @see #getX()
245      * @see #getY()
246      */
247     public static final int ACTION_DROP = 3;
248 
249     /**
250      * Action constant returned by {@link #getAction()}:  Signals to a View that the drag and drop
251      * operation has concluded.  A View that changed its appearance during the operation should
252      * return to its usual drawing state in response to this event.
253      * <p>
254      *  All views with listeners that returned boolean <code>true</code> for the ACTION_DRAG_STARTED
255      *  event will receive the ACTION_DRAG_ENDED event even if they are not currently visible when
256      *  the drag ends. Views removed during the drag operation won't receive the ACTION_DRAG_ENDED
257      *  event.
258      * </p>
259      * <p>
260      *  The View object can call {@link #getResult()} to see the result of the operation.
261      *  If a View returned {@code true} in response to {@link #ACTION_DROP}, then
262      *  getResult() returns {@code true}, otherwise it returns {@code false}.
263      * </p>
264      * @see #ACTION_DRAG_STARTED
265      * @see #getResult()
266      */
267     public static final int ACTION_DRAG_ENDED = 4;
268 
269     /**
270      * Action constant returned by {@link #getAction()}: Signals to a View that the drag point has
271      * entered the bounding box of the View.
272      * <p>
273      *  If the View can accept a drop, it can react to ACTION_DRAG_ENTERED
274      *  by changing its appearance in a way that tells the user that the View is the current
275      *  drop target.
276      * </p>
277      * The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
278      * drag shadow out of the View object's bounding box or into a descendant view that can accept
279      * the data. If the user moves the drag shadow back into the View object's bounding box or out
280      * of a descendant view that can accept the data, the View receives an ACTION_DRAG_ENTERED again
281      * before receiving any more ACTION_DRAG_LOCATION events.
282      * </p>
283      * @see #ACTION_DRAG_ENTERED
284      * @see #ACTION_DRAG_LOCATION
285      */
286     public static final int ACTION_DRAG_ENTERED = 5;
287 
288     /**
289      * Action constant returned by {@link #getAction()}: Signals that the user has moved the
290      * drag shadow out of the bounding box of the View or into a descendant view that can accept
291      * the data.
292      * The View can react by changing its appearance in a way that tells the user that
293      * View is no longer the immediate drop target.
294      * <p>
295      *  After the system sends an ACTION_DRAG_EXITED event to the View, the View receives no more
296      *  ACTION_DRAG_LOCATION events until the user drags the drag shadow back over the View.
297      * </p>
298      *
299      */
300      public static final int ACTION_DRAG_EXITED = 6;
301 
DragEvent()302     private DragEvent() {
303     }
304 
init(int action, float x, float y, float offsetX, float offsetY, int displayId, int flags, ClipDescription description, ClipData data, SurfaceControl dragSurface, IDragAndDropPermissions dragAndDropPermissions, Object localState, boolean result)305     private void init(int action, float x, float y, float offsetX, float offsetY, int displayId,
306             int flags, ClipDescription description, ClipData data, SurfaceControl dragSurface,
307             IDragAndDropPermissions dragAndDropPermissions, Object localState, boolean result) {
308         mAction = action;
309         mX = x;
310         mY = y;
311         mOffsetX = offsetX;
312         mOffsetY = offsetY;
313         mDisplayId = displayId;
314         mFlags = flags;
315         mClipDescription = description;
316         mClipData = data;
317         mDragSurface = dragSurface;
318         mDragAndDropPermissions = dragAndDropPermissions;
319         mLocalState = localState;
320         mDragResult = result;
321     }
322 
obtain()323     static DragEvent obtain() {
324         return DragEvent.obtain(0, 0f, 0f, 0f, 0f, 0, 0, null, null, null, null, null, false);
325     }
326 
327     /** @hide */
obtain(int action, float x, float y, float offsetX, float offsetY, int displayId, int flags, Object localState, ClipDescription description, ClipData data, SurfaceControl dragSurface, IDragAndDropPermissions dragAndDropPermissions, boolean result)328     public static DragEvent obtain(int action, float x, float y, float offsetX, float offsetY,
329             int displayId, int flags, Object localState, ClipDescription description, ClipData data,
330             SurfaceControl dragSurface, IDragAndDropPermissions dragAndDropPermissions,
331             boolean result) {
332         final DragEvent ev;
333         synchronized (gRecyclerLock) {
334             if (gRecyclerTop == null) {
335                 ev = new DragEvent();
336                 ev.init(action, x, y, offsetX, offsetY, displayId, flags, description, data,
337                         dragSurface, dragAndDropPermissions, localState, result);
338                 return ev;
339             }
340             ev = gRecyclerTop;
341             gRecyclerTop = ev.mNext;
342             gRecyclerUsed -= 1;
343         }
344         ev.mRecycledLocation = null;
345         ev.mRecycled = false;
346         ev.mNext = null;
347 
348         ev.init(action, x, y, offsetX, offsetY, displayId, flags, description, data, dragSurface,
349                 dragAndDropPermissions, localState, result);
350 
351         return ev;
352     }
353 
354     /** @hide */
355     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
obtain(DragEvent source)356     public static DragEvent obtain(DragEvent source) {
357         return obtain(source.mAction, source.mX, source.mY, source.mOffsetX, source.mOffsetY,
358                 source.mDisplayId, source.mFlags, source.mLocalState, source.mClipDescription,
359                 source.mClipData, source.mDragSurface, source.mDragAndDropPermissions,
360                 source.mDragResult);
361     }
362 
363     /**
364      * Inspect the action value of this event.
365      * @return One of the following action constants, in the order in which they usually occur
366      * during a drag and drop operation:
367      * <ul>
368      *  <li>{@link #ACTION_DRAG_STARTED}</li>
369      *  <li>{@link #ACTION_DRAG_ENTERED}</li>
370      *  <li>{@link #ACTION_DRAG_LOCATION}</li>
371      *  <li>{@link #ACTION_DROP}</li>
372      *  <li>{@link #ACTION_DRAG_EXITED}</li>
373      *  <li>{@link #ACTION_DRAG_ENDED}</li>
374      * </ul>
375      */
getAction()376     public int getAction() {
377         return mAction;
378     }
379 
380     /**
381      * Gets the X coordinate of the drag point. The value is only valid if the event action is
382      * {@link #ACTION_DRAG_STARTED}, {@link #ACTION_DRAG_LOCATION} or {@link #ACTION_DROP}.
383      * @return The current drag point's X coordinate
384      */
getX()385     public float getX() {
386         return mX;
387     }
388 
389     /**
390      * Gets the Y coordinate of the drag point. The value is only valid if the event action is
391      * {@link #ACTION_DRAG_STARTED}, {@link #ACTION_DRAG_LOCATION} or {@link #ACTION_DROP}.
392      * @return The current drag point's Y coordinate
393      */
getY()394     public float getY() {
395         return mY;
396     }
397 
398     /** @hide */
getOffsetX()399     public float getOffsetX() {
400         return mOffsetX;
401     }
402 
403     /** @hide */
getOffsetY()404     public float getOffsetY() {
405         return mOffsetY;
406     }
407 
408     /** @hide */
getDisplayId()409     public int getDisplayId() {
410         return mDisplayId;
411     }
412 
413     /**
414      * Returns the {@link android.content.ClipData} object sent to the system as part of the call
415      * to
416      * {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
417      * startDragAndDrop()}.
418      * This method only returns valid data if the event action is {@link #ACTION_DROP}.
419      * @return The ClipData sent to the system by startDragAndDrop().
420      */
getClipData()421     public ClipData getClipData() {
422         return mClipData;
423     }
424 
425     /**
426      * Returns the {@link android.content.ClipDescription} object contained in the
427      * {@link android.content.ClipData} object sent to the system as part of the call to
428      * {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
429      * startDragAndDrop()}.
430      * The drag handler or listener for a View can use the metadata in this object to decide if the
431      * View can accept the dragged View object's data.
432      * <p>
433      * This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
434      * @return The ClipDescription that was part of the ClipData sent to the system by
435      *     startDragAndDrop().
436      */
getClipDescription()437     public ClipDescription getClipDescription() {
438         return mClipDescription;
439     }
440 
441     /** @hide */
getDragSurface()442     public SurfaceControl getDragSurface() {
443         return mDragSurface;
444     }
445 
446     /** @hide */
getDragFlags()447     public int getDragFlags() {
448         return mFlags;
449     }
450 
451     /** @hide */
getDragAndDropPermissions()452     public IDragAndDropPermissions getDragAndDropPermissions() {
453         return mDragAndDropPermissions;
454     }
455 
456     /**
457      * Returns the local state object sent to the system as part of the call to
458      * {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
459      * startDragAndDrop()}.
460      * The object is intended to provide local information about the drag and drop operation. For
461      * example, it can indicate whether the drag and drop operation is a copy or a move.
462      * <p>
463      * The local state is available only to views in the activity which has started the drag
464      * operation. In all other activities this method will return null
465      * </p>
466      * <p>
467      *  This method returns valid data for all event actions.
468      * </p>
469      * @return The local state object sent to the system by startDragAndDrop().
470      */
getLocalState()471     public Object getLocalState() {
472         return mLocalState;
473     }
474 
475     /**
476      * <p>
477      * Returns an indication of the result of the drag and drop operation.
478      * This method only returns valid data if the action type is {@link #ACTION_DRAG_ENDED}.
479      * The return value depends on what happens after the user releases the drag shadow.
480      * </p>
481      * <p>
482      * If the user releases the drag shadow on a View that can accept a drop, the system sends an
483      * {@link #ACTION_DROP} event to the View object's drag event listener. If the listener
484      * returns {@code true}, then getResult() will return {@code true}.
485      * If the listener returns {@code false}, then getResult() returns {@code false}.
486      * </p>
487      * <p>
488      * Notice that getResult() also returns {@code false} if no {@link #ACTION_DROP} is sent. This
489      * happens, for example, when the user releases the drag shadow over an area outside of the
490      * application. In this case, the system sends out {@link #ACTION_DRAG_ENDED} for the current
491      * operation, but never sends out {@link #ACTION_DROP}.
492      * </p>
493      * @return {@code true} if a drag event listener returned {@code true} in response to
494      * {@link #ACTION_DROP}. If the system did not send {@link #ACTION_DROP} before
495      * {@link #ACTION_DRAG_ENDED}, or if the listener returned {@code false} in response to
496      * {@link #ACTION_DROP}, then {@code false} is returned.
497      */
getResult()498     public boolean getResult() {
499         return mDragResult;
500     }
501 
502     /**
503      * Recycle the DragEvent, to be re-used by a later caller.  After calling
504      * this function you must never touch the event again.
505      *
506      * @hide
507      */
recycle()508     public final void recycle() {
509         // Ensure recycle is only called once!
510         if (TRACK_RECYCLED_LOCATION) {
511             if (mRecycledLocation != null) {
512                 throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation);
513             }
514             mRecycledLocation = new RuntimeException("Last recycled here");
515         } else {
516             if (mRecycled) {
517                 throw new RuntimeException(toString() + " recycled twice!");
518             }
519             mRecycled = true;
520         }
521 
522         mClipData = null;
523         mClipDescription = null;
524         mLocalState = null;
525         mEventHandlerWasCalled = false;
526 
527         synchronized (gRecyclerLock) {
528             if (gRecyclerUsed < MAX_RECYCLED) {
529                 gRecyclerUsed++;
530                 mNext = gRecyclerTop;
531                 gRecyclerTop = this;
532             }
533         }
534     }
535 
536     /**
537      * Returns a string that represents the symbolic name of the specified unmasked action
538      * such as "ACTION_DRAG_START", "ACTION_DRAG_END" or an equivalent numeric constant
539      * such as "35" if unknown.
540      *
541      * @param action The action.
542      * @return The symbolic name of the specified action.
543      * @see #getAction()
544      * @hide
545      */
actionToString(int action)546     public static String actionToString(int action) {
547         switch (action) {
548             case ACTION_DRAG_STARTED:
549                 return "ACTION_DRAG_STARTED";
550             case ACTION_DRAG_LOCATION:
551                 return "ACTION_DRAG_LOCATION";
552             case ACTION_DROP:
553                 return "ACTION_DROP";
554             case ACTION_DRAG_ENDED:
555                 return "ACTION_DRAG_ENDED";
556             case ACTION_DRAG_ENTERED:
557                 return "ACTION_DRAG_ENTERED";
558             case ACTION_DRAG_EXITED:
559                 return "ACTION_DRAG_EXITED";
560         }
561         return Integer.toString(action);
562     }
563 
564     /**
565      * Returns a string containing a concise, human-readable representation of this DragEvent
566      * object.
567      * @return A string representation of the DragEvent object.
568      */
569     @Override
toString()570     public String toString() {
571         return "DragEvent{" + Integer.toHexString(System.identityHashCode(this))
572         + " action=" + mAction + " @ (" + mX + ", " + mY + ") desc=" + mClipDescription
573         + " data=" + mClipData + " local=" + mLocalState + " result=" + mDragResult
574         + "}";
575     }
576 
577     /* Parcelable interface */
578 
579     /**
580      * Returns information about the {@link android.os.Parcel} representation of this DragEvent
581      * object.
582      * @return Information about the {@link android.os.Parcel} representation.
583      */
describeContents()584     public int describeContents() {
585         return 0;
586     }
587 
588     /**
589      * Creates a {@link android.os.Parcel} object from this DragEvent object.
590      * @param dest A {@link android.os.Parcel} object in which to put the DragEvent object.
591      * @param flags Flags to store in the Parcel.
592      */
writeToParcel(Parcel dest, int flags)593     public void writeToParcel(Parcel dest, int flags) {
594         dest.writeInt(mAction);
595         dest.writeFloat(mX);
596         dest.writeFloat(mY);
597         dest.writeFloat(mOffsetX);
598         dest.writeFloat(mOffsetY);
599         dest.writeInt(mFlags);
600         dest.writeInt(mDragResult ? 1 : 0);
601         if (mClipData == null) {
602             dest.writeInt(0);
603         } else {
604             dest.writeInt(1);
605             mClipData.writeToParcel(dest, flags);
606         }
607         if (mClipDescription == null) {
608             dest.writeInt(0);
609         } else {
610             dest.writeInt(1);
611             mClipDescription.writeToParcel(dest, flags);
612         }
613         if (mDragSurface == null) {
614             dest.writeInt(0);
615         } else {
616             dest.writeInt(1);
617             mDragSurface.writeToParcel(dest, flags);
618         }
619         if (mDragAndDropPermissions == null) {
620             dest.writeInt(0);
621         } else {
622             dest.writeInt(1);
623             dest.writeStrongBinder(mDragAndDropPermissions.asBinder());
624         }
625     }
626 
627     /**
628      * A container for creating a DragEvent from a Parcel.
629      */
630     public static final @android.annotation.NonNull Parcelable.Creator<DragEvent> CREATOR =
631         new Parcelable.Creator<DragEvent>() {
632         public DragEvent createFromParcel(Parcel in) {
633             DragEvent event = DragEvent.obtain();
634             event.mAction = in.readInt();
635             event.mX = in.readFloat();
636             event.mY = in.readFloat();
637             event.mOffsetX = in.readFloat();
638             event.mOffsetY = in.readFloat();
639             event.mFlags = in.readInt();
640             event.mDragResult = (in.readInt() != 0);
641             if (in.readInt() != 0) {
642                 event.mClipData = ClipData.CREATOR.createFromParcel(in);
643             }
644             if (in.readInt() != 0) {
645                 event.mClipDescription = ClipDescription.CREATOR.createFromParcel(in);
646             }
647             if (in.readInt() != 0) {
648                 event.mDragSurface = SurfaceControl.CREATOR.createFromParcel(in);
649                 event.mDragSurface.setUnreleasedWarningCallSite("DragEvent");
650             }
651             if (in.readInt() != 0) {
652                 event.mDragAndDropPermissions =
653                         IDragAndDropPermissions.Stub.asInterface(in.readStrongBinder());
654             }
655             return event;
656         }
657 
658         public DragEvent[] newArray(int size) {
659             return new DragEvent[size];
660         }
661     };
662 }
663