Make sure we don't override existing requests for the DivisionCanvasView.

Since each view could hold up to 4, this had been replacing earlier requests
with later requests for images that were intended for other positions
in the DivisionCanvasView.

Change-Id: Ica8e9d101cea0041281a155ca7ec979807559aa5
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 1284135..ad005c3 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -446,7 +446,11 @@
         mSwipeEnabled = swipeEnabled;
         mPriorityMarkersEnabled = priorityArrowEnabled;
         mAdapter = adapter;
-        sContactPhotoManager.removePhoto(mContactImagesHolder);
+        final int count = mContactImagesHolder.getDivisionCount();
+        for (int pos = 0; pos < count; pos++) {
+            sContactPhotoManager.removePhoto(DividedImageCanvas.generateHash(mContactImagesHolder,
+                    pos));
+        }
         setContentDescription();
         requestLayout();
     }
@@ -642,8 +646,9 @@
             mContactImagesHolder.setDivisionIds(mHeader.displayableSenderEmails);
             int size = mHeader.displayableSenderEmails.size();
             for (int i = 0; i < DividedImageCanvas.MAX_DIVISIONS && i < size; i++) {
-                sContactPhotoManager.loadThumbnail(mContactImagesHolder,
-                        mHeader.displayableSenderNames.get(i),
+                sContactPhotoManager.loadThumbnail(
+                        DividedImageCanvas.generateHash(mContactImagesHolder, i),
+                        mContactImagesHolder, mHeader.displayableSenderNames.get(i),
                         mHeader.displayableSenderEmails.get(i), DEFAULT_AVATAR_PROVIDER);
             }
         }
@@ -753,22 +758,40 @@
 
         mPaperclipX = mDateX - ATTACHMENT.getWidth();
 
-        mFoldersXEnd = mCoordinates.foldersXEnd;
+        int cellWidth = mContext.getResources().getDimensionPixelSize(R.dimen.folder_cell_width);
+
         if (ConversationItemViewCoordinates.isWideMode(mMode)) {
+            // Folders are displayed above the date.
+            mFoldersXEnd = mCoordinates.foldersXEnd;
             // In wide mode, the end of the senders should align with
             // the start of the subject and is based on a max width.
             mSendersWidth = mCoordinates.sendersWidth;
         } else {
             // In normal mode, the width is based on where the folders or date
             // (or attachment icon) start.
-            int dateAttachmentStart = 0;
-            // Have this end near the paperclip or date, not the folders.
-            if (mHeader.paperclip != null) {
-                dateAttachmentStart = mPaperclipX;
+            mFoldersXEnd = mCoordinates.foldersXEnd;
+            if (mCoordinates.showFolders) {
+                final int sendersEnd;
+                if (mHeader.paperclip != null) {
+                    sendersEnd = mPaperclipX;
+                } else {
+                    sendersEnd = mDateX - cellWidth / 2;
+                }
+                mSendersWidth = sendersEnd - mCoordinates.sendersX - 2 * cellWidth;
+                if (mHeader.folderDisplayer.hasVisibleFolders()) {
+                    mSendersWidth -= ConversationItemViewCoordinates.getFoldersWidth(mContext,
+                            mMode);
+                }
             } else {
-                dateAttachmentStart = mDateX;
+                int dateAttachmentStart = 0;
+                // Have this end near the paperclip or date, not the folders.
+                if (mHeader.paperclip != null) {
+                    dateAttachmentStart = mPaperclipX;
+                } else {
+                    dateAttachmentStart = mDateX;
+                }
+                mSendersWidth = dateAttachmentStart - mCoordinates.sendersX - cellWidth;
             }
-            mSendersWidth = dateAttachmentStart - mCoordinates.sendersX ;
         }
 
         // Second pass to layout each fragment.
diff --git a/src/com/android/mail/photomanager/ContactPhotoManager.java b/src/com/android/mail/photomanager/ContactPhotoManager.java
index 2733023..71c9a92 100644
--- a/src/com/android/mail/photomanager/ContactPhotoManager.java
+++ b/src/com/android/mail/photomanager/ContactPhotoManager.java
@@ -100,21 +100,23 @@
     }
 
     /**
-     * Calls {@link #loadThumbnail(DividedImageCanvas, long, boolean, DefaultImageProvider)} with
-     * {@link #DEFAULT_AVATAR}.
+     * Calls
+     * {@link #loadThumbnail(long, DividedImageCanvas, long, boolean, DefaultImageProvider)}
+     * with {@link #DEFAULT_AVATAR}.
      */
-    public final void loadThumbnail(DividedImageCanvas view, String name, String emailAddress) {
-        loadThumbnail(view, name, emailAddress, DEFAULT_AVATAR);
+    public final void loadThumbnail(Long hashCode, DividedImageCanvas view, String name,
+            String emailAddress) {
+        loadThumbnail(hashCode, view, name, emailAddress, DEFAULT_AVATAR);
     }
 
-    public abstract void loadThumbnail(DividedImageCanvas view, String name, String emailAddress,
-            DefaultImageProvider defaultProvider);
+    public abstract void loadThumbnail(Long hashCode, DividedImageCanvas view, String name,
+            String emailAddress, DefaultImageProvider defaultProvider);
 
     /**
      * Remove photo from the supplied image view. This also cancels current pending load request
      * inside this photo manager.
      */
-    public abstract void removePhoto(DividedImageCanvas view);
+    public abstract void removePhoto(Long hash);
 
     /**
      * Temporarily stops loading photos from the database.
@@ -222,8 +224,8 @@
      * A map from DividedImageView to the corresponding photo ID or uri, encapsulated in a request.
      * The request may swapped out before the photo loading request is started.
      */
-    private final ConcurrentHashMap<DividedImageCanvas, Request> mPendingRequests =
-            new ConcurrentHashMap<DividedImageCanvas, Request>();
+    private final ConcurrentHashMap<Long, Request> mPendingRequests =
+            new ConcurrentHashMap<Long, Request>();
 
     /**
      * Handler for messages sent to the UI thread.
@@ -359,26 +361,26 @@
     }
 
     @Override
-    public void loadThumbnail(DividedImageCanvas view, String name, String emailAddress,
-            DefaultImageProvider defaultProvider) {
+    public void loadThumbnail(Long hashCode, DividedImageCanvas view, String name,
+            String emailAddress, DefaultImageProvider defaultProvider) {
         if (TextUtils.isEmpty(emailAddress)) {
             // No photo is needed
             defaultProvider.applyDefaultImage(name, emailAddress, view, -1);
-            mPendingRequests.remove(view);
+            mPendingRequests.remove(hashCode);
         } else {
             if (DEBUG)
                 LogUtils.d(TAG, "loadPhoto request: " + name);
-            loadPhotoByIdOrUri(view,
-                    Request.createFromEmailAddress(name, emailAddress, defaultProvider));
+            loadPhotoByIdOrUri(hashCode, view,
+                    Request.createFromEmailAddress(name, emailAddress, defaultProvider, view));
         }
     }
 
-    private void loadPhotoByIdOrUri(DividedImageCanvas view, Request request) {
+    private void loadPhotoByIdOrUri(Long hashCode, DividedImageCanvas view, Request request) {
         boolean loaded = loadCachedPhoto(view, request, false);
         if (loaded) {
-            mPendingRequests.remove(view);
+            mPendingRequests.remove(hashCode);
         } else {
-            mPendingRequests.put(view, request);
+            mPendingRequests.put(hashCode, request);
             if (!mPaused) {
                 // Send a request to start loading photos
                 requestLoading();
@@ -387,9 +389,12 @@
     }
 
     @Override
-    public void removePhoto(DividedImageCanvas view) {
-        view.reset();
-        mPendingRequests.remove(view);
+    public void removePhoto(Long hash) {
+        Request r = mPendingRequests.get(hash);
+        if (r != null) {
+            r.getView().reset();
+            mPendingRequests.remove(hash);
+        }
     }
 
     @Override
@@ -507,11 +512,11 @@
      * photos still haven't been loaded, sends another request for image loading.
      */
     private void processLoadedImages() {
-        Iterator<DividedImageCanvas> iterator = mPendingRequests.keySet().iterator();
+        Iterator<Long> iterator = mPendingRequests.keySet().iterator();
         while (iterator.hasNext()) {
-            DividedImageCanvas view = iterator.next();
-            Request key = mPendingRequests.get(view);
-            boolean loaded = loadCachedPhoto(view, key, true);
+            Long hash = iterator.next();
+            Request key = mPendingRequests.get(hash);
+            boolean loaded = loadCachedPhoto(key.getView(), key, true);
             if (loaded) {
                 iterator.remove();
             }
@@ -915,7 +920,7 @@
                             // In case there are multiple contacts for this
                             // contact, try to always pick the one that actually
                             // has a photo.
-                            if (id != 0) {
+                            if (!photoIdsCursor.isNull(DATA_PHOTO_ID_COLUMN)) {
                                 contactAddress = photoIdsCursor.getString(DATA_EMAIL_COLUMN);
                                 photoIds.add(id);
                                 photoIdsAsString.add(id + "");
@@ -997,13 +1002,19 @@
         private final DefaultImageProvider mDefaultProvider;
         private final String mDisplayName;
         private final String mEmailAddress;
+        private final DividedImageCanvas mView;
 
         private Request(String name, String emailAddress, int requestedExtent,
-                DefaultImageProvider defaultProvider) {
+                DefaultImageProvider defaultProvider, DividedImageCanvas view) {
             mRequestedExtent = requestedExtent;
             mDefaultProvider = defaultProvider;
             mDisplayName = name;
             mEmailAddress = emailAddress;
+            mView = view;
+        }
+
+        public DividedImageCanvas getView() {
+            return mView;
         }
 
         public String getDisplayName() {
@@ -1015,8 +1026,8 @@
         }
 
         public static Request createFromEmailAddress(String displayName, String emailAddress,
-                DefaultImageProvider defaultProvider) {
-            return new Request(displayName, emailAddress, -1, defaultProvider);
+                DefaultImageProvider defaultProvider, DividedImageCanvas view) {
+            return new Request(displayName, emailAddress, -1, defaultProvider, view);
         }
 
         @Override
@@ -1026,6 +1037,7 @@
             result = prime * result + mRequestedExtent;
             result = prime * result + ((mDisplayName == null) ? 0 : mDisplayName.hashCode());
             result = prime * result + ((mEmailAddress == null) ? 0 : mEmailAddress.hashCode());
+            result = prime * result + ((mView == null) ? 0 : mView.hashCode());
             return result;
         }
 
diff --git a/src/com/android/mail/ui/DividedImageCanvas.java b/src/com/android/mail/ui/DividedImageCanvas.java
index 5a826f3..7da9a5a 100644
--- a/src/com/android/mail/ui/DividedImageCanvas.java
+++ b/src/com/android/mail/ui/DividedImageCanvas.java
@@ -24,6 +24,7 @@
 import android.graphics.Rect;
 
 import com.android.mail.photomanager.BitmapUtil;
+import com.google.common.base.Objects;
 
 import java.util.ArrayList;
 
@@ -337,4 +338,19 @@
             scale = s;
         }
     }
+
+    /**
+     * Get the number of divisions currently associated with this DivisionImageCanvas.
+     */
+    public int getDivisionCount() {
+        return mDivisionIds != null ? 0 : mDivisionIds.size();
+    }
+
+    /**
+     * Generate a unique hashcode to use for the request for an image to put in
+     * the specified position of the DividedImageCanvas.
+     */
+    public static long generateHash(DividedImageCanvas contactImagesHolder, int i) {
+        return Objects.hashCode(contactImagesHolder, i);
+    }
 }