Be Careful of Drag-and-Drop on Android N
As part of a forthcoming book update, I began working with the revised drag-and-drop APIs for Android N. Drag-and-drop has been part of Android since 3.0, but since it is limited to a single activity, it does not seem to be all that popular. Now, with multi-window support, drag-and-drop can work between apps… and that is where you need to be careful.
When you start a drag-and-drop operation via
(or the earlier
startDrag()), you can include
in the request. This indicates that you want the drag-and-drop operation
to work between apps. Without this flag, the drag-and-drop is limited
to your own app. This is wonderful: it is an easy change, but apps
do not accidentally leak data by default.
However, I cannot find an equivalent for handling drops.
When you register a drop target with
setOnDragListener(), there is no flag to say that you want to support cross-app drag-and-drop requests
When you get a
DragEvent, there is no built-in means to determine whether the event arose from your app or from another app
Hence, if you implement drag-and-drop, you can get drag events originating from other apps on Android N, without any changes to your code to say that you want this behavior.
IMHO, this is not a good idea. Accepting foreign drag events should be something you opt into. With luck, this will get addressed, though I do not hold out tons of hope.
If you have been using drag-and-drop purely within your app, and you
want your drop target to know whether a
DragEvent is from your app
or from another app, you can use a slight hack: pass a non-
value for the third parameter to
This is called the “local state”, and the name is accurate: it does not appear
to be passed across process boundaries. For any
DragEvent delivered to your
drop target, you can call
getLocalState() on the
DragEvent to get
the local state value. If that is not
null, then you know the
DragEvent initiated in your app. If the local state is
and you are sure that you are providing a value for it in all of your
startDragAndDrop() calls — then you know that the
DragEvent came from another app.
Ideally, eventually you support cross-app drag-and-drop. But, since you
are not in control over
DragEvent objects originating from other
apps, you will need a lot more defensive programming in your drop target
code. You might be expecting a
Uri and get a
String, for example.