am c5435cdd: am e7469eca: am c50bbc02: Merge "Migrate extras to ClipData for image/video capture intents." into lmp-dev

* commit 'c5435cdd91f6778d753f99ee6ee8c5132e0ae962':
  Migrate extras to ClipData for image/video capture intents.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0bab7b2..de5b9c4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2205,6 +2205,7 @@
                     cl, component.getClassName(), r.intent);
             StrictMode.incrementExpectedActivityCount(activity.getClass());
             r.intent.setExtrasClassLoader(cl);
+            r.intent.prepareToEnterProcess();
             if (r.state != null) {
                 r.state.setClassLoader(cl);
             }
@@ -2429,6 +2430,7 @@
         for (int i=0; i<N; i++) {
             Intent intent = intents.get(i);
             intent.setExtrasClassLoader(r.activity.getClassLoader());
+            intent.prepareToEnterProcess();
             r.activity.mFragments.noteStateNotSaved();
             mInstrumentation.callActivityOnNewIntent(r.activity, intent);
         }
@@ -2552,6 +2554,7 @@
         try {
             java.lang.ClassLoader cl = packageInfo.getClassLoader();
             data.intent.setExtrasClassLoader(cl);
+            data.intent.prepareToEnterProcess();
             data.setExtrasClassLoader(cl);
             receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
         } catch (Exception e) {
@@ -2753,6 +2756,7 @@
         if (s != null) {
             try {
                 data.intent.setExtrasClassLoader(s.getClassLoader());
+                data.intent.prepareToEnterProcess();
                 try {
                     if (!data.rebind) {
                         IBinder binder = s.onBind(data.intent);
@@ -2781,6 +2785,7 @@
         if (s != null) {
             try {
                 data.intent.setExtrasClassLoader(s.getClassLoader());
+                data.intent.prepareToEnterProcess();
                 boolean doRebind = s.onUnbind(data.intent);
                 try {
                     if (doRebind) {
@@ -2856,6 +2861,7 @@
             try {
                 if (data.args != null) {
                     data.args.setExtrasClassLoader(s.getClassLoader());
+                    data.args.prepareToEnterProcess();
                 }
                 int res;
                 if (!data.taskRemoved) {
@@ -3506,6 +3512,7 @@
             try {
                 if (ri.mData != null) {
                     ri.mData.setExtrasClassLoader(r.activity.getClassLoader());
+                    ri.mData.prepareToEnterProcess();
                 }
                 if (DEBUG_RESULTS) Slog.v(TAG,
                         "Delivering result to activity " + r + " : " + ri);
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 7a16ef8..d19604b 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -810,20 +810,16 @@
         }
     }
 
-    /**
-     * Prepare this {@link ClipData} to leave an app process.
-     *
-     * @hide
-     */
-    public void prepareToLeaveUser(int userId) {
+    /** @hide */
+    public void fixUris(int contentUserHint) {
         final int size = mItems.size();
         for (int i = 0; i < size; i++) {
             final Item item = mItems.get(i);
             if (item.mIntent != null) {
-                item.mIntent.prepareToLeaveUser(userId);
+                item.mIntent.fixUris(contentUserHint);
             }
             if (item.mUri != null) {
-                item.mUri = maybeAddUserId(item.mUri, userId);
+                item.mUri = maybeAddUserId(item.mUri, contentUserHint);
             }
         }
     }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 51ffbc9..f224f40 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -17,6 +17,7 @@
 package android.content;
 
 import android.content.pm.ApplicationInfo;
+import android.provider.MediaStore;
 import android.util.ArraySet;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -38,6 +39,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.StrictMode;
+import android.os.UserHandle;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsProvider;
 import android.provider.OpenableColumns;
@@ -3958,6 +3960,7 @@
     private Rect mSourceBounds;
     private Intent mSelector;
     private ClipData mClipData;
+    private int mContentUserHint = UserHandle.USER_CURRENT;
 
     // ---------------------------------------------------------------------
 
@@ -3977,6 +3980,7 @@
         this.mPackage = o.mPackage;
         this.mComponent = o.mComponent;
         this.mFlags = o.mFlags;
+        this.mContentUserHint = o.mContentUserHint;
         if (o.mCategories != null) {
             this.mCategories = new ArraySet<String>(o.mCategories);
         }
@@ -4681,6 +4685,11 @@
         return mClipData;
     }
 
+    /** @hide */
+    public int getContentUserHint() {
+        return mContentUserHint;
+    }
+
     /**
      * Sets the ClassLoader that will be used when unmarshalling
      * any Parcelable values from the extras of this Intent.
@@ -5700,6 +5709,16 @@
     }
 
     /**
+     * This is NOT a secure mechanism to identify the user who sent the intent.
+     * When the intent is sent to a different user, it is used to fix uris by adding the userId
+     * who sent the intent.
+     * @hide
+     */
+    public void setContentUserHint(int contentUserHint) {
+        mContentUserHint = contentUserHint;
+    }
+
+    /**
      * Add extended data to the intent.  The name must include a package
      * prefix, for example the app com.android.contacts would use names
      * like "com.android.contacts.ShowAll".
@@ -6752,6 +6771,7 @@
     @FillInFlags
     public int fillIn(Intent other, @FillInFlags int flags) {
         int changes = 0;
+        boolean mayHaveCopiedUris = false;
         if (other.mAction != null
                 && (mAction == null || (flags&FILL_IN_ACTION) != 0)) {
             mAction = other.mAction;
@@ -6763,6 +6783,7 @@
             mData = other.mData;
             mType = other.mType;
             changes |= FILL_IN_DATA;
+            mayHaveCopiedUris = true;
         }
         if (other.mCategories != null
                 && (mCategories == null || (flags&FILL_IN_CATEGORIES) != 0)) {
@@ -6792,6 +6813,7 @@
                 && (mClipData == null || (flags&FILL_IN_CLIP_DATA) != 0)) {
             mClipData = other.mClipData;
             changes |= FILL_IN_CLIP_DATA;
+            mayHaveCopiedUris = true;
         }
         // Component is special: it can -only- be set if explicitly allowed,
         // since otherwise the sender could force the intent somewhere the
@@ -6809,12 +6831,14 @@
         if (mExtras == null) {
             if (other.mExtras != null) {
                 mExtras = new Bundle(other.mExtras);
+                mayHaveCopiedUris = true;
             }
         } else if (other.mExtras != null) {
             try {
                 Bundle newb = new Bundle(other.mExtras);
                 newb.putAll(mExtras);
                 mExtras = newb;
+                mayHaveCopiedUris = true;
             } catch (RuntimeException e) {
                 // Modifying the extras can cause us to unparcel the contents
                 // of the bundle, and if we do this in the system process that
@@ -6824,6 +6848,10 @@
                 Log.w("Intent", "Failure filling in extras", e);
             }
         }
+        if (mayHaveCopiedUris && mContentUserHint == UserHandle.USER_CURRENT
+                && other.mContentUserHint != UserHandle.USER_CURRENT) {
+            mContentUserHint = other.mContentUserHint;
+        }
         return changes;
     }
 
@@ -7051,8 +7079,15 @@
             first = false;
             b.append("(has extras)");
         }
+        if (mContentUserHint != UserHandle.USER_CURRENT) {
+            if (!first) {
+                b.append(' ');
+            }
+            first = false;
+            b.append("u=").append(mContentUserHint);
+        }
         if (mSelector != null) {
-            b.append(" sel={");
+            b.append(" sel=");
             mSelector.toShortString(b, secure, comp, extras, clip);
             b.append("}");
         }
@@ -7229,7 +7264,7 @@
         } else {
             out.writeInt(0);
         }
-
+        out.writeInt(mContentUserHint);
         out.writeBundle(mExtras);
     }
 
@@ -7278,7 +7313,7 @@
         if (in.readInt() != 0) {
             mClipData = new ClipData(in);
         }
-
+        mContentUserHint = in.readInt();
         mExtras = in.readBundle();
     }
 
@@ -7488,39 +7523,50 @@
     }
 
     /**
-     * Prepare this {@link Intent} to be sent to another user
-     *
      * @hide
      */
-    public void prepareToLeaveUser(int userId) {
+    public void prepareToEnterProcess() {
+        if (mContentUserHint != UserHandle.USER_CURRENT) {
+            fixUris(mContentUserHint);
+            mContentUserHint = UserHandle.USER_CURRENT;
+        }
+    }
+
+    /**
+     * @hide
+     */
+     public void fixUris(int contentUserHint) {
         Uri data = getData();
         if (data != null) {
-            mData = maybeAddUserId(data, userId);
-        }
-        if (mSelector != null) {
-            mSelector.prepareToLeaveUser(userId);
+            mData = maybeAddUserId(data, contentUserHint);
         }
         if (mClipData != null) {
-            mClipData.prepareToLeaveUser(userId);
+            mClipData.fixUris(contentUserHint);
         }
         String action = getAction();
         if (ACTION_SEND.equals(action)) {
             final Uri stream = getParcelableExtra(EXTRA_STREAM);
             if (stream != null) {
-                putExtra(EXTRA_STREAM, maybeAddUserId(stream, userId));
+                putExtra(EXTRA_STREAM, maybeAddUserId(stream, contentUserHint));
             }
-        }
-        if (ACTION_SEND_MULTIPLE.equals(action)) {
+        } else if (ACTION_SEND_MULTIPLE.equals(action)) {
             final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM);
             if (streams != null) {
                 ArrayList<Uri> newStreams = new ArrayList<Uri>();
                 for (int i = 0; i < streams.size(); i++) {
-                    newStreams.add(maybeAddUserId(streams.get(i), userId));
+                    newStreams.add(maybeAddUserId(streams.get(i), contentUserHint));
                 }
                 putParcelableArrayListExtra(EXTRA_STREAM, newStreams);
             }
+        } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
+                || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(action)
+                || MediaStore.ACTION_VIDEO_CAPTURE.equals(action)) {
+            final Uri output = getParcelableExtra(MediaStore.EXTRA_OUTPUT);
+            if (output != null) {
+                putExtra(MediaStore.EXTRA_OUTPUT, maybeAddUserId(output, contentUserHint));
+            }
         }
-    }
+     }
 
     /**
      * Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and
@@ -7611,6 +7657,20 @@
                 }
             } catch (ClassCastException e) {
             }
+        } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
+                || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(action)
+                || MediaStore.ACTION_VIDEO_CAPTURE.equals(action)) {
+            final Uri output;
+            try {
+                output = getParcelableExtra(MediaStore.EXTRA_OUTPUT);
+            } catch (ClassCastException e) {
+                return false;
+            }
+            if (output != null) {
+                setClipData(ClipData.newRawUri("", output));
+                addFlags(FLAG_GRANT_WRITE_URI_PERMISSION|FLAG_GRANT_READ_URI_PERMISSION);
+                return true;
+            }
         }
 
         return false;
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 325917e..d137f0c 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -256,6 +256,11 @@
      * object in the extra field. This is useful for applications that only need a small image.
      * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri
      * value of EXTRA_OUTPUT.
+     * As of {@link android.os.Build.VERSION_CODES#L}, this uri can also be supplied through
+     * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
+     * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
+     * If you don't set a ClipData, it will be copied there for you when calling
+     * {@link Context#startActivity(Intent)}.
      * @see #EXTRA_OUTPUT
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@@ -276,6 +281,11 @@
      * object in the extra field. This is useful for applications that only need a small image.
      * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri
      * value of EXTRA_OUTPUT.
+     * As of {@link android.os.Build.VERSION_CODES#L}, this uri can also be supplied through
+     * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
+     * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
+     * If you don't set a ClipData, it will be copied there for you when calling
+     * {@link Context#startActivity(Intent)}.
      *
      * @see #ACTION_IMAGE_CAPTURE
      * @see #EXTRA_OUTPUT
@@ -294,6 +304,11 @@
      * where the video is written. If EXTRA_OUTPUT is not present the video will be
      * written to the standard location for videos, and the Uri of that location will be
      * returned in the data field of the Uri.
+     * As of {@link android.os.Build.VERSION_CODES#L}, this uri can also be supplied through
+     * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
+     * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
+     * If you don't set a ClipData, it will be copied there for you when calling
+     * {@link Context#startActivity(Intent)}.
      * @see #EXTRA_OUTPUT
      * @see #EXTRA_VIDEO_QUALITY
      * @see #EXTRA_SIZE_LIMIT
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 0eadde1..1c01353 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -89,7 +89,7 @@
             Slog.e(TAG, "PackageManagerService is dead?");
         }
         if (canForward) {
-            newIntent.prepareToLeaveUser(callingUserId);
+            newIntent.setContentUserHint(callingUserId);
 
             final android.content.pm.ResolveInfo ri = getPackageManager().resolveActivityAsUser(
                         newIntent, MATCH_DEFAULT_ONLY, userDest.getIdentifier());
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 314e906..f38b280 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6644,6 +6644,11 @@
         if (data == null && clip == null) {
             return null;
         }
+        // Default userId for uris in the intent (if they don't specify it themselves)
+        int contentUserHint = intent.getContentUserHint();
+        if (contentUserHint == UserHandle.USER_CURRENT) {
+            contentUserHint = UserHandle.getUserId(callingUid);
+        }
         final IPackageManager pm = AppGlobals.getPackageManager();
         int targetUid;
         if (needed != null) {
@@ -6663,7 +6668,7 @@
             }
         }
         if (data != null) {
-            GrantUri grantUri = GrantUri.resolve(UserHandle.getUserId(callingUid), data);
+            GrantUri grantUri = GrantUri.resolve(contentUserHint, data);
             targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode,
                     targetUid);
             if (targetUid > 0) {
@@ -6677,7 +6682,7 @@
             for (int i=0; i<clip.getItemCount(); i++) {
                 Uri uri = clip.getItemAt(i).getUri();
                 if (uri != null) {
-                    GrantUri grantUri = GrantUri.resolve(UserHandle.getUserId(callingUid), uri);
+                    GrantUri grantUri = GrantUri.resolve(contentUserHint, uri);
                     targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode,
                             targetUid);
                     if (targetUid > 0) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ab13259..3785229 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2587,7 +2587,7 @@
                     + " res=" + resultCode + " data=" + resultData);
             if (resultTo.userId != r.userId) {
                 if (resultData != null) {
-                    resultData.prepareToLeaveUser(r.userId);
+                    resultData.setContentUserHint(r.userId);
                 }
             }
             if (r.info.applicationInfo.uid > 0) {