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.app.ActivityManagerNative;
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 mPermissionOwnerToken;
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            mPermissionOwnerToken = ActivityManagerNative.getDefault().
102                    newUriPermissionOwner("drop");
103            mDragAndDropPermissions.takeTransient(mPermissionOwnerToken);
104        } catch (RemoteException e) {
105            return false;
106        }
107        return true;
108    }
109
110    /**
111     * Revoke permissions explicitly.
112     */
113    public void release() {
114        try {
115            mDragAndDropPermissions.release();
116            mPermissionOwnerToken = null;
117        } catch (RemoteException e) {
118        }
119    }
120
121    public static final Parcelable.Creator<DragAndDropPermissions> CREATOR =
122            new Parcelable.Creator<DragAndDropPermissions> () {
123        @Override
124        public DragAndDropPermissions createFromParcel(Parcel source) {
125            return new DragAndDropPermissions(source);
126        }
127
128        @Override
129        public DragAndDropPermissions[] newArray(int size) {
130            return new DragAndDropPermissions[size];
131        }
132    };
133
134    @Override
135    public int describeContents() {
136        return 0;
137    }
138
139    @Override
140    public void writeToParcel(Parcel destination, int flags) {
141        destination.writeStrongInterface(mDragAndDropPermissions);
142        destination.writeStrongBinder(mPermissionOwnerToken);
143    }
144
145    private DragAndDropPermissions(Parcel in) {
146        mDragAndDropPermissions = IDragAndDropPermissions.Stub.asInterface(in.readStrongBinder());
147        mPermissionOwnerToken = in.readStrongBinder();
148    }
149}
150