Bind DropPermissions life cycle to Activity
Move requestDropPermissions from DragEvent to Activity.
Permissions will be granted using UriPermissionOwner
associated with this activity and revoked when the activity
is destroyed (if DropPermissions.release is not called before that).
Change-Id: Ic8f8fc3f56f57e83b9bc34ae8c96d82c2c9c4e1d
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6d72059..800ebc6 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -31,6 +31,8 @@
import android.transition.TransitionManager;
import android.util.ArrayMap;
import android.util.SuperNotCalledException;
+import android.view.DragEvent;
+import android.view.DropPermissions;
import android.view.Window.WindowControllerCallback;
import android.widget.Toolbar;
@@ -6336,6 +6338,21 @@
mActivityTransitionState.startPostponedEnterTransition();
}
+ /**
+ * Create {@link DropPermissions} object bound to this activity and controlling the access
+ * permissions for content URIs associated with the {@link DragEvent}.
+ * @param event Drag event
+ * @return The DropPermissions object used to control access to the content URIs. Null if
+ * no content URIs are associated with the event or if permissions could not be granted.
+ */
+ public DropPermissions requestDropPermissions(DragEvent event) {
+ DropPermissions dropPermissions = DropPermissions.obtain(event);
+ if (dropPermissions != null && dropPermissions.take(getActivityToken())) {
+ return dropPermissions;
+ }
+ return null;
+ }
+
// ------------------ Internal API ------------------
final void setParent(Activity parent) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1b08273..3a3aa92 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1845,6 +1845,15 @@
return true;
}
+ case GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder activityToken = data.readStrongBinder();
+ IBinder perm = getUriPermissionOwnerForActivity(activityToken);
+ reply.writeNoException();
+ reply.writeStrongBinder(perm);
+ return true;
+ }
+
case GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder owner = data.readStrongBinder();
@@ -5121,6 +5130,19 @@
return res;
}
+ public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(activityToken);
+ mRemote.transact(GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION, data, reply, 0);
+ reply.readException();
+ IBinder res = reply.readStrongBinder();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 0ecf223..61b1bc8 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -363,6 +363,7 @@
public String getProviderMimeType(Uri uri, int userId) throws RemoteException;
public IBinder newUriPermissionOwner(String name) throws RemoteException;
+ public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) throws RemoteException;
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException;
public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
@@ -920,4 +921,5 @@
int KILL_PACKAGE_DEPENDENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 354;
int ENTER_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 355;
int SET_VR_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 356;
+ int GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 357;
}
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 5903d4a..71db0b5 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -364,20 +364,9 @@
return mClipDescription;
}
- /**
- * Requests the permissions for the content URIs contained in {@link android.content.ClipData}
- * object associated with this event. Which permissions will be granted is defined by the set of
- * flags passed to {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)}.
- * Returns the {@link DropPermissions} object that can be used by the receiving app to release
- * the permissions for the content URIs when they are no longer needed.
- * This method only returns valid data if the event action is {@link #ACTION_DROP}.
- * @return The DropPermissions object used to control access to the content URIs.
- */
- public DropPermissions requestDropPermissions() {
- if (mDropPermissions == null) {
- return null;
- }
- return new DropPermissions(mDropPermissions);
+ /** @hide */
+ public IDropPermissions getDropPermissions() {
+ return mDropPermissions;
}
/**
diff --git a/core/java/android/view/DropPermissions.java b/core/java/android/view/DropPermissions.java
index 780461f..8c948a9 100644
--- a/core/java/android/view/DropPermissions.java
+++ b/core/java/android/view/DropPermissions.java
@@ -16,11 +16,27 @@
package android.view;
+import android.os.IBinder;
import android.os.RemoteException;
import com.android.internal.view.IDropPermissions;
import dalvik.system.CloseGuard;
+/**
+ * {@link DropPermissions} controls the access permissions for the content URIs associated with a
+ * {@link DragEvent}.
+ * <p>
+ * Permission are granted when this object is created by {@link
+ * android.app.Activity#requestDropPermissions(DragEvent) Activity.requestDropPermissions}.
+ * Which permissions are granted is defined by the set of flags passed to {@link
+ * View#startDragAndDrop(android.content.ClipData, View.DragShadowBuilder, Object, int)
+ * View.startDragAndDrop} by the app that started the drag operation.
+ * <p>
+ * The life cycle of the permissions is bound to the activity used to call {@link
+ * android.app.Activity#requestDropPermissions(DragEvent) requestDropPermissions}. The
+ * permissions are revoked when this activity is destroyed, or when {@link #release()} is called,
+ * whichever occurs first.
+ */
public final class DropPermissions {
private final IDropPermissions mDropPermissions;
@@ -28,21 +44,43 @@
private final CloseGuard mCloseGuard = CloseGuard.get();
/**
- * Create a new DropPermissions object to be passed to the client with a DragEvent.
- *
+ * Create a new {@link DropPermissions} object to control the access permissions for content
+ * URIs associated with {@link DragEvent}.
+ * @param dragEvent Drag event
+ * @return {@link DropPermissions} object or null if there are no content URIs associated with
+ * the {@link DragEvent}.
* @hide
*/
- DropPermissions(IDropPermissions dropPermissions) {
- mDropPermissions = dropPermissions;
- try {
- mDropPermissions.take();
- } catch (RemoteException e) {
+ public static DropPermissions obtain(DragEvent dragEvent) {
+ if (dragEvent.getDropPermissions() == null) {
+ return null;
}
- mCloseGuard.open("release");
+ return new DropPermissions(dragEvent.getDropPermissions());
+ }
+
+ /** @hide */
+ private DropPermissions(IDropPermissions dropPermissions) {
+ mDropPermissions = dropPermissions;
}
/**
- * Revoke permissions taken by {@link DragEvent#requestDropPermissions()}.
+ * Take the permissions and bind their lifetime to the activity.
+ * @param activityToken Binder pointing to an Activity instance to bind the lifetime to.
+ * @return True if permissions are successfully taken.
+ * @hide
+ */
+ public boolean take(IBinder activityToken) {
+ try {
+ mDropPermissions.take(activityToken);
+ } catch (RemoteException e) {
+ return false;
+ }
+ mCloseGuard.open("release");
+ return true;
+ }
+
+ /**
+ * Revoke permissions explicitly.
*/
public void release() {
try {
diff --git a/core/java/com/android/internal/view/IDropPermissions.aidl b/core/java/com/android/internal/view/IDropPermissions.aidl
index 86d27e7..2438bda 100644
--- a/core/java/com/android/internal/view/IDropPermissions.aidl
+++ b/core/java/com/android/internal/view/IDropPermissions.aidl
@@ -16,11 +16,13 @@
package com.android.internal.view;
+import android.os.IBinder;
+
/**
* Interface to allow a drop receiver to request permissions for URIs passed along with ClipData
* contained in DragEvent.
*/
interface IDropPermissions {
- void take();
+ void take(IBinder activityToken);
void release();
}