| /* |
| * 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: real docs */ |
| 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()}. Delivery of a DragEvent whose |
| * action is ACTION_DRAG_STARTED means that a drag operation has been initiated. The |
| * view receiving this DragEvent should inspect the metadata of the dragged content, |
| * available via {@link #getClipDescription()}, and return {@code true} from |
| * {@link View#onDragEvent(DragEvent)} if the view is prepared to accept a drop of |
| * that clip data. If the view chooses to present a visual indication that it is |
| * a valid target of the ongoing drag, then it should draw that indication in response |
| * to this event. |
| * <p> |
| * A view will only receive ACTION_DRAG_ENTERED, ACTION_DRAG_LOCATION, ACTION_DRAG_EXITED, |
| * and ACTION_DRAG_LOCATION events if it returns {@code true} in response to the |
| * ACTION_DRAG_STARTED event. |
| */ |
| public static final int ACTION_DRAG_STARTED = 1; |
| |
| /** |
| * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose |
| * action is ACTION_DRAG_LOCATION means that the drag operation is currently hovering |
| * over the view. The {@link #getX()} and {@link #getY()} methods supply the location |
| * of the drag point within the view's coordinate system. |
| * <p> |
| * A view will receive an ACTION_DRAG_ENTERED event before receiving any |
| * ACTION_DRAG_LOCATION events. If the drag point leaves the view, then an |
| * ACTION_DRAG_EXITED event is delivered to the view, after which no more |
| * ACTION_DRAG_LOCATION events will be sent (unless the drag re-enters the view, |
| * of course). |
| */ |
| public static final int ACTION_DRAG_LOCATION = 2; |
| |
| /** |
| * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose |
| * action is ACTION_DROP means that the dragged content has been dropped on this view. |
| * The view should retrieve the content via {@link #getClipData()} and act on it |
| * appropriately. The {@link #getX()} and {@link #getY()} methods supply the location |
| * of the drop point within the view's coordinate system. |
| * <p> |
| * The view should return {@code true} from its {@link View#onDragEvent(DragEvent)} |
| * method in response to this event if it accepted the content, and {@code false} |
| * if it ignored the drop. |
| */ |
| public static final int ACTION_DROP = 3; |
| |
| /** |
| * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose |
| * action is ACTION_DRAG_ENDED means that the drag operation has concluded. A view |
| * that is drawing a visual indication of drag acceptance should return to its usual |
| * drawing state in response to this event. |
| * <p> |
| * 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. |
| */ |
| public static final int ACTION_DRAG_ENDED = 4; |
| |
| /** |
| * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose |
| * action is ACTION_DRAG_ENTERED means that the drag point has entered the view's |
| * bounds. If the view changed its visual state in response to the ACTION_DRAG_ENTERED |
| * event, it should return to its normal drag-in-progress visual state in response to |
| * this event. |
| * <p> |
| * A view will receive an ACTION_DRAG_ENTERED event before receiving any |
| * ACTION_DRAG_LOCATION events. If the drag point leaves the view, then an |
| * ACTION_DRAG_EXITED event is delivered to the view, after which no more |
| * ACTION_DRAG_LOCATION events will be sent (unless the drag re-enters the view, |
| * of course). |
| */ |
| public static final int ACTION_DRAG_ENTERED = 5; |
| |
| /** |
| * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose |
| * action is ACTION_DRAG_ENTERED means that the drag point has entered the view's |
| * bounds. If the view chooses to present a visual indication that it will receive |
| * the drop if it occurs now, then it should draw that indication in response to |
| * this event. |
| * <p> |
| * A view will receive an ACTION_DRAG_ENTERED event before receiving any |
| * ACTION_DRAG_LOCATION events. If the drag point leaves the view, then an |
| * ACTION_DRAG_EXITED event is delivered to the view, after which no more |
| * ACTION_DRAG_LOCATION events will be sent (unless the drag re-enters the view, |
| * of course). |
| */ |
| 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 {@link #ACTION_DRAG_STARTED}, {@link #ACTION_DRAG_ENDED}, |
| * {@link #ACTION_DROP}, {@link #ACTION_DRAG_ENTERED}, {@link #ACTION_DRAG_EXITED}, |
| * or {@link #ACTION_DRAG_LOCATION}. |
| */ |
| public int getAction() { |
| return mAction; |
| } |
| |
| /** |
| * For ACTION_DRAG_LOCATION and ACTION_DROP events, returns the x coordinate of the |
| * drag point. |
| * @return The current drag point's x coordinate, when relevant. |
| */ |
| public float getX() { |
| return mX; |
| } |
| |
| /** |
| * For ACTION_DRAG_LOCATION and ACTION_DROP events, returns the y coordinate of the |
| * drag point. |
| * @return The current drag point's y coordinate, when relevant. |
| */ |
| public float getY() { |
| return mY; |
| } |
| |
| /** |
| * Provides the data payload of the drag operation. This payload is only available |
| * for events whose action value is ACTION_DROP. |
| * @return The ClipData containing the data being dropped on the view. |
| */ |
| public ClipData getClipData() { |
| return mClipData; |
| } |
| |
| /** |
| * Provides a description of the drag operation's data payload. This payload is |
| * available for all DragEvents other than ACTION_DROP. |
| * @return A ClipDescription describing the contents of the data being dragged. |
| */ |
| public ClipDescription getClipDescription() { |
| return mClipDescription; |
| } |
| |
| /** |
| * Provides the local state object passed as the {@code myLocalState} parameter to |
| * View.startDrag(). The object will always be null here if the application receiving |
| * the DragEvent is not the one that started the drag. |
| */ |
| public Object getLocalState() { |
| return mLocalState; |
| } |
| |
| /** |
| * Provides an indication of whether the drag operation concluded successfully. |
| * This method is only available on ACTION_DRAG_ENDED events. |
| * @return {@code true} if the drag operation ended with an accepted drop; {@code false} |
| * otherwise. |
| */ |
| 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; |
| } |
| } |
| } |
| |
| @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 */ |
| |
| public int describeContents() { |
| return 0; |
| } |
| |
| 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); |
| } |
| } |
| |
| public static final Parcelable.Creator<DragEvent> CREATOR = |
| new Parcelable.Creator<DragEvent>() { |
| 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]; |
| } |
| }; |
| } |