1d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod/**
2d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod * Copyright (C) 2013 The Android Open Source Project
3d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod *
4d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod * Licensed under the Apache License, Version 2.0 (the "License");
5d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod * you may not use this file except in compliance with the License.
6d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod * You may obtain a copy of the License at
7d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod *
8d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod *      http://www.apache.org/licenses/LICENSE-2.0
9d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod *
10d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod * Unless required by applicable law or agreed to in writing, software
11d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod * distributed under the License is distributed on an "AS IS" BASIS,
12d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod * See the License for the specific language governing permissions and
14d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod * limitations under the License.
15d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod */
16d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbodpackage com.android.volley.toolbox;
17d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
18d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbodimport android.content.Context;
19d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbodimport android.text.TextUtils;
20d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbodimport android.util.AttributeSet;
21c3dce982fb05a7674d360255a9831adf83475099Vladimir Baryshnikovimport android.view.ViewGroup.LayoutParams;
22d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbodimport android.widget.ImageView;
23d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
24b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbodimport com.android.volley.VolleyError;
25d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbodimport com.android.volley.toolbox.ImageLoader.ImageContainer;
26b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbodimport com.android.volley.toolbox.ImageLoader.ImageListener;
27d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
28d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod/**
29d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod * Handles fetching an image from a URL as well as the life-cycle of the
30d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod * associated request.
31d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod */
32d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbodpublic class NetworkImageView extends ImageView {
33d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    /** The URL of the network image to load */
34d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    private String mUrl;
35d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
36d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    /**
37d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * Resource ID of the image to be used as a placeholder until the network image is loaded.
38d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     */
39d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    private int mDefaultImageId;
40d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
41d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    /**
42d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * Resource ID of the image to be used if the network response fails.
43d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     */
44d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    private int mErrorImageId;
45d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
46d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    /** Local copy of the ImageLoader. */
47d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    private ImageLoader mImageLoader;
48d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
49da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton    /** Current ImageContainer. (either in-flight or finished) */
50da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton    private ImageContainer mImageContainer;
51da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton
52d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    public NetworkImageView(Context context) {
53d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        this(context, null);
54d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    }
55d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
56d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    public NetworkImageView(Context context, AttributeSet attrs) {
57d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        this(context, attrs, 0);
58d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    }
59d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
60d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    public NetworkImageView(Context context, AttributeSet attrs, int defStyle) {
61d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        super(context, attrs, defStyle);
62d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    }
63d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
64d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    /**
65d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * Sets URL of the image that should be loaded into this view. Note that calling this will
66d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * immediately either set the cached image (if available) or the default image specified by
67d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * {@link NetworkImageView#setDefaultImageResId(int)} on the view.
68d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     *
69d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * NOTE: If applicable, {@link NetworkImageView#setDefaultImageResId(int)} and
70d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * {@link NetworkImageView#setErrorImageResId(int)} should be called prior to calling
71d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * this function.
72d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     *
73d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * @param url The URL that should be loaded into this ImageView.
74d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * @param imageLoader ImageLoader that will be used to make the request.
75d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     */
76d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    public void setImageUrl(String url, ImageLoader imageLoader) {
77d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        mUrl = url;
78d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        mImageLoader = imageLoader;
79d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        // The URL has potentially changed. See if we need to load it.
80b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod        loadImageIfNecessary(false);
81d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    }
82d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
83d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    /**
84d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * Sets the default image resource ID to be used for this view until the attempt to load it
85d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * completes.
86d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     */
87d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    public void setDefaultImageResId(int defaultImage) {
88d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        mDefaultImageId = defaultImage;
89d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    }
90d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
91d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    /**
92d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * Sets the error image resource ID to be used for this view in the event that the image
93d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * requested fails to load.
94d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     */
95d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    public void setErrorImageResId(int errorImage) {
96d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        mErrorImageId = errorImage;
97d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    }
98d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
99d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    /**
100d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     * Loads the image for the view if it isn't already loaded.
101b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod     * @param isInLayoutPass True if this was invoked from a layout pass, false otherwise.
102d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod     */
103baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod    void loadImageIfNecessary(final boolean isInLayoutPass) {
104d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        int width = getWidth();
105d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        int height = getHeight();
106d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
107baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod        boolean wrapWidth = false, wrapHeight = false;
108baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod        if (getLayoutParams() != null) {
109baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod            wrapWidth = getLayoutParams().width == LayoutParams.WRAP_CONTENT;
110baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod            wrapHeight = getLayoutParams().height == LayoutParams.WRAP_CONTENT;
111baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod        }
112baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod
113aa6a5e69c646e8ef926a794a031ca4a9b5526a89Aurash Mahbod        // if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content
114aa6a5e69c646e8ef926a794a031ca4a9b5526a89Aurash Mahbod        // view, hold off on loading the image.
115baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod        boolean isFullyWrapContent = wrapWidth && wrapHeight;
116aa6a5e69c646e8ef926a794a031ca4a9b5526a89Aurash Mahbod        if (width == 0 && height == 0 && !isFullyWrapContent) {
117d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod            return;
118d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        }
119d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
120d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        // if the URL to be loaded in this view is empty, cancel any old requests and clear the
121d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        // currently loaded image.
122d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        if (TextUtils.isEmpty(mUrl)) {
123da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton            if (mImageContainer != null) {
124da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton                mImageContainer.cancelRequest();
125da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton                mImageContainer = null;
126d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod            }
12754086f9c87af47015cb5de5356310598e4b7dbf5Adam W. Brown            setDefaultImageOrNull();
128d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod            return;
129d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        }
130d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
131d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        // if there was an old request in this view, check if it needs to be canceled.
132da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton        if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {
133da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton            if (mImageContainer.getRequestUrl().equals(mUrl)) {
134d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod                // if the request is from the same URL, return.
135d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod                return;
136d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod            } else {
137d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod                // if there is a pre-existing request, cancel it if it's fetching a different URL.
138da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton                mImageContainer.cancelRequest();
13954086f9c87af47015cb5de5356310598e4b7dbf5Adam W. Brown                setDefaultImageOrNull();
140d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod            }
141d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        }
142d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
143baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod        // Calculate the max image width / height to use while ignoring WRAP_CONTENT dimens.
144baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod        int maxWidth = wrapWidth ? 0 : width;
145baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod        int maxHeight = wrapHeight ? 0 : height;
146baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod
147d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        // The pre-existing content of this view didn't match the current URL. Load the new image
148d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        // from the network.
149d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        ImageContainer newContainer = mImageLoader.get(mUrl,
150b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                new ImageListener() {
151b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                    @Override
152b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                    public void onErrorResponse(VolleyError error) {
153b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                        if (mErrorImageId != 0) {
154b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                            setImageResource(mErrorImageId);
155b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                        }
156b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                    }
157b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod
158b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                    @Override
159b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                    public void onResponse(final ImageContainer response, boolean isImmediate) {
160b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                        // If this was an immediate response that was delivered inside of a layout
161b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                        // pass do not set the image immediately as it will trigger a requestLayout
162b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                        // inside of a layout. Instead, defer setting the image by posting back to
163b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                        // the main thread.
164b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                        if (isImmediate && isInLayoutPass) {
165b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                            post(new Runnable() {
166b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                                @Override
167b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                                public void run() {
168b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                                    onResponse(response, false);
169b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                                }
170b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                            });
171b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                            return;
172b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                        }
173b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod
174b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                        if (response.getBitmap() != null) {
175b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                            setImageBitmap(response.getBitmap());
176b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                        } else if (mDefaultImageId != 0) {
177b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                            setImageResource(mDefaultImageId);
178b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                        }
179b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod                    }
180baa2ff70bea2dbfb89d6732902e6b2bd6de7d207Aurash Mahbod                }, maxWidth, maxHeight);
181d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
182da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton        // update the ImageContainer to be the new bitmap container.
183da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton        mImageContainer = newContainer;
184d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    }
185d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
18654086f9c87af47015cb5de5356310598e4b7dbf5Adam W. Brown    private void setDefaultImageOrNull() {
18754086f9c87af47015cb5de5356310598e4b7dbf5Adam W. Brown        if(mDefaultImageId != 0) {
18854086f9c87af47015cb5de5356310598e4b7dbf5Adam W. Brown            setImageResource(mDefaultImageId);
18954086f9c87af47015cb5de5356310598e4b7dbf5Adam W. Brown        }
19054086f9c87af47015cb5de5356310598e4b7dbf5Adam W. Brown        else {
19154086f9c87af47015cb5de5356310598e4b7dbf5Adam W. Brown            setImageBitmap(null);
19254086f9c87af47015cb5de5356310598e4b7dbf5Adam W. Brown        }
19354086f9c87af47015cb5de5356310598e4b7dbf5Adam W. Brown    }
19454086f9c87af47015cb5de5356310598e4b7dbf5Adam W. Brown
195d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    @Override
196d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
197d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        super.onLayout(changed, left, top, right, bottom);
198b25a6e0f4d3bfdeddfc10e8f5518bab5c16634fdAurash Mahbod        loadImageIfNecessary(true);
199d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    }
200d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
201d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    @Override
202d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    protected void onDetachedFromWindow() {
203da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton        if (mImageContainer != null) {
204d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod            // If the view was bound to an image request, cancel it and clear
205d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod            // out the image from the view.
206da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton            mImageContainer.cancelRequest();
207d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod            setImageBitmap(null);
208da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton            // also clear out the container so we can reload the image if necessary.
209da703141dabd9cae3f71e15a4b9cbb79f6d5d4b8Evan Charlton            mImageContainer = null;
210d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        }
211d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        super.onDetachedFromWindow();
212d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    }
213d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod
214d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    @Override
215d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    protected void drawableStateChanged() {
216d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        super.drawableStateChanged();
217d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod        invalidate();
218d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod    }
219d62a616ebca5bfa4f9ec5517208e13f2d501b69aAurash Mahbod}
220