Merge "Add missing assets to make HC run on the phone again"
diff --git a/src/com/android/contacts/util/ContactBadgeUtil.java b/src/com/android/contacts/util/ContactBadgeUtil.java
index baff615..d779701 100644
--- a/src/com/android/contacts/util/ContactBadgeUtil.java
+++ b/src/com/android/contacts/util/ContactBadgeUtil.java
@@ -48,14 +48,17 @@
      */
     public static Bitmap getPhoto(ContactLoader.Result contactData) {
         final long photoId = contactData.getPhotoId();
+        if (photoId <= 0) {
+            // No photo ID
+            return null;
+        }
 
         for (Entity entity : contactData.getEntities()) {
             for (NamedContentValues subValue : entity.getSubValues()) {
                 final ContentValues entryValues = subValue.values;
                 final long dataId = entryValues.getAsLong(Data._ID);
-                final String mimeType = entryValues.getAsString(Data.MIMETYPE);
-
                 if (dataId == photoId) {
+                    final String mimeType = entryValues.getAsString(Data.MIMETYPE);
                     // Correct Data Id but incorrect MimeType? Don't load
                     if (!Photo.CONTENT_ITEM_TYPE.equals(mimeType)) return null;
                     final byte[] binaryData = entryValues.getAsByteArray(Photo.PHOTO);
@@ -69,16 +72,7 @@
     }
 
     /**
-     * Returns the social snippet, including the date
-     * @param status             The status of the contact. If this is either null or empty,
-     *                            no social snippet is shown
-     * @param statusTimestamp    The timestamp (retrieved via a call to
-     *                            {@link System#currentTimeMillis()}) of the last status update.
-     *                            This value can be null if it is not known.
-     * @param statusLabel        The id of a resource string that specifies the current
-     *                            status. This value can be null if no Label should be used.
-     * @param statusResPackage   The name of the resource package containing the resource string
-     *                            referenced in the parameter statusLabel.
+     * Returns the social snippet attribution, including the date
      */
     public static CharSequence getSocialDate(ContactLoader.Result contactData,
             Context context) {
diff --git a/src/com/android/contacts/views/ContactLoader.java b/src/com/android/contacts/views/ContactLoader.java
index 0764ecf..d272f59 100644
--- a/src/com/android/contacts/views/ContactLoader.java
+++ b/src/com/android/contacts/views/ContactLoader.java
@@ -87,6 +87,7 @@
         private final long mNameRawContactId;
         private final int mDisplayNameSource;
         private final long mPhotoId;
+        private final String mPhotoUri;
         private final String mDisplayName;
         private final String mPhoneticName;
         private final boolean mStarred;
@@ -121,6 +122,7 @@
             mNameRawContactId = -1;
             mDisplayNameSource = DisplayNameSources.UNDEFINED;
             mPhotoId = -1;
+            mPhotoUri = null;
             mDisplayName = null;
             mPhoneticName = null;
             mStarred = false;
@@ -133,11 +135,12 @@
 
         /**
          * Constructor to call when contact was found
+         * @param photoUri TODO
          */
         private Result(Uri uri, Uri lookupUri, long directoryId, String lookupKey, long id,
-                long nameRawContactId, int displayNameSource, long photoId, String displayName,
-                String phoneticName, boolean starred, Integer presence, String status,
-                Long statusTimestamp, Integer statusLabel, String statusResPackage) {
+                long nameRawContactId, int displayNameSource, long photoId, String photoUri,
+                String displayName, String phoneticName, boolean starred, Integer presence,
+                String status, Long statusTimestamp, Integer statusLabel, String statusResPackage) {
             mLookupUri = lookupUri;
             mUri = uri;
             mDirectoryId = directoryId;
@@ -148,6 +151,7 @@
             mNameRawContactId = nameRawContactId;
             mDisplayNameSource = displayNameSource;
             mPhotoId = photoId;
+            mPhotoUri = photoUri;
             mDisplayName = displayName;
             mPhoneticName = phoneticName;
             mStarred = starred;
@@ -191,6 +195,9 @@
         public long getPhotoId() {
             return mPhotoId;
         }
+        public String getPhotoUri() {
+            return mPhotoUri;
+        }
         public String getDisplayName() {
             return mDisplayName;
         }
@@ -349,7 +356,9 @@
                 Data.STATUS_RES_PACKAGE,
                 Data.STATUS_ICON,
                 Data.STATUS_LABEL,
-                Data.STATUS_TIMESTAMP
+                Data.STATUS_TIMESTAMP,
+
+                Contacts.PHOTO_URI,
         };
 
         public final static int NAME_RAW_CONTACT_ID = 0;
@@ -411,6 +420,12 @@
         public final static int PRESENCE = 52;
         public final static int CHAT_CAPABILITY = 53;
         public final static int STATUS = 54;
+        public final static int STATUS_RES_PACKAGE = 55;
+        public final static int STATUS_ICON = 56;
+        public final static int STATUS_LABEL = 57;
+        public final static int STATUS_TIMESTAMP = 58;
+
+        public final static int PHOTO_URI = 59;
     }
 
     private static class DirectoryQuery {
@@ -575,6 +590,7 @@
             final String displayName = cursor.getString(ContactQuery.DISPLAY_NAME);
             final String phoneticName = cursor.getString(ContactQuery.PHONETIC_NAME);
             final long photoId = cursor.getLong(ContactQuery.PHOTO_ID);
+            final String photoUri = cursor.getString(ContactQuery.PHOTO_URI);
             final boolean starred = cursor.getInt(ContactQuery.STARRED) != 0;
             final Integer presence = cursor.isNull(ContactQuery.CONTACT_PRESENCE)
                     ? null
@@ -592,8 +608,9 @@
             Uri lookupUri = ContentUris.withAppendedId(
                     Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), contactId);
             return new Result(contactUri, lookupUri, directoryId, lookupKey, contactId,
-                    nameRawContactId, displayNameSource, photoId, displayName, phoneticName,
-                    starred, presence, status, statusTimestamp, statusLabel, statusResPackage);
+                    nameRawContactId, displayNameSource, photoId, photoUri, displayName,
+                    phoneticName, starred, presence, status, statusTimestamp, statusLabel,
+                    statusResPackage);
         }
 
         /**
@@ -770,8 +787,8 @@
             }
 
             mContact = result;
-            mLookupUri = result.getLookupUri();
             if (result != null) {
+                mLookupUri = result.getLookupUri();
                 unregisterObserver();
                 if (mObserver == null) {
                     mObserver = new ForceLoadContentObserver();
diff --git a/src/com/android/contacts/views/detail/ContactDetailHeaderView.java b/src/com/android/contacts/views/detail/ContactDetailHeaderView.java
index 5f43f02..7d1e9ec 100644
--- a/src/com/android/contacts/views/detail/ContactDetailHeaderView.java
+++ b/src/com/android/contacts/views/detail/ContactDetailHeaderView.java
@@ -26,7 +26,9 @@
 import android.content.Entity;
 import android.content.Entity.NamedContentValues;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.provider.ContactsContract.CommonDataKinds.Organization;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
@@ -34,6 +36,7 @@
 import android.provider.ContactsContract.StatusUpdates;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.CheckBox;
@@ -41,6 +44,10 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
 /**
  * Header for displaying a title bar with contact info. You
  * can bind specific values by calling
@@ -114,7 +121,15 @@
 
         setDisplayName(contactData.getDisplayName(), contactData.getPhoneticName());
         setCompany(contactData);
-        setPhoto(ContactBadgeUtil.getPhoto(contactData));
+        Bitmap photo = ContactBadgeUtil.getPhoto(contactData);
+        if (photo != null) {
+            setPhoto(photo);
+        } else if (contactData.getPhotoUri() != null) {
+            setPhoto(null);
+            new AsyncPhotoLoader().execute(contactData.getPhotoUri());
+        } else {
+            setPhoto(ContactBadgeUtil.loadPlaceholderPhoto(mContext));
+        }
         setStared(contactData.getStarred());
         setPresence(contactData.getPresence());
         setSocialSnippet(contactData.getSocialSnippet());
@@ -307,4 +322,44 @@
             }
         }
     }
+
+    private class AsyncPhotoLoader extends AsyncTask<String, Void, Bitmap> {
+
+        private static final int BUFFER_SIZE = 1024*16;
+
+        @Override
+        protected Bitmap doInBackground(String... params) {
+            Uri uri = Uri.parse(params[0]);
+            Bitmap bitmap = null;
+            try {
+                InputStream is = getContext().getContentResolver().openInputStream(uri);
+                if (is != null) {
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    try {
+                        byte[] mBuffer = new byte[BUFFER_SIZE];
+
+                        int size;
+                        while ((size = is.read(mBuffer)) != -1) {
+                            baos.write(mBuffer, 0, size);
+                        }
+                        byte[] bytes = baos.toByteArray();
+                        bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
+                    } finally {
+                        is.close();
+                    }
+                } else {
+                    Log.v(TAG, "Cannot load photo " + uri);
+                }
+            } catch (IOException e) {
+                Log.e(TAG, "Cannot load photo " + uri, e);
+            }
+
+            return bitmap;
+        }
+
+        @Override
+        protected void onPostExecute(Bitmap bitmap) {
+            setPhoto(bitmap);
+        }
+    }
 }