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