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 325917ea..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) {