Contacts App modifications for large photos.

Most of the work is on the provider side - essentially, the
provider will now deal with any size photo, downsizing it as
necessary to fit in a display size and thumbnail size.  So
on the client we just need to pass in a larger photo to get a
hi-res display image for the contact.

Also switched a few spots to use the PHOTO_URI (with
openAssetFile) instead of PHOTO_THUMB_URI - more likely
remain.

Change-Id: I6ff8dd5453a9ff787907ab113d6e8aa6a71fcae1
diff --git a/src/com/android/contacts/ContactLoader.java b/src/com/android/contacts/ContactLoader.java
index 7ed9d86..f10e6b8 100644
--- a/src/com/android/contacts/ContactLoader.java
+++ b/src/com/android/contacts/ContactLoader.java
@@ -28,6 +28,7 @@
 import android.content.Loader;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.net.Uri;
@@ -45,6 +46,8 @@
 import android.util.Log;
 
 import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -673,6 +676,33 @@
          * not found, returns null
          */
         private void loadPhotoBinaryData(Result contactData) {
+
+            // If we have a photo URI, try loading that first.
+            String photoUri = contactData.getPhotoUri();
+            if (photoUri != null) {
+                try {
+                    AssetFileDescriptor fd = getContext().getContentResolver()
+                           .openAssetFileDescriptor(Uri.parse(photoUri), "r");
+                    byte[] buffer = new byte[16 * 1024];
+                    FileInputStream fis = fd.createInputStream();
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    try {
+                        int size;
+                        while ((size = fis.read(buffer)) != -1) {
+                            baos.write(buffer, 0, size);
+                        }
+                        contactData.setPhotoBinaryData(baos.toByteArray());
+                    } finally {
+                        fis.close();
+                        fd.close();
+                    }
+                    return;
+                } catch (IOException ioe) {
+                    // Just fall back to the case below.
+                }
+            }
+
+            // If we couldn't load from a file, fall back to the data blob.
             final long photoId = contactData.getPhotoId();
             if (photoId <= 0) {
                 // No photo ID
diff --git a/src/com/android/contacts/GroupMemberLoader.java b/src/com/android/contacts/GroupMemberLoader.java
index 13edff0..e2945f6 100644
--- a/src/com/android/contacts/GroupMemberLoader.java
+++ b/src/com/android/contacts/GroupMemberLoader.java
@@ -48,10 +48,11 @@
         Data.CONTACT_PRESENCE,                  // 6
         Data.CONTACT_CHAT_CAPABILITY,           // 7
         Data.PHOTO_ID,                          // 8
-        Data.PHOTO_THUMBNAIL_URI,               // 9
-        Data.LOOKUP_KEY,                        // 10
-        Data.PHONETIC_NAME,                     // 11
-        Data.HAS_PHONE_NUMBER,                  // 12
+        Data.PHOTO_URI,                         // 9
+        Data.PHOTO_THUMBNAIL_URI,               // 10
+        Data.LOOKUP_KEY,                        // 11
+        Data.PHONETIC_NAME,                     // 12
+        Data.HAS_PHONE_NUMBER,                  // 13
     };
 
     private final long mGroupId;
@@ -66,6 +67,7 @@
     public static final int CONTACT_CHAT_CAPABILITY_COLUMN_INDEX = 7;
     public static final int CONTACT_PHOTO_ID_COLUMN_INDEX = 8;
     public static final int CONTACT_PHOTO_URI_COLUMN_INDEX = 9;
+    public static final int CONTACT_PHOTO_THUMBNAIL_URI_COLUMN_INDEX = 10;
     public static final int CONTACT_LOOKUP_KEY_COLUMN_INDEX = 10;
     public static final int CONTACT_PHONETIC_NAME_COLUMN_INDEX = 11;
     public static final int CONTACT_HAS_PHONE_COLUMN_INDEX = 12;
diff --git a/src/com/android/contacts/activities/AttachPhotoActivity.java b/src/com/android/contacts/activities/AttachPhotoActivity.java
index 65d24c3..1eabaf7 100644
--- a/src/com/android/contacts/activities/AttachPhotoActivity.java
+++ b/src/com/android/contacts/activities/AttachPhotoActivity.java
@@ -35,6 +35,7 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Photo;
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.DisplayPhoto;
 import android.provider.ContactsContract.RawContacts;
 import android.widget.Toast;
 
@@ -57,6 +58,9 @@
 
     private ContentResolver mContentResolver;
 
+    // Height/width (in pixels) to request for the photo - queried from the provider.
+    private static int mPhotoDim;
+
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -70,6 +74,16 @@
         }
 
         mContentResolver = getContentResolver();
+
+        // Load the photo dimension to request.
+        Cursor c = mContentResolver.query(DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
+                new String[]{DisplayPhoto.DISPLAY_MAX_DIM}, null, null, null);
+        try {
+            c.moveToFirst();
+            mPhotoDim = c.getInt(0);
+        } finally {
+            c.close();
+        }
     }
 
     @Override
@@ -121,8 +135,8 @@
             intent.putExtra("crop", "true");
             intent.putExtra("aspectX", 1);
             intent.putExtra("aspectY", 1);
-            intent.putExtra("outputX", 96);
-            intent.putExtra("outputY", 96);
+            intent.putExtra("outputX", mPhotoDim);
+            intent.putExtra("outputY", mPhotoDim);
             intent.putExtra("return-data", true);
             startActivityForResult(intent, REQUEST_CROP_PHOTO);
 
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index ece2a29..4d116d1 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -66,6 +66,7 @@
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.CommonDataKinds.Website;
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.DisplayPhoto;
 import android.provider.ContactsContract.Groups;
 import android.provider.ContactsContract.Intents;
 import android.provider.ContactsContract.RawContacts;
@@ -196,8 +197,6 @@
 
     private final EntityDeltaComparator mComparator = new EntityDeltaComparator();
 
-    private static final int ICON_SIZE = 96;
-
     private static final File PHOTO_DIR = new File(
             Environment.getExternalStorageDirectory() + "/DCIM/Camera");
 
@@ -216,6 +215,9 @@
 
     private File mCurrentPhotoFile;
 
+    // Height/width (in pixels) to request for the photo - queried from the provider.
+    private int mPhotoPickSize;
+
     private Context mContext;
     private String mAction;
     private Uri mLookupUri;
@@ -265,6 +267,7 @@
     public void onAttach(Activity activity) {
         super.onAttach(activity);
         mContext = activity;
+        loadPhotoPickSize();
     }
 
     @Override
@@ -774,17 +777,28 @@
         return save(SaveMode.JOIN);
     }
 
+    private void loadPhotoPickSize() {
+        Cursor c = mContext.getContentResolver().query(DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
+                new String[]{DisplayPhoto.DISPLAY_MAX_DIM}, null, null, null);
+        try {
+            c.moveToFirst();
+            mPhotoPickSize = c.getInt(0);
+        } finally {
+            c.close();
+        }
+    }
+
     /**
      * Constructs an intent for picking a photo from Gallery, cropping it and returning the bitmap.
      */
-    public static Intent getPhotoPickIntent() {
+    public Intent getPhotoPickIntent() {
         Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
         intent.setType("image/*");
         intent.putExtra("crop", "true");
         intent.putExtra("aspectX", 1);
         intent.putExtra("aspectY", 1);
-        intent.putExtra("outputX", ICON_SIZE);
-        intent.putExtra("outputY", ICON_SIZE);
+        intent.putExtra("outputX", mPhotoPickSize);
+        intent.putExtra("outputY", mPhotoPickSize);
         intent.putExtra("return-data", true);
         return intent;
     }
@@ -840,14 +854,14 @@
     /**
      * Constructs an intent for image cropping.
      */
-    public static Intent getCropImageIntent(Uri photoUri) {
+    public Intent getCropImageIntent(Uri photoUri) {
         Intent intent = new Intent("com.android.camera.action.CROP");
         intent.setDataAndType(photoUri, "image/*");
         intent.putExtra("crop", "true");
         intent.putExtra("aspectX", 1);
         intent.putExtra("aspectY", 1);
-        intent.putExtra("outputX", ICON_SIZE);
-        intent.putExtra("outputY", ICON_SIZE);
+        intent.putExtra("outputX", mPhotoPickSize);
+        intent.putExtra("outputY", mPhotoPickSize);
         intent.putExtra("return-data", true);
         return intent;
     }