Merge "Remove InputContentInfo#requestPermission()" into nyc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 0323098f..237dafb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -44923,7 +44923,6 @@
     method public android.content.ClipDescription getDescription();
     method public android.net.Uri getLinkUri();
     method public void releasePermission();
-    method public void requestPermission();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputContentInfo> CREATOR;
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index aa1d74c..a06c36a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -48091,7 +48091,6 @@
     method public android.content.ClipDescription getDescription();
     method public android.net.Uri getLinkUri();
     method public void releasePermission();
-    method public void requestPermission();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputContentInfo> CREATOR;
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index d904415..361161c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -45003,7 +45003,6 @@
     method public android.content.ClipDescription getDescription();
     method public android.net.Uri getLinkUri();
     method public void releasePermission();
-    method public void requestPermission();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputContentInfo> CREATOR;
   }
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 07910b6..ecfcbc5 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -840,15 +840,16 @@
     public void closeConnection();
 
     /**
-     * When this flag is used, the editor will be able to request read access to the content URI
-     * contained in the {@link InputContentInfo} object.
+     * When this flag is used in {@link #commitContent(InputContentInfo, int, Bundle)}, the editor
+     * will be able to request read access to the content URI contained in the
+     * {@link InputContentInfo} object.
      *
      * <p>Make sure that the content provider owning the Uri sets the
      * {@link android.R.styleable#AndroidManifestProvider_grantUriPermissions
      * grantUriPermissions} attribute in its manifest or included the
      * {@link android.R.styleable#AndroidManifestGrantUriPermission
-     * &lt;grant-uri-permissions&gt;} tag. Otherwise {@link InputContentInfo#requestPermission()}
-     * can fail.</p>
+     * &lt;grant-uri-permissions&gt;} tag. Otherwise
+     * {@link #commitContent(InputContentInfo, int, Bundle)} can fail.</p>
      *
      * <p>Although calling this API is allowed only for the IME that is currently selected, the
      * client is able to request a temporary read-only access even after the current IME is switched
diff --git a/core/java/android/view/inputmethod/InputContentInfo.java b/core/java/android/view/inputmethod/InputContentInfo.java
index 9579bbf..df20643 100644
--- a/core/java/android/view/inputmethod/InputContentInfo.java
+++ b/core/java/android/view/inputmethod/InputContentInfo.java
@@ -163,22 +163,6 @@
     }
 
     /**
-     * Requests a temporary read-only access permission for content URI associated with this object.
-     *
-     * <p>Does nothing if the temporary permission is already granted.</p>
-     */
-    public void requestPermission() {
-        if (mUriToken == null) {
-            return;
-        }
-        try {
-            mUriToken.take();
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Releases a temporary read-only access permission for content URI associated with this object.
      *
      * <p>Does nothing if the temporary permission is not granted.</p>
diff --git a/core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl b/core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl
index 8abc807..c259348 100644
--- a/core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl
@@ -22,6 +22,5 @@
  * {@hide}
  */
 interface IInputContentUriToken {
-    void take();
     void release();
 }
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 9a09dcc..15422b6 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -517,20 +517,22 @@
 
     public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
         boolean result = false;
+        final boolean grantUriPermission =
+                (flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0;
         if (isMethodMissing(MissingMethodFlags.COMMIT_CONTENT)) {
             // This method is not implemented.
             return false;
         }
         try {
-            if ((flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
+            if (grantUriPermission) {
                 final AbstractInputMethodService inputMethodService = mInputMethodService.get();
                 if (inputMethodService == null) {
                     // This basically should not happen, because it's the the caller of this method.
                     return false;
                 }
+                // Temporarily grant URI permission.
                 inputMethodService.exposeContent(inputContentInfo, this);
             }
-
             InputContextCallback callback = InputContextCallback.getInstance();
             mIInputContext.commitContent(inputContentInfo, flags, opts, callback.mSeq, callback);
             synchronized (callback) {
@@ -540,6 +542,10 @@
                 }
             }
             callback.dispose();
+            // If this request is not handled, then there is no reason to keep the URI permission.
+            if (grantUriPermission && !result) {
+                inputContentInfo.releasePermission();
+            }
         } catch (RemoteException e) {
             return false;
         }
diff --git a/services/core/java/com/android/server/InputContentUriTokenHandler.java b/services/core/java/com/android/server/InputContentUriTokenHandler.java
index 3f4972b..12e1d62 100644
--- a/services/core/java/com/android/server/InputContentUriTokenHandler.java
+++ b/services/core/java/com/android/server/InputContentUriTokenHandler.java
@@ -45,48 +45,40 @@
     @GuardedBy("mLock")
     private IBinder mPermissionOwnerToken = null;
 
-    InputContentUriTokenHandler(@NonNull Uri contentUri, int sourceUid,
+    static InputContentUriTokenHandler create(@NonNull Uri contentUri, int sourceUid,
             @NonNull String targetPackage, @UserIdInt int sourceUserId,
             @UserIdInt int targetUserId) {
+        final IBinder permissionOwner;
+        try {
+            permissionOwner = ActivityManagerNative.getDefault()
+                    .newUriPermissionOwner("InputContentUriTokenHandler");
+        } catch (RemoteException e) {
+            return null;
+        }
+
+        long origId = Binder.clearCallingIdentity();
+        try {
+            ActivityManagerNative.getDefault().grantUriPermissionFromOwner(
+                    permissionOwner, sourceUserId, targetPackage, contentUri,
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, targetUserId);
+        } catch (RemoteException e) {
+            return null;
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+        return new InputContentUriTokenHandler(contentUri, sourceUid, targetPackage, sourceUserId,
+                targetUserId, permissionOwner);
+    }
+
+    private InputContentUriTokenHandler(@NonNull Uri contentUri, int sourceUid,
+            @NonNull String targetPackage, @UserIdInt int sourceUserId,
+            @UserIdInt int targetUserId, @NonNull IBinder permissionOwnerToken) {
         mUri = contentUri;
         mSourceUid = sourceUid;
         mTargetPackage = targetPackage;
         mSourceUserId = sourceUserId;
         mTargetUserId = targetUserId;
-    }
-
-    @Override
-    public void take() {
-        synchronized (mLock) {
-            if (mPermissionOwnerToken != null) {
-                // Permission is already granted.
-                return;
-            }
-
-            try {
-                mPermissionOwnerToken = ActivityManagerNative.getDefault()
-                        .newUriPermissionOwner("InputContentUriTokenHandler");
-            } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
-            }
-
-            doTakeLocked(mPermissionOwnerToken);
-        }
-    }
-
-    private void doTakeLocked(@NonNull IBinder permissionOwner) {
-        long origId = Binder.clearCallingIdentity();
-        try {
-            try {
-                ActivityManagerNative.getDefault().grantUriPermissionFromOwner(
-                        permissionOwner, mSourceUid, mTargetPackage, mUri,
-                        Intent.FLAG_GRANT_READ_URI_PERMISSION, mSourceUserId, mTargetUserId);
-            } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
+        mPermissionOwnerToken = permissionOwnerToken;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index e0d89f2..2c22829 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -3953,7 +3953,7 @@
             }
             final int imeUserId = UserHandle.getUserId(uid);
             final int appUserId = UserHandle.getUserId(mCurClient.uid);
-            return new InputContentUriTokenHandler(contentUri, uid, packageName, imeUserId,
+            return InputContentUriTokenHandler.create(contentUri, uid, packageName, imeUserId,
                     appUserId);
         }
     }