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);
     }
 
     /**