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 
17 package android.view;
18 
19 import static java.lang.Integer.toHexString;
20 
21 import android.app.Activity;
22 import android.os.IBinder;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 import android.os.RemoteException;
26 import android.util.Log;
27 
28 import com.android.internal.view.IDragAndDropPermissions;
29 
30 /**
31  * {@link DragAndDropPermissions} controls the access permissions for the content URIs associated
32  * with a {@link DragEvent}.
33  * <p>
34  * Permission are granted when this object is created by {@link
35  * android.app.Activity#requestDragAndDropPermissions(DragEvent)
36  * Activity.requestDragAndDropPermissions}.
37  * Which permissions are granted is defined by the set of flags passed to {@link
38  * View#startDragAndDrop(android.content.ClipData, View.DragShadowBuilder, Object, int)
39  * View.startDragAndDrop} by the app that started the drag operation.
40  * </p>
41  * <p>
42  * The lifecycle of the permissions is bound to the activity used to call {@link
43  * android.app.Activity#requestDragAndDropPermissions(DragEvent) requestDragAndDropPermissions}. The
44  * permissions are revoked when this activity is destroyed, or when {@link #release()} is called,
45  * whichever occurs first.
46  * </p>
47  * <p>
48  * If you anticipate that your application will receive a large number of drops (e.g. document
49  * editor), you should try to call {@link #release()} on the obtained permissions as soon as they
50  * are no longer required. Permissions can be added to your activity's
51  * {@link Activity#onSaveInstanceState} bundle and later retrieved in order to manually release
52  * the permissions once they are no longer needed.
53  * </p>
54  * <p>
55  * Learn more about <a href="/guide/topics/ui/drag-drop#DragPermissionsMultiWindow">drag permissions
56  * in multi-window mode</a>.
57  * </p>
58  */
59 public final class DragAndDropPermissions implements Parcelable {
60 
61     private static final String TAG = "DragAndDrop";
62     private static final boolean DEBUG = false;
63 
64     private final IDragAndDropPermissions mDragAndDropPermissions;
65 
66     /**
67      * Create a new {@link DragAndDropPermissions} object to control the access permissions for
68      * content URIs associated with {@link DragEvent}.
69      * @param dragEvent Drag event
70      * @return {@link DragAndDropPermissions} object or null if there are no content URIs associated
71      * with the {@link DragEvent}.
72      * @hide
73      */
obtain(DragEvent dragEvent)74     public static DragAndDropPermissions obtain(DragEvent dragEvent) {
75         if (dragEvent.getDragAndDropPermissions() == null) {
76             return null;
77         }
78         return new DragAndDropPermissions(dragEvent.getDragAndDropPermissions());
79     }
80 
81     /** @hide */
DragAndDropPermissions(IDragAndDropPermissions dragAndDropPermissions)82     private DragAndDropPermissions(IDragAndDropPermissions dragAndDropPermissions) {
83         mDragAndDropPermissions = dragAndDropPermissions;
84     }
85 
86     /**
87      * Take permissions, binding their lifetime to the activity.
88      *
89      * <p>Note: This API is exposed to apps via
90      * {@link Activity#requestDragAndDropPermissions(DragEvent)}.
91      *
92      * @param activityToken Binder pointing to an Activity instance to bind the lifetime to.
93      * @return True if permissions are successfully taken.
94      *
95      * @hide
96      */
take(IBinder activityToken)97     public boolean take(IBinder activityToken) {
98         try {
99             if (DEBUG) {
100                 Log.d(TAG, this + ": calling take() with activity-bound token: "
101                         + toHexString(activityToken.hashCode()));
102             }
103             mDragAndDropPermissions.take(activityToken);
104         } catch (RemoteException e) {
105             Log.w(TAG, this + ": take() failed with a RemoteException", e);
106             return false;
107         }
108         return true;
109     }
110 
111     /**
112      * Take permissions transiently. Permissions will be tied to this object's lifecycle; if not
113      * released explicitly, they will be released automatically when there are no more references
114      * to this object and it's garbage collected.
115      *
116      * <p>Note: This API is not exposed to apps.
117      *
118      * @return True if permissions are successfully taken.
119      *
120      * @hide
121      */
takeTransient()122     public boolean takeTransient() {
123         try {
124             if (DEBUG) {
125                 Log.d(TAG, this + ": calling takeTransient()");
126             }
127             mDragAndDropPermissions.takeTransient();
128         } catch (RemoteException e) {
129             Log.w(TAG, this + ": takeTransient() failed with a RemoteException", e);
130             return false;
131         }
132         return true;
133     }
134 
135     /**
136      * Revoke permissions explicitly.
137      */
release()138     public void release() {
139         try {
140             mDragAndDropPermissions.release();
141         } catch (RemoteException e) {
142             throw e.rethrowFromSystemServer();
143         }
144     }
145 
146     public static final @android.annotation.NonNull Parcelable.Creator<DragAndDropPermissions> CREATOR =
147             new Parcelable.Creator<DragAndDropPermissions> () {
148         @Override
149         public DragAndDropPermissions createFromParcel(Parcel source) {
150             return new DragAndDropPermissions(source);
151         }
152 
153         @Override
154         public DragAndDropPermissions[] newArray(int size) {
155             return new DragAndDropPermissions[size];
156         }
157     };
158 
159     @Override
describeContents()160     public int describeContents() {
161         return 0;
162     }
163 
164     @Override
writeToParcel(Parcel destination, int flags)165     public void writeToParcel(Parcel destination, int flags) {
166         destination.writeStrongInterface(mDragAndDropPermissions);
167     }
168 
DragAndDropPermissions(Parcel in)169     private DragAndDropPermissions(Parcel in) {
170         mDragAndDropPermissions = IDragAndDropPermissions.Stub.asInterface(in.readStrongBinder());
171     }
172 }
173