Only kill image requests from the one fragment

In ContractEntryListAdapter#changeCursor(), don't kill all image loading
requests app wide. Instead, only kill the image loading requests that
were associated with the adapter's fragment.

Bug: 15522504
Change-Id: Ib4e0448217e8bbb8df55e74649a013e0f1688a22
diff --git a/src/com/android/contacts/common/ContactPhotoManager.java b/src/com/android/contacts/common/ContactPhotoManager.java
index 213a7a2..24b96e2 100644
--- a/src/com/android/contacts/common/ContactPhotoManager.java
+++ b/src/com/android/contacts/common/ContactPhotoManager.java
@@ -49,6 +49,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.LruCache;
+import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ImageView;
 
 import com.android.contacts.common.lettertiles.LetterTileDrawable;
@@ -513,7 +515,7 @@
     /**
      * Cancels all pending requests to load photos asynchronously.
      */
-    public abstract void cancelPendingRequests();
+    public abstract void cancelPendingRequests(View fragmentRootView);
 
     /**
      * Temporarily stops loading photos from the database.
@@ -843,11 +845,30 @@
 
 
     /**
-     * Cancels all pending requests to load photos asynchronously.
+     * Cancels pending requests to load photos asynchronously for views inside
+     * {@param fragmentRootView}. If {@param fragmentRootView} is null, cancels all requests.
      */
     @Override
-    public void cancelPendingRequests() {
-        mPendingRequests.clear();
+    public void cancelPendingRequests(View fragmentRootView) {
+        if (fragmentRootView == null) {
+            mPendingRequests.clear();
+            return;
+        }
+        ImageView[] requestSetCopy = mPendingRequests.keySet().toArray(new ImageView[
+                mPendingRequests.size()]);
+        for (ImageView imageView : requestSetCopy) {
+            // If an ImageView is orphaned (currently scrap) or a child of fragmentRootView, then
+            // we can safely remove its request.
+            if (imageView.getParent() == null || isChildView(fragmentRootView, imageView)) {
+                mPendingRequests.remove(imageView);
+            }
+        }
+    }
+
+    private static boolean isChildView(View parent, View potentialChild) {
+        return potentialChild.getParent() != null && (potentialChild.getParent() == parent || (
+                potentialChild.getParent() instanceof ViewGroup && isChildView(parent,
+                        (ViewGroup) potentialChild.getParent())));
     }
 
     @Override
diff --git a/src/com/android/contacts/common/list/ContactEntryListAdapter.java b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
index fc8f0d4..83a8c39 100644
--- a/src/com/android/contacts/common/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
@@ -72,6 +72,11 @@
      */
     private boolean mProfileExists;
 
+    /**
+     * The root view of the fragment that this adapter is associated with.
+     */
+    private View mFragmentRootView;
+
     private ContactPhotoManager mPhotoLoader;
 
     private String mQueryString;
@@ -96,6 +101,14 @@
         addPartitions();
     }
 
+    /**
+     * @param fragmentRootView Root view of the fragment. This is used to restrict the scope of
+     * image loading requests that get cancelled on cursor changes.
+     */
+    protected void setFragmentRootView(View fragmentRootView) {
+        mFragmentRootView = fragmentRootView;
+    }
+
     protected void setDefaultFilterHeaderText(int resourceId) {
         mDefaultFilterHeaderText = getContext().getResources().getText(resourceId);
     }
@@ -447,7 +460,7 @@
         }
 
         // When the cursor changes, cancel any pending asynchronous photo loads.
-        mPhotoLoader.cancelPendingRequests();
+        mPhotoLoader.cancelPendingRequests(mFragmentRootView);
     }
 
     public void changeCursor(Cursor cursor) {
diff --git a/src/com/android/contacts/common/list/ContactEntryListFragment.java b/src/com/android/contacts/common/list/ContactEntryListFragment.java
index 29cacd8..b1f93c6 100644
--- a/src/com/android/contacts/common/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/common/list/ContactEntryListFragment.java
@@ -737,6 +737,8 @@
 
         configureVerticalScrollbar();
         configurePhotoLoader();
+
+        getAdapter().setFragmentRootView(getView());
     }
 
     protected void configurePhotoLoader() {