Merge "Fix call-log auto-scroll-to-top behavior."
diff --git a/src/com/android/contacts/ContactLoader.java b/src/com/android/contacts/ContactLoader.java
index 195eb78..685bd7d 100644
--- a/src/com/android/contacts/ContactLoader.java
+++ b/src/com/android/contacts/ContactLoader.java
@@ -56,14 +56,13 @@
 import android.provider.ContactsContract.StreamItems;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.LongSparseArray;
 
 import java.io.ByteArrayOutputStream;
 import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -120,7 +119,7 @@
         private final Integer mPresence;
         private final ArrayList<Entity> mEntities;
         private final ArrayList<StreamItemEntry> mStreamItems;
-        private final HashMap<Long, DataStatus> mStatuses;
+        private final LongSparseArray<DataStatus> mStatuses;
         private final ArrayList<AccountType> mInvitableAccountTypes;
 
         private String mDirectoryDisplayName;
@@ -131,7 +130,6 @@
 
         private ArrayList<GroupMetaData> mGroups;
 
-        private boolean mLoadingPhoto;
         private byte[] mPhotoBinaryData;
         private final boolean mSendToVoicemail;
         private final String mCustomRingtone;
@@ -199,7 +197,7 @@
             mId = id;
             mEntities = new ArrayList<Entity>();
             mStreamItems = new ArrayList<StreamItemEntry>();
-            mStatuses = new HashMap<Long, DataStatus>();
+            mStatuses = new LongSparseArray<DataStatus>();
             mNameRawContactId = nameRawContactId;
             mDisplayNameSource = displayNameSource;
             mPhotoId = photoId;
@@ -246,7 +244,6 @@
 
             mGroups = from.mGroups;
 
-            mLoadingPhoto = from.mLoadingPhoto;
             mPhotoBinaryData = from.mPhotoBinaryData;
             mSendToVoicemail = from.mSendToVoicemail;
             mCustomRingtone = from.mCustomRingtone;
@@ -265,10 +262,6 @@
             mDirectoryExportSupport = exportSupport;
         }
 
-        private void setLoadingPhoto(boolean flag) {
-            mLoadingPhoto = flag;
-        }
-
         private void setPhotoBinaryData(byte[] photoBinaryData) {
             mPhotoBinaryData = photoBinaryData;
         }
@@ -392,7 +385,7 @@
             return mStreamItems;
         }
 
-        public HashMap<Long, DataStatus> getStatuses() {
+        public LongSparseArray<DataStatus> getStatuses() {
             return mStatuses;
         }
 
@@ -425,10 +418,6 @@
             return mDirectoryAccountName;
         }
 
-        public boolean isLoadingPhoto() {
-            return mLoadingPhoto;
-        }
-
         public byte[] getPhotoBinaryData() {
             return mPhotoBinaryData;
         }
@@ -732,7 +721,7 @@
                 Entity entity = null;
                 Result result = loadContactHeaderData(cursor, contactUri);
                 ArrayList<Entity> entities = result.getEntities();
-                HashMap<Long, DataStatus> statuses = result.getStatuses();
+                LongSparseArray<DataStatus> statuses = result.getStatuses();
                 for (; !cursor.isAfterLast(); cursor.moveToNext()) {
                     long rawContactId = cursor.getLong(ContactQuery.RAW_CONTACT_ID);
                     if (rawContactId != currentRawContactId) {
@@ -824,7 +813,7 @@
                 return;
             }
 
-            HashMap<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap(invitables);
+            Map<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap(invitables);
 
             // Remove the ones that already have a raw contact in the current contact
             for (Entity entity : contactData.getEntities()) {
@@ -1066,7 +1055,8 @@
                             .appendPath(result.getLookupKey())
                             .appendPath(Contacts.StreamItems.CONTENT_DIRECTORY).build(),
                     null, null, null, null);
-            Map<Long, StreamItemEntry> streamItemsById = new HashMap<Long, StreamItemEntry>();
+            LongSparseArray<StreamItemEntry> streamItemsById =
+                    new LongSparseArray<StreamItemEntry>();
             ArrayList<StreamItemEntry> streamItems = new ArrayList<StreamItemEntry>();
             try {
                 while (cursor.moveToNext()) {
@@ -1166,11 +1156,6 @@
                             mLookupUri, true, mObserver);
                 }
 
-                if (mContact.getPhotoBinaryData() == null && mContact.getPhotoUri() != null) {
-                    mContact.setLoadingPhoto(true);
-                    new AsyncPhotoLoader().execute(mContact.getPhotoUri());
-                }
-
                 // inform the source of the data that this contact is being looked at
                 postViewNotificationToSyncAdapter();
             }
@@ -1213,50 +1198,6 @@
         }
     }
 
-    private class AsyncPhotoLoader extends AsyncTask<String, Void, byte[]> {
-
-        private static final int BUFFER_SIZE = 1024*16;
-
-        @Override
-        protected byte[] doInBackground(String... params) {
-            Uri uri = Uri.parse(params[0]);
-            byte[] data = 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);
-                        }
-                        data = baos.toByteArray();
-                    } finally {
-                        is.close();
-                    }
-                } else {
-                    Log.v(TAG, "Cannot load photo " + uri);
-                }
-            } catch (IOException e) {
-                Log.e(TAG, "Cannot load photo " + uri, e);
-            }
-
-            return data;
-        }
-
-        @Override
-        protected void onPostExecute(byte[] data) {
-            if (mContact != null) {
-                mContact = new Result(mContact);
-                mContact.setPhotoBinaryData(data);
-                mContact.setLoadingPhoto(false);
-                deliverResult(mContact);
-            }
-        }
-    }
-
     private void unregisterObserver() {
         if (mObserver != null) {
             getContext().getContentResolver().unregisterContentObserver(mObserver);
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index f475609..6de361d 100644
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -727,7 +727,7 @@
         deliverCallback(callbackIntent);
     }
 
-    private void addMembersToGroup(ContentResolver resolver, long[] rawContactsToAdd,
+    private static void addMembersToGroup(ContentResolver resolver, long[] rawContactsToAdd,
             long groupId) {
         if (rawContactsToAdd == null) {
             return;
@@ -762,9 +762,8 @@
                 }
 
                 // Apply batch
-                ContentProviderResult[] results = null;
                 if (!rawContactOperations.isEmpty()) {
-                    results = resolver.applyBatch(ContactsContract.AUTHORITY, rawContactOperations);
+                    resolver.applyBatch(ContactsContract.AUTHORITY, rawContactOperations);
                 }
             } catch (RemoteException e) {
                 // Something went wrong, bail without success
@@ -780,7 +779,7 @@
         }
     }
 
-    private void removeMembersFromGroup(ContentResolver resolver, long[] rawContactsToRemove,
+    private static void removeMembersFromGroup(ContentResolver resolver, long[] rawContactsToRemove,
             long groupId) {
         if (rawContactsToRemove == null) {
             return;
@@ -789,7 +788,7 @@
             // Apply the delete operation on the data row for the given raw contact's
             // membership in the given group. If no contact matches the provided selection, then
             // nothing will be done. Just continue to the next contact.
-            getContentResolver().delete(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=? AND " +
+            resolver.delete(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=? AND " +
                     Data.MIMETYPE + "=? AND " + GroupMembership.GROUP_ROW_ID + "=?",
                     new String[] { String.valueOf(rawContactId),
                     GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(groupId)});
diff --git a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
index eabd9ec..9f37899 100644
--- a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
+++ b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
@@ -61,7 +61,6 @@
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.AlphaAnimation;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.TextView;
 
@@ -208,10 +207,6 @@
      */
     public static OnClickListener setPhoto(Context context, Result contactData,
             ImageView photoView, boolean expandPhotoOnClick) {
-        if (contactData.isLoadingPhoto()) {
-            photoView.setImageBitmap(null);
-            return null;
-        }
         byte[] photo = contactData.getPhotoBinaryData();
         Bitmap bitmap = photo != null ? BitmapFactory.decodeByteArray(photo, 0, photo.length)
                 : ContactBadgeUtil.loadDefaultAvatarPhoto(context, true, false);
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index d8e5a1d..33e2ab4 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -42,7 +42,6 @@
 import com.android.contacts.util.DateUtils;
 import com.android.contacts.util.PhoneCapabilityTester;
 import com.android.contacts.util.StructuredPostalUtils;
-import com.android.contacts.widget.TransitionAnimationView;
 import com.android.internal.telephony.ITelephony;
 import com.google.common.annotations.VisibleForTesting;
 
diff --git a/src/com/android/contacts/group/SuggestedMemberListAdapter.java b/src/com/android/contacts/group/SuggestedMemberListAdapter.java
index 08401bf..30718de 100644
--- a/src/com/android/contacts/group/SuggestedMemberListAdapter.java
+++ b/src/com/android/contacts/group/SuggestedMemberListAdapter.java
@@ -295,6 +295,7 @@
 
         @Override
         protected void publishResults(CharSequence constraint, FilterResults results) {
+            @SuppressWarnings("unchecked")
             List<SuggestedMember> suggestionsList = (List<SuggestedMember>) results.values;
             if (suggestionsList == null) {
                 return;