Make contacts photo pickers compatible with new documents UI
The old contacts photo picker code was using unguaranteed behavior
(that Intent.GET_CONTENT would support MediaStore.EXTRA_OUTPUT) and this
caused it to not work anymore with the new document picker.
This CL changes all usages of files to instead use URIs.
Also, a FileProvider has been added to Contacts, to allow us to pass in
URI pointing to our private cache in intent.setClipData with
Intent.FLAG_GRANT_WRITE_URI_PERMISSION and Intent.FLAG_GRANT_READ_URI_PERMISSION
so we no longer have to reply on the MediaStore.EXTRA_OUTPUT being parsed
and supported. The use of the FileProvider also prevents unauthorized access
to temporary files during the caching process.
Bug: 10745342
Change-Id: Iaee3d7d112dd124a2f5596c4b9704ea75d3b3419
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index 32fb190..8a3ef32 100644
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -54,6 +54,8 @@
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.util.CallerInfoCacheUtils;
+import com.android.contacts.util.ContactPhotoUtils;
+
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -61,6 +63,7 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -294,9 +297,9 @@
public static Intent createSaveContactIntent(Context context, RawContactDeltaList state,
String saveModeExtraKey, int saveMode, boolean isProfile,
Class<? extends Activity> callbackActivity, String callbackAction, long rawContactId,
- String updatedPhotoPath) {
+ Uri updatedPhotoPath) {
Bundle bundle = new Bundle();
- bundle.putString(String.valueOf(rawContactId), updatedPhotoPath);
+ bundle.putParcelable(String.valueOf(rawContactId), updatedPhotoPath);
return createSaveContactIntent(context, state, saveModeExtraKey, saveMode, isProfile,
callbackActivity, callbackAction, bundle);
}
@@ -449,7 +452,7 @@
// the ContactProvider already knows about newly-created contacts.
if (updatedPhotos != null) {
for (String key : updatedPhotos.keySet()) {
- String photoFilePath = updatedPhotos.getString(key);
+ Uri photoUri = updatedPhotos.getParcelable(key);
long rawContactId = Long.parseLong(key);
// If the raw-contact ID is negative, we are saving a new raw-contact;
@@ -462,8 +465,7 @@
}
}
- File photoFile = new File(photoFilePath);
- if (!saveUpdatedPhoto(rawContactId, photoFile)) succeeded = false;
+ if (!saveUpdatedPhoto(rawContactId, photoUri)) succeeded = false;
}
}
@@ -484,37 +486,12 @@
* Save updated photo for the specified raw-contact.
* @return true for success, false for failure
*/
- private boolean saveUpdatedPhoto(long rawContactId, File photoFile) {
+ private boolean saveUpdatedPhoto(long rawContactId, Uri photoUri) {
final Uri outputUri = Uri.withAppendedPath(
ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
- try {
- final FileOutputStream outputStream = getContentResolver()
- .openAssetFileDescriptor(outputUri, "rw").createOutputStream();
- try {
- final FileInputStream inputStream = new FileInputStream(photoFile);
- try {
- final byte[] buffer = new byte[16 * 1024];
- int length;
- int totalLength = 0;
- while ((length = inputStream.read(buffer)) > 0) {
- outputStream.write(buffer, 0, length);
- totalLength += length;
- }
- Log.v(TAG, "Wrote " + totalLength + " bytes for photo " + photoFile.toString());
- } finally {
- inputStream.close();
- }
- } finally {
- outputStream.close();
- photoFile.delete();
- }
- } catch (IOException e) {
- Log.e(TAG, "Failed to write photo: " + photoFile.toString() + " because: " + e);
- return false;
- }
- return true;
+ return ContactPhotoUtils.savePhotoFromUriToUri(this, photoUri, outputUri, true);
}
/**