• 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 View#DRAG_FLAG_* flags used to start the current drag, only provided if the target window
161      * has the {@link WindowManager.LayoutParams#PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP} flag
162      * and is only sent with {@link #ACTION_DRAG_STARTED} and {@link #ACTION_DROP}.
163      */
164     private int mFlags;
165 
166     private DragEvent mNext;
167     private RuntimeException mRecycledLocation;
168     private boolean mRecycled;
169 
170     private static final int MAX_RECYCLED = 10;
171     private static final Object gRecyclerLock = new Object();
172     private static int gRecyclerUsed = 0;
173     private static DragEvent gRecyclerTop = null;
174 
175     /**
176      * Action constant returned by {@link #getAction()}: Signals the start of a
177      * drag and drop operation. The View should return {@code true} from its
178      * {@link View#onDragEvent(DragEvent) onDragEvent()} handler method or
179      * {@link View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()} listener
180      * if it can accept a drop. The onDragEvent() or onDrag() methods usually inspect the metadata
181      * from {@link #getClipDescription()} to determine if they can accept the data contained in
182      * this drag. For an operation that doesn't represent data transfer, these methods may
183      * perform other actions to determine whether or not the View should accept the data.
184      * If the View wants to indicate that it is a valid drop target, it can also react by
185      * changing its appearance.
186      * <p>
187      *  Views added or becoming visible for the first time during a drag operation receive this
188      *  event when they are added or becoming visible.
189      * </p>
190      * <p>
191      *  A View only receives further drag events for the drag operation if it returns {@code true}
192      *  in response to ACTION_DRAG_STARTED.
193      * </p>
194      * @see #ACTION_DRAG_ENDED
195      * @see #getX()
196      * @see #getY()
197      */
198     public static final int ACTION_DRAG_STARTED = 1;
199 
200     /**
201      * Action constant returned by {@link #getAction()}: Sent to a View after
202      * {@link #ACTION_DRAG_ENTERED} while the drag shadow is still within the View object's bounding
203      * box, but not within a descendant view that can accept the data. The {@link #getX()} and
204      * {@link #getY()} methods supply
205      * the X and Y position of the drag point within the View object's bounding box.
206      * <p>
207      * A View receives an {@link #ACTION_DRAG_ENTERED} event before receiving any
208      * ACTION_DRAG_LOCATION events.
209      * </p>
210      * <p>
211      * The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
212      * drag shadow out of the View object's bounding box or into a descendant view that can accept
213      * the data. If the user moves the drag shadow back into the View object's bounding box or out
214      * of a descendant view that can accept the data, the View receives an ACTION_DRAG_ENTERED again
215      * before receiving any more ACTION_DRAG_LOCATION events.
216      * </p>
217      * @see #ACTION_DRAG_ENTERED
218      * @see #getX()
219      * @see #getY()
220      */
221     public static final int ACTION_DRAG_LOCATION = 2;
222 
223     /**
224      * Action constant returned by {@link #getAction()}: Signals to a View that the user
225      * has released the drag shadow, and the drag point is within the bounding box of the View and
226      * not within a descendant view that can accept the data.
227      * The View should retrieve the data from the DragEvent by calling {@link #getClipData()}.
228      * The methods {@link #getX()} and {@link #getY()} return the X and Y position of the drop point
229      * within the View object's bounding box.
230      * <p>
231      * The View should return {@code true} from its {@link View#onDragEvent(DragEvent)}
232      * handler or {@link View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()}
233      * listener if it accepted the drop, and {@code false} if it ignored the drop.
234      * </p>
235      * <p>
236      * The View can also react to this action by changing its appearance.
237      * </p>
238      * @see #getClipData()
239      * @see #getX()
240      * @see #getY()
241      */
242     public static final int ACTION_DROP = 3;
243 
244     /**
245      * Action constant returned by {@link #getAction()}:  Signals to a View that the drag and drop
246      * operation has concluded.  A View that changed its appearance during the operation should
247      * return to its usual drawing state in response to this event.
248      * <p>
249      *  All views with listeners that returned boolean <code>true</code> for the ACTION_DRAG_STARTED
250      *  event will receive the ACTION_DRAG_ENDED event even if they are not currently visible when
251      *  the drag ends. Views removed during the drag operation won't receive the ACTION_DRAG_ENDED
252      *  event.
253      * </p>
254      * <p>
255      *  The View object can call {@link #getResult()} to see the result of the operation.
256      *  If a View returned {@code true} in response to {@link #ACTION_DROP}, then
257      *  getResult() returns {@code true}, otherwise it returns {@code false}.
258      * </p>
259      * @see #ACTION_DRAG_STARTED
260      * @see #getResult()
261      */
262     public static final int ACTION_DRAG_ENDED = 4;
263 
264     /**
265      * Action constant returned by {@link #getAction()}: Signals to a View that the drag point has
266      * entered the bounding box of the View.
267      * <p>
268      *  If the View can accept a drop, it can react to ACTION_DRAG_ENTERED
269      *  by changing its appearance in a way that tells the user that the View is the current
270      *  drop target.
271      * </p>
272      * The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
273      * drag shadow out of the View object's bounding box or into a descendant view that can accept
274      * the data. If the user moves the drag shadow back into the View object's bounding box or out
275      * of a descendant view that can accept the data, the View receives an ACTION_DRAG_ENTERED again
276      * before receiving any more ACTION_DRAG_LOCATION events.
277      * </p>
278      * @see #ACTION_DRAG_ENTERED
279      * @see #ACTION_DRAG_LOCATION
280      */
281     public static final int ACTION_DRAG_ENTERED = 5;
282 
283     /**
284      * Action constant returned by {@link #getAction()}: Signals that the user has moved the
285      * drag shadow out of the bounding box of the View or into a descendant view that can accept
286      * the data.
287      * The View can react by changing its appearance in a way that tells the user that
288      * View is no longer the immediate drop target.
289      * <p>
290      *  After the system sends an ACTION_DRAG_EXITED event to the View, the View receives no more
291      *  ACTION_DRAG_LOCATION events until the user drags the drag shadow back over the View.
292      * </p>
293      *
294      */
295      public static final int ACTION_DRAG_EXITED = 6;
296 
DragEvent()297     private DragEvent() {
298     }
299 
init(int action, float x, float y, float offsetX, float offsetY, int flags, ClipDescription description, ClipData data, SurfaceControl dragSurface, IDragAndDropPermissions dragAndDropPermissions, Object localState, boolean result)300     private void init(int action, float x, float y, float offsetX, float offsetY, int flags,
301             ClipDescription description, ClipData data, SurfaceControl dragSurface,
302             IDragAndDropPermissions dragAndDropPermissions, Object localState, boolean result) {
303         mAction = action;
304         mX = x;
305         mY = y;
306         mOffsetX = offsetX;
307         mOffsetY = offsetY;
308         mFlags = flags;
309         mClipDescription = description;
310         mClipData = data;
311         mDragSurface = dragSurface;
312         mDragAndDropPermissions = dragAndDropPermissions;
313         mLocalState = localState;
314         mDragResult = result;
315     }
316 
obtain()317     static DragEvent obtain() {
318         return DragEvent.obtain(0, 0f, 0f, 0f, 0f, 0, null, null, null, null, null, false);
319     }
320 
321     /** @hide */
obtain(int action, float x, float y, float offsetX, float offsetY, int flags, Object localState, ClipDescription description, ClipData data, SurfaceControl dragSurface, IDragAndDropPermissions dragAndDropPermissions, boolean result)322     public static DragEvent obtain(int action, float x, float y, float offsetX, float offsetY,
323             int flags, Object localState, ClipDescription description, ClipData data,
324             SurfaceControl dragSurface, IDragAndDropPermissions dragAndDropPermissions,
325             boolean result) {
326         final DragEvent ev;
327         synchronized (gRecyclerLock) {
328             if (gRecyclerTop == null) {
329                 ev = new DragEvent();
330                 ev.init(action, x, y, offsetX, offsetY, flags, description, data, dragSurface,
331                         dragAndDropPermissions, localState, result);
332                 return ev;
333             }
334             ev = gRecyclerTop;
335             gRecyclerTop = ev.mNext;
336             gRecyclerUsed -= 1;
337         }
338         ev.mRecycledLocation = null;
339         ev.mRecycled = false;
340         ev.mNext = null;
341 
342         ev.init(action, x, y, offsetX, offsetY, flags, description, data, dragSurface,
343                 dragAndDropPermissions, localState, result);
344 
345         return ev;
346     }
347 
348     /** @hide */
349     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
obtain(DragEvent source)350     public static DragEvent obtain(DragEvent source) {
351         return obtain(source.mAction, source.mX, source.mY, source.mOffsetX, source.mOffsetY,
352                 source.mFlags, source.mLocalState, source.mClipDescription, source.mClipData,
353                 source.mDragSurface, source.mDragAndDropPermissions, source.mDragResult);
354     }
355 
356     /**
357      * Inspect the action value of this event.
358      * @return One of the following action constants, in the order in which they usually occur
359      * during a drag and drop operation:
360      * <ul>
361      *  <li>{@link #ACTION_DRAG_STARTED}</li>
362      *  <li>{@link #ACTION_DRAG_ENTERED}</li>
363      *  <li>{@link #ACTION_DRAG_LOCATION}</li>
364      *  <li>{@link #ACTION_DROP}</li>
365      *  <li>{@link #ACTION_DRAG_EXITED}</li>
366      *  <li>{@link #ACTION_DRAG_ENDED}</li>
367      * </ul>
368      */
getAction()369     public int getAction() {
370         return mAction;
371     }
372 
373     /**
374      * Gets the X coordinate of the drag point. The value is only valid if the event action is
375      * {@link #ACTION_DRAG_STARTED}, {@link #ACTION_DRAG_LOCATION} or {@link #ACTION_DROP}.
376      * @return The current drag point's X coordinate
377      */
getX()378     public float getX() {
379         return mX;
380     }
381 
382     /**
383      * Gets the Y coordinate of the drag point. The value is only valid if the event action is
384      * {@link #ACTION_DRAG_STARTED}, {@link #ACTION_DRAG_LOCATION} or {@link #ACTION_DROP}.
385      * @return The current drag point's Y coordinate
386      */
getY()387     public float getY() {
388         return mY;
389     }
390 
391     /** @hide */
getOffsetX()392     public float getOffsetX() {
393         return mOffsetX;
394     }
395 
396     /** @hide */
getOffsetY()397     public float getOffsetY() {
398         return mOffsetY;
399     }
400 
401     /**
402      * Returns the {@link android.content.ClipData} object sent to the system as part of the call
403      * to
404      * {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
405      * startDragAndDrop()}.
406      * This method only returns valid data if the event action is {@link #ACTION_DROP}.
407      * @return The ClipData sent to the system by startDragAndDrop().
408      */
getClipData()409     public ClipData getClipData() {
410         return mClipData;
411     }
412 
413     /**
414      * Returns the {@link android.content.ClipDescription} object contained in the
415      * {@link android.content.ClipData} object sent to the system as part of the call to
416      * {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
417      * startDragAndDrop()}.
418      * The drag handler or listener for a View can use the metadata in this object to decide if the
419      * View can accept the dragged View object's data.
420      * <p>
421      * This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
422      * @return The ClipDescription that was part of the ClipData sent to the system by
423      *     startDragAndDrop().
424      */
getClipDescription()425     public ClipDescription getClipDescription() {
426         return mClipDescription;
427     }
428 
429     /** @hide */
getDragSurface()430     public SurfaceControl getDragSurface() {
431         return mDragSurface;
432     }
433 
434     /** @hide */
getDragFlags()435     public int getDragFlags() {
436         return mFlags;
437     }
438 
439     /** @hide */
getDragAndDropPermissions()440     public IDragAndDropPermissions getDragAndDropPermissions() {
441         return mDragAndDropPermissions;
442     }
443 
444     /**
445      * Returns the local state object sent to the system as part of the call to
446      * {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
447      * startDragAndDrop()}.
448      * The object is intended to provide local information about the drag and drop operation. For
449      * example, it can indicate whether the drag and drop operation is a copy or a move.
450      * <p>
451      * The local state is available only to views in the activity which has started the drag
452      * operation. In all other activities this method will return null
453      * </p>
454      * <p>
455      *  This method returns valid data for all event actions.
456      * </p>
457      * @return The local state object sent to the system by startDragAndDrop().
458      */
getLocalState()459     public Object getLocalState() {
460         return mLocalState;
461     }
462 
463     /**
464      * <p>
465      * Returns an indication of the result of the drag and drop operation.
466      * This method only returns valid data if the action type is {@link #ACTION_DRAG_ENDED}.
467      * The return value depends on what happens after the user releases the drag shadow.
468      * </p>
469      * <p>
470      * If the user releases the drag shadow on a View that can accept a drop, the system sends an
471      * {@link #ACTION_DROP} event to the View object's drag event listener. If the listener
472      * returns {@code true}, then getResult() will return {@code true}.
473      * If the listener returns {@code false}, then getResult() returns {@code false}.
474      * </p>
475      * <p>
476      * Notice that getResult() also returns {@code false} if no {@link #ACTION_DROP} is sent. This
477      * happens, for example, when the user releases the drag shadow over an area outside of the
478      * application. In this case, the system sends out {@link #ACTION_DRAG_ENDED} for the current
479      * operation, but never sends out {@link #ACTION_DROP}.
480      * </p>
481      * @return {@code true} if a drag event listener returned {@code true} in response to
482      * {@link #ACTION_DROP}. If the system did not send {@link #ACTION_DROP} before
483      * {@link #ACTION_DRAG_ENDED}, or if the listener returned {@code false} in response to
484      * {@link #ACTION_DROP}, then {@code false} is returned.
485      */
getResult()486     public boolean getResult() {
487         return mDragResult;
488     }
489 
490     /**
491      * Recycle the DragEvent, to be re-used by a later caller.  After calling
492      * this function you must never touch the event again.
493      *
494      * @hide
495      */
recycle()496     public final void recycle() {
497         // Ensure recycle is only called once!
498         if (TRACK_RECYCLED_LOCATION) {
499             if (mRecycledLocation != null) {
500                 throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation);
501             }
502             mRecycledLocation = new RuntimeException("Last recycled here");
503         } else {
504             if (mRecycled) {
505                 throw new RuntimeException(toString() + " recycled twice!");
506             }
507             mRecycled = true;
508         }
509 
510         mClipData = null;
511         mClipDescription = null;
512         mLocalState = null;
513         mEventHandlerWasCalled = false;
514 
515         synchronized (gRecyclerLock) {
516             if (gRecyclerUsed < MAX_RECYCLED) {
517                 gRecyclerUsed++;
518                 mNext = gRecyclerTop;
519                 gRecyclerTop = this;
520             }
521         }
522     }
523 
524     /**
525      * Returns a string that represents the symbolic name of the specified unmasked action
526      * such as "ACTION_DRAG_START", "ACTION_DRAG_END" or an equivalent numeric constant
527      * such as "35" if unknown.
528      *
529      * @param action The action.
530      * @return The symbolic name of the specified action.
531      * @see #getAction()
532      * @hide
533      */
actionToString(int action)534     public static String actionToString(int action) {
535         switch (action) {
536             case ACTION_DRAG_STARTED:
537                 return "ACTION_DRAG_STARTED";
538             case ACTION_DRAG_LOCATION:
539                 return "ACTION_DRAG_LOCATION";
540             case ACTION_DROP:
541                 return "ACTION_DROP";
542             case ACTION_DRAG_ENDED:
543                 return "ACTION_DRAG_ENDED";
544             case ACTION_DRAG_ENTERED:
545                 return "ACTION_DRAG_ENTERED";
546             case ACTION_DRAG_EXITED:
547                 return "ACTION_DRAG_EXITED";
548         }
549         return Integer.toString(action);
550     }
551 
552     /**
553      * Returns a string containing a concise, human-readable representation of this DragEvent
554      * object.
555      * @return A string representation of the DragEvent object.
556      */
557     @Override
toString()558     public String toString() {
559         return "DragEvent{" + Integer.toHexString(System.identityHashCode(this))
560         + " action=" + mAction + " @ (" + mX + ", " + mY + ") desc=" + mClipDescription
561         + " data=" + mClipData + " local=" + mLocalState + " result=" + mDragResult
562         + "}";
563     }
564 
565     /* Parcelable interface */
566 
567     /**
568      * Returns information about the {@link android.os.Parcel} representation of this DragEvent
569      * object.
570      * @return Information about the {@link android.os.Parcel} representation.
571      */
describeContents()572     public int describeContents() {
573         return 0;
574     }
575 
576     /**
577      * Creates a {@link android.os.Parcel} object from this DragEvent object.
578      * @param dest A {@link android.os.Parcel} object in which to put the DragEvent object.
579      * @param flags Flags to store in the Parcel.
580      */
writeToParcel(Parcel dest, int flags)581     public void writeToParcel(Parcel dest, int flags) {
582         dest.writeInt(mAction);
583         dest.writeFloat(mX);
584         dest.writeFloat(mY);
585         dest.writeFloat(mOffsetX);
586         dest.writeFloat(mOffsetY);
587         dest.writeInt(mFlags);
588         dest.writeInt(mDragResult ? 1 : 0);
589         if (mClipData == null) {
590             dest.writeInt(0);
591         } else {
592             dest.writeInt(1);
593             mClipData.writeToParcel(dest, flags);
594         }
595         if (mClipDescription == null) {
596             dest.writeInt(0);
597         } else {
598             dest.writeInt(1);
599             mClipDescription.writeToParcel(dest, flags);
600         }
601         if (mDragSurface == null) {
602             dest.writeInt(0);
603         } else {
604             dest.writeInt(1);
605             mDragSurface.writeToParcel(dest, flags);
606         }
607         if (mDragAndDropPermissions == null) {
608             dest.writeInt(0);
609         } else {
610             dest.writeInt(1);
611             dest.writeStrongBinder(mDragAndDropPermissions.asBinder());
612         }
613     }
614 
615     /**
616      * A container for creating a DragEvent from a Parcel.
617      */
618     public static final @android.annotation.NonNull Parcelable.Creator<DragEvent> CREATOR =
619         new Parcelable.Creator<DragEvent>() {
620         public DragEvent createFromParcel(Parcel in) {
621             DragEvent event = DragEvent.obtain();
622             event.mAction = in.readInt();
623             event.mX = in.readFloat();
624             event.mY = in.readFloat();
625             event.mOffsetX = in.readFloat();
626             event.mOffsetY = in.readFloat();
627             event.mFlags = in.readInt();
628             event.mDragResult = (in.readInt() != 0);
629             if (in.readInt() != 0) {
630                 event.mClipData = ClipData.CREATOR.createFromParcel(in);
631             }
632             if (in.readInt() != 0) {
633                 event.mClipDescription = ClipDescription.CREATOR.createFromParcel(in);
634             }
635             if (in.readInt() != 0) {
636                 event.mDragSurface = SurfaceControl.CREATOR.createFromParcel(in);
637                 event.mDragSurface.setUnreleasedWarningCallSite("DragEvent");
638             }
639             if (in.readInt() != 0) {
640                 event.mDragAndDropPermissions =
641                         IDragAndDropPermissions.Stub.asInterface(in.readStrongBinder());
642             }
643             return event;
644         }
645 
646         public DragEvent[] newArray(int size) {
647             return new DragEvent[size];
648         }
649     };
650 }
651