android.view.DragEvent Maven / Gradle / Ivy
Show all versions of android-all Show documentation
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view;
import android.content.ClipData;
import android.content.ClipDescription;
import android.os.Parcel;
import android.os.Parcelable;
//TODO: Improve Javadoc
/**
* Represents an event that is sent out by the system at various times during a drag and drop
* operation. It is a complex data structure that contains several important pieces of data about
* the operation and the underlying data.
*
* View objects that receive a DragEvent call {@link #getAction()}, which returns
* an action type that indicates the state of the drag and drop operation. This allows a View
* object to react to a change in state by changing its appearance or performing other actions.
* For example, a View can react to the {@link #ACTION_DRAG_ENTERED} action type by
* by changing one or more colors in its displayed image.
*
*
* During a drag and drop operation, the system displays an image that the user drags. This image
* is called a drag shadow. Several action types reflect the position of the drag shadow relative
* to the View receiving the event.
*
*
* Most methods return valid data only for certain event actions. This is summarized in the
* following table. Each possible {@link #getAction()} value is listed in the first column. The
* other columns indicate which method or methods return valid data for that getAction() value:
*
*
*
* getAction() Value
* getClipDescription()
* getLocalState()
* getX()
* getY()
* getClipData()
* getResult()
*
*
* ACTION_DRAG_STARTED
* X
* X
* X
* X
*
*
*
*
* ACTION_DRAG_ENTERED
* X
* X
*
*
*
*
*
*
* ACTION_DRAG_LOCATION
* X
* X
* X
* X
*
*
*
*
* ACTION_DRAG_EXITED
* X
* X
*
*
*
*
*
*
* ACTION_DROP
* X
* X
* X
* X
* X
*
*
*
* ACTION_DRAG_ENDED
* X
* X
*
*
*
* X
*
*
*
* The {@link android.view.DragEvent#getAction()},
* {@link android.view.DragEvent#describeContents()},
* {@link android.view.DragEvent#writeToParcel(Parcel,int)}, and
* {@link android.view.DragEvent#toString()} methods always return valid data.
*
*
*
* Developer Guides
* For a guide to implementing drag and drop features, read the
* Drag and Drop developer guide.
*
*/
public class DragEvent implements Parcelable {
private static final boolean TRACK_RECYCLED_LOCATION = false;
int mAction;
float mX, mY;
ClipDescription mClipDescription;
ClipData mClipData;
Object mLocalState;
boolean mDragResult;
private DragEvent mNext;
private RuntimeException mRecycledLocation;
private boolean mRecycled;
private static final int MAX_RECYCLED = 10;
private static final Object gRecyclerLock = new Object();
private static int gRecyclerUsed = 0;
private static DragEvent gRecyclerTop = null;
/**
* Action constant returned by {@link #getAction()}: Signals the start of a
* drag and drop operation. The View should return {@code true} from its
* {@link View#onDragEvent(DragEvent) onDragEvent()} handler method or
* {@link View.View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()} listener
* if it can accept a drop. The onDragEvent() or onDrag() methods usually inspect the metadata
* from {@link #getClipDescription()} to determine if they can accept the data contained in
* this drag. For an operation that doesn't represent data transfer, these methods may
* perform other actions to determine whether or not the View should accept the drag.
* If the View wants to indicate that it is a valid drop target, it can also react by
* changing its appearance.
*
* A View only receives further drag events if it returns {@code true} in response to
* ACTION_DRAG_STARTED.
*
* @see #ACTION_DRAG_ENDED
*/
public static final int ACTION_DRAG_STARTED = 1;
/**
* Action constant returned by {@link #getAction()}: Sent to a View after
* {@link #ACTION_DRAG_ENTERED} if the drag shadow is still within the View object's bounding
* box. The {@link #getX()} and {@link #getY()} methods supply
* the X and Y position of of the drag point within the View object's bounding box.
*
* A View receives an {@link #ACTION_DRAG_ENTERED} event before receiving any
* ACTION_DRAG_LOCATION events.
*
*
* The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
* drag shadow out of the View object's bounding box. If the user moves the drag shadow back
* into the View object's bounding box, the View receives an ACTION_DRAG_ENTERED again before
* receiving any more ACTION_DRAG_LOCATION events.
*
* @see #ACTION_DRAG_ENTERED
* @see #getX()
* @see #getY()
*/
public static final int ACTION_DRAG_LOCATION = 2;
/**
* Action constant returned by {@link #getAction()}: Signals to a View that the user
* has released the drag shadow, and the drag point is within the bounding box of the View.
* The View should retrieve the data from the DragEvent by calling {@link #getClipData()}.
* The methods {@link #getX()} and {@link #getY()} return the X and Y position of the drop point
* within the View object's bounding box.
*
* The View should return {@code true} from its {@link View#onDragEvent(DragEvent)}
* handler or {@link View.View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()}
* listener if it accepted the drop, and {@code false} if it ignored the drop.
*
*
* The View can also react to this action by changing its appearance.
*
* @see #getClipData()
* @see #getX()
* @see #getY()
*/
public static final int ACTION_DROP = 3;
/**
* Action constant returned by {@link #getAction()}: Signals to a View that the drag and drop
* operation has concluded. A View that changed its appearance during the operation should
* return to its usual drawing state in response to this event.
*
* All views that received an ACTION_DRAG_STARTED event will receive the
* ACTION_DRAG_ENDED event even if they are not currently visible when the drag ends.
*
*
* The View object can call {@link #getResult()} to see the result of the operation.
* If a View returned {@code true} in response to {@link #ACTION_DROP}, then
* getResult() returns {@code true}, otherwise it returns {@code false}.
*
* @see #ACTION_DRAG_STARTED
* @see #getResult()
*/
public static final int ACTION_DRAG_ENDED = 4;
/**
* Action constant returned by {@link #getAction()}: Signals to a View that the drag point has
* entered the bounding box of the View.
*
* If the View can accept a drop, it can react to ACTION_DRAG_ENTERED
* by changing its appearance in a way that tells the user that the View is the current
* drop target.
*
* The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
* drag shadow out of the View object's bounding box. If the user moves the drag shadow back
* into the View object's bounding box, the View receives an ACTION_DRAG_ENTERED again before
* receiving any more ACTION_DRAG_LOCATION events.
*
* @see #ACTION_DRAG_ENTERED
* @see #ACTION_DRAG_LOCATION
*/
public static final int ACTION_DRAG_ENTERED = 5;
/**
* Action constant returned by {@link #getAction()}: Signals that the user has moved the
* drag shadow outside the bounding box of the View.
* The View can react by changing its appearance in a way that tells the user that
* View is no longer the immediate drop target.
*
* After the system sends an ACTION_DRAG_EXITED event to the View, the View receives no more
* ACTION_DRAG_LOCATION events until the user drags the drag shadow back over the View.
*
*
*/
public static final int ACTION_DRAG_EXITED = 6;
private DragEvent() {
}
private void init(int action, float x, float y, ClipDescription description, ClipData data,
Object localState, boolean result) {
mAction = action;
mX = x;
mY = y;
mClipDescription = description;
mClipData = data;
mLocalState = localState;
mDragResult = result;
}
static DragEvent obtain() {
return DragEvent.obtain(0, 0f, 0f, null, null, null, false);
}
/** @hide */
public static DragEvent obtain(int action, float x, float y, Object localState,
ClipDescription description, ClipData data, boolean result) {
final DragEvent ev;
synchronized (gRecyclerLock) {
if (gRecyclerTop == null) {
ev = new DragEvent();
ev.init(action, x, y, description, data, localState, result);
return ev;
}
ev = gRecyclerTop;
gRecyclerTop = ev.mNext;
gRecyclerUsed -= 1;
}
ev.mRecycledLocation = null;
ev.mRecycled = false;
ev.mNext = null;
ev.init(action, x, y, description, data, localState, result);
return ev;
}
/** @hide */
public static DragEvent obtain(DragEvent source) {
return obtain(source.mAction, source.mX, source.mY, source.mLocalState,
source.mClipDescription, source.mClipData, source.mDragResult);
}
/**
* Inspect the action value of this event.
* @return One of the following action constants, in the order in which they usually occur
* during a drag and drop operation:
*
* - {@link #ACTION_DRAG_STARTED}
* - {@link #ACTION_DRAG_ENTERED}
* - {@link #ACTION_DRAG_LOCATION}
* - {@link #ACTION_DROP}
* - {@link #ACTION_DRAG_EXITED}
* - {@link #ACTION_DRAG_ENDED}
*
*/
public int getAction() {
return mAction;
}
/**
* Gets the X coordinate of the drag point. The value is only valid if the event action is
* {@link #ACTION_DRAG_LOCATION} or {@link #ACTION_DROP}.
* @return The current drag point's Y coordinate
*/
public float getX() {
return mX;
}
/**
* Gets the Y coordinate of the drag point. The value is valid if the
* event action is {@link #ACTION_DRAG_ENTERED}, {@link #ACTION_DRAG_LOCATION},
* {@link #ACTION_DROP}, or {@link #ACTION_DRAG_EXITED}.
* @return The current drag point's Y coordinate
*/
public float getY() {
return mY;
}
/**
* Returns the {@link android.content.ClipData} object sent to the system as part of the call
* to
* {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
* This method only returns valid data if the event action is {@link #ACTION_DROP}.
* @return The ClipData sent to the system by startDrag().
*/
public ClipData getClipData() {
return mClipData;
}
/**
* Returns the {@link android.content.ClipDescription} object contained in the
* {@link android.content.ClipData} object sent to the system as part of the call to
* {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
* The drag handler or listener for a View can use the metadata in this object to decide if the
* View can accept the dragged View object's data.
*
* This method returns valid data for all event actions.
* @return The ClipDescription that was part of the ClipData sent to the system by startDrag().
*/
public ClipDescription getClipDescription() {
return mClipDescription;
}
/**
* Returns the local state object sent to the system as part of the call to
* {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
* The object is intended to provide local information about the drag and drop operation. For
* example, it can indicate whether the drag and drop operation is a copy or a move.
*
* This method returns valid data for all event actions.
*
* @return The local state object sent to the system by startDrag().
*/
public Object getLocalState() {
return mLocalState;
}
/**
*
* Returns an indication of the result of the drag and drop operation.
* This method only returns valid data if the action type is {@link #ACTION_DRAG_ENDED}.
* The return value depends on what happens after the user releases the drag shadow.
*
*
* If the user releases the drag shadow on a View that can accept a drop, the system sends an
* {@link #ACTION_DROP} event to the View object's drag event listener. If the listener
* returns {@code true}, then getResult() will return {@code true}.
* If the listener returns {@code false}, then getResult() returns {@code false}.
*
*
* Notice that getResult() also returns {@code false} if no {@link #ACTION_DROP} is sent. This
* happens, for example, when the user releases the drag shadow over an area outside of the
* application. In this case, the system sends out {@link #ACTION_DRAG_ENDED} for the current
* operation, but never sends out {@link #ACTION_DROP}.
*
* @return {@code true} if a drag event listener returned {@code true} in response to
* {@link #ACTION_DROP}. If the system did not send {@link #ACTION_DROP} before
* {@link #ACTION_DRAG_ENDED}, or if the listener returned {@code false} in response to
* {@link #ACTION_DROP}, then {@code false} is returned.
*/
public boolean getResult() {
return mDragResult;
}
/**
* Recycle the DragEvent, to be re-used by a later caller. After calling
* this function you must never touch the event again.
*
* @hide
*/
public final void recycle() {
// Ensure recycle is only called once!
if (TRACK_RECYCLED_LOCATION) {
if (mRecycledLocation != null) {
throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation);
}
mRecycledLocation = new RuntimeException("Last recycled here");
} else {
if (mRecycled) {
throw new RuntimeException(toString() + " recycled twice!");
}
mRecycled = true;
}
mClipData = null;
mClipDescription = null;
mLocalState = null;
synchronized (gRecyclerLock) {
if (gRecyclerUsed < MAX_RECYCLED) {
gRecyclerUsed++;
mNext = gRecyclerTop;
gRecyclerTop = this;
}
}
}
/**
* Returns a string containing a concise, human-readable representation of this DragEvent
* object.
* @return A string representation of the DragEvent object.
*/
@Override
public String toString() {
return "DragEvent{" + Integer.toHexString(System.identityHashCode(this))
+ " action=" + mAction + " @ (" + mX + ", " + mY + ") desc=" + mClipDescription
+ " data=" + mClipData + " local=" + mLocalState + " result=" + mDragResult
+ "}";
}
/* Parcelable interface */
/**
* Returns information about the {@link android.os.Parcel} representation of this DragEvent
* object.
* @return Information about the {@link android.os.Parcel} representation.
*/
public int describeContents() {
return 0;
}
/**
* Creates a {@link android.os.Parcel} object from this DragEvent object.
* @param dest A {@link android.os.Parcel} object in which to put the DragEvent object.
* @param flags Flags to store in the Parcel.
*/
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mAction);
dest.writeFloat(mX);
dest.writeFloat(mY);
dest.writeInt(mDragResult ? 1 : 0);
if (mClipData == null) {
dest.writeInt(0);
} else {
dest.writeInt(1);
mClipData.writeToParcel(dest, flags);
}
if (mClipDescription == null) {
dest.writeInt(0);
} else {
dest.writeInt(1);
mClipDescription.writeToParcel(dest, flags);
}
}
/**
* A container for creating a DragEvent from a Parcel.
*/
public static final Parcelable.Creator CREATOR =
new Parcelable.Creator() {
public DragEvent createFromParcel(Parcel in) {
DragEvent event = DragEvent.obtain();
event.mAction = in.readInt();
event.mX = in.readFloat();
event.mY = in.readFloat();
event.mDragResult = (in.readInt() != 0);
if (in.readInt() != 0) {
event.mClipData = ClipData.CREATOR.createFromParcel(in);
}
if (in.readInt() != 0) {
event.mClipDescription = ClipDescription.CREATOR.createFromParcel(in);
}
return event;
}
public DragEvent[] newArray(int size) {
return new DragEvent[size];
}
};
}