1/*
2** Copyright 2015, 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
17package android.view;
18
19import android.app.Activity;
20import android.os.Binder;
21import android.os.IBinder;
22import android.os.Parcel;
23import android.os.Parcelable;
24import android.os.RemoteException;
25
26import com.android.internal.view.IDragAndDropPermissions;
27
28/**
29 * {@link DragAndDropPermissions} controls the access permissions for the content URIs associated
30 * with a {@link DragEvent}.
31 * <p>
32 * Permission are granted when this object is created by {@link
33 * android.app.Activity#requestDragAndDropPermissions(DragEvent)
34 * Activity.requestDragAndDropPermissions}.
35 * Which permissions are granted is defined by the set of flags passed to {@link
36 * View#startDragAndDrop(android.content.ClipData, View.DragShadowBuilder, Object, int)
37 * View.startDragAndDrop} by the app that started the drag operation.
38 * </p>
39 * <p>
40 * The life cycle of the permissions is bound to the activity used to call {@link
41 * android.app.Activity#requestDragAndDropPermissions(DragEvent) requestDragAndDropPermissions}. The
42 * permissions are revoked when this activity is destroyed, or when {@link #release()} is called,
43 * whichever occurs first.
44 * </p>
45 * <p>
46 * If you anticipate that your application will receive a large number of drops (e.g. document
47 * editor), you should try to call {@link #release()} on the obtained permissions as soon as they
48 * are no longer required. Permissions can be added to your activity's
49 * {@link Activity#onSaveInstanceState} bundle and later retrieved in order to manually release
50 * the permissions once they are no longer needed.
51 * </p>
52 */
53public final class DragAndDropPermissions implements Parcelable {
54
55    private final IDragAndDropPermissions mDragAndDropPermissions;
56
57    private IBinder mTransientToken;
58
59    /**
60     * Create a new {@link DragAndDropPermissions} object to control the access permissions for
61     * content URIs associated with {@link DragEvent}.
62     * @param dragEvent Drag event
63     * @return {@link DragAndDropPermissions} object or null if there are no content URIs associated
64     * with the {@link DragEvent}.
65     * @hide
66     */
67    public static DragAndDropPermissions obtain(DragEvent dragEvent) {
68        if (dragEvent.getDragAndDropPermissions() == null) {
69            return null;
70        }
71        return new DragAndDropPermissions(dragEvent.getDragAndDropPermissions());
72    }
73
74    /** @hide */
75    private DragAndDropPermissions(IDragAndDropPermissions dragAndDropPermissions) {
76        mDragAndDropPermissions = dragAndDropPermissions;
77    }
78
79    /**
80     * Take the permissions and bind their lifetime to the activity.
81     * @param activityToken Binder pointing to an Activity instance to bind the lifetime to.
82     * @return True if permissions are successfully taken.
83     * @hide
84     */
85    public boolean take(IBinder activityToken) {
86        try {
87            mDragAndDropPermissions.take(activityToken);
88        } catch (RemoteException e) {
89            return false;
90        }
91        return true;
92    }
93
94    /**
95     * Take the permissions. Must call {@link #release} explicitly.
96     * @return True if permissions are successfully taken.
97     * @hide
98     */
99    public boolean takeTransient() {
100        try {
101            mTransientToken = new Binder();
102            mDragAndDropPermissions.takeTransient(mTransientToken);
103        } catch (RemoteException e) {
104            return false;
105        }
106        return true;
107    }
108
109    /**
110     * Revoke permissions explicitly.
111     */
112    public void release() {
113        try {
114            mDragAndDropPermissions.release();
115            mTransientToken = null;
116        } catch (RemoteException e) {
117        }
118    }
119
120    public static final Parcelable.Creator<DragAndDropPermissions> CREATOR =
121            new Parcelable.Creator<DragAndDropPermissions> () {
122        @Override
123        public DragAndDropPermissions createFromParcel(Parcel source) {
124            return new DragAndDropPermissions(source);
125        }
126
127        @Override
128        public DragAndDropPermissions[] newArray(int size) {
129            return new DragAndDropPermissions[size];
130        }
131    };
132
133    @Override
134    public int describeContents() {
135        return 0;
136    }
137
138    @Override
139    public void writeToParcel(Parcel destination, int flags) {
140        destination.writeStrongInterface(mDragAndDropPermissions);
141        destination.writeStrongBinder(mTransientToken);
142    }
143
144    private DragAndDropPermissions(Parcel in) {
145        mDragAndDropPermissions = IDragAndDropPermissions.Stub.asInterface(in.readStrongBinder());
146        mTransientToken = in.readStrongBinder();
147    }
148}
149