146616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei/* 246616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * Copyright (C) 2013 The Android Open Source Project 346616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * 446616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * Licensed under the Apache License, Version 2.0 (the "License"); 546616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * you may not use this file except in compliance with the License. 646616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * You may obtain a copy of the License at 746616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * 846616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * http://www.apache.org/licenses/LICENSE-2.0 946616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * 1046616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * Unless required by applicable law or agreed to in writing, software 1146616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * distributed under the License is distributed on an "AS IS" BASIS, 1246616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1346616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * See the License for the specific language governing permissions and 1446616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei * limitations under the License. 1546616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei */ 1646616414f6dabb6d57b0ac433a5fabe2abb8b5a9Mark Wei 17a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Weipackage com.android.bitmap.view; 18a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 19a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Weiimport android.content.Context; 20a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Weiimport android.graphics.Bitmap; 21a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Weiimport android.graphics.drawable.Drawable; 22a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Weiimport android.net.Uri; 23d7654f820a99358a7d2b2afb9b3a174690e213f6Mark Weiimport android.os.Build; 24a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Weiimport android.util.AttributeSet; 25a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Weiimport android.widget.ImageView; 26a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 27a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Weiimport com.android.bitmap.drawable.BasicBitmapDrawable; 28a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 29a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei/** 30a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei * A helpful ImageView replacement that can generally be used in lieu of ImageView. 319c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * BitmapDrawableImageView has logic to unbind its BasicBitmapDrawable when it is detached from the 329c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei * window. 33a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev * 34a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev * If you are using this with RecyclerView, 35a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev * or any use-case where {@link android.view.View#onDetachedFromWindow} is 36a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev * not a good signal for unbind, 37a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev * makes sure you {@link #setShouldUnbindOnDetachFromWindow} to false. 38a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei */ 399c6ac19d4a3d39b7c2992060957920118ff56a65Mark Weipublic class BitmapDrawableImageView extends ImageView { 401a340d4fca7babcb67d6cfa754f58c1a756dfca0Mark Wei private static final boolean HAS_TRANSIENT_STATE_SUPPORTED = 41d7654f820a99358a7d2b2afb9b3a174690e213f6Mark Wei Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; 425b46c679794d2f4362e8064b0291c578835d75e0Mark Wei private static final boolean TEMPORARY = true; 435b46c679794d2f4362e8064b0291c578835d75e0Mark Wei private static final boolean PERMANENT = !TEMPORARY; 445b46c679794d2f4362e8064b0291c578835d75e0Mark Wei 45a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei private BasicBitmapDrawable mDrawable; 46a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev private boolean mShouldUnbindOnDetachFromWindow = true; 479024423249c9b1779f523cc4fe757fda2d205844Mark Wei private boolean mAttachedToWindow; 48a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 499c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei public BitmapDrawableImageView(final Context context) { 50a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei this(context, null); 51a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei } 52a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 539c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei public BitmapDrawableImageView(final Context context, final AttributeSet attrs) { 54a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei this(context, attrs, 0); 55a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei } 56a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 579c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei public BitmapDrawableImageView(final Context context, final AttributeSet attrs, 589c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei final int defStyle) { 59a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei super(context, attrs, defStyle); 60a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei } 61a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 62a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev public boolean shouldUnbindOnDetachFromWindow() { 63a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev return mShouldUnbindOnDetachFromWindow; 64a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev } 65a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev 66a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev public void setShouldUnbindOnDetachFromWindow(boolean shouldUnbindOnDetachFromWindow) { 67a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev mShouldUnbindOnDetachFromWindow = shouldUnbindOnDetachFromWindow; 68a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev } 69a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev 70a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei /** 7189e59f00d67791754e44e65413baa95f94056df4Mark Wei * Get the source drawable for this BitmapDrawableImageView. 7289e59f00d67791754e44e65413baa95f94056df4Mark Wei * @return The source drawable casted to the given type, or null if the type does not match. 739c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei */ 7489e59f00d67791754e44e65413baa95f94056df4Mark Wei @SuppressWarnings("unchecked") // Cast to type parameter. 7589e59f00d67791754e44e65413baa95f94056df4Mark Wei public <E extends BasicBitmapDrawable> E getTypedDrawable() { 7689e59f00d67791754e44e65413baa95f94056df4Mark Wei try { 7789e59f00d67791754e44e65413baa95f94056df4Mark Wei return (E) mDrawable; 7889e59f00d67791754e44e65413baa95f94056df4Mark Wei } catch (Exception ignored) { 7989e59f00d67791754e44e65413baa95f94056df4Mark Wei return null; 8089e59f00d67791754e44e65413baa95f94056df4Mark Wei } 819c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei } 829c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei 839c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei /** 8489e59f00d67791754e44e65413baa95f94056df4Mark Wei * Set the given drawable as the source for this BitmapDrawableImageView. 85a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei * @param drawable The source drawable. 86a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei */ 8789e59f00d67791754e44e65413baa95f94056df4Mark Wei public <E extends BasicBitmapDrawable> void setTypedDrawable(E drawable) { 88a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei super.setImageDrawable(drawable); 89a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev if (drawable != mDrawable) { 90a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev unbindDrawable(); 91a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev } 92a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei mDrawable = drawable; 93a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei } 94a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 95a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev public void unbindDrawable() { 965b46c679794d2f4362e8064b0291c578835d75e0Mark Wei unbindDrawable(PERMANENT); 975b46c679794d2f4362e8064b0291c578835d75e0Mark Wei } 985b46c679794d2f4362e8064b0291c578835d75e0Mark Wei 995b46c679794d2f4362e8064b0291c578835d75e0Mark Wei private void unbindDrawable(boolean temporary) { 1009c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei if (mDrawable != null) { 1015b46c679794d2f4362e8064b0291c578835d75e0Mark Wei mDrawable.unbind(temporary); 1029c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei } 103a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei } 104a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 105a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei @Override 1069c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei public void setImageResource(final int resId) { 1079c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei super.setImageResource(resId); 1089c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei unbindDrawable(); 109b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei mDrawable = null; 110a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei } 111a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 112a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei @Override 1139c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei public void setImageURI(final Uri uri) { 1149c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei super.setImageURI(uri); 1159c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei unbindDrawable(); 116b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei mDrawable = null; 117a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei } 118a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 119a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei @Override 1209c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei public void setImageDrawable(final Drawable drawable) { 1219c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei super.setImageDrawable(drawable); 1229c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei unbindDrawable(); 123b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei mDrawable = null; 124a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei } 125a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 126a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei @Override 1279c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei public void setImageBitmap(final Bitmap bm) { 1289c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei super.setImageBitmap(bm); 1299c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei unbindDrawable(); 130b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei mDrawable = null; 131a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei } 132a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei 133a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei @Override 1349024423249c9b1779f523cc4fe757fda2d205844Mark Wei protected void onAttachedToWindow() { 1359024423249c9b1779f523cc4fe757fda2d205844Mark Wei super.onAttachedToWindow(); 1369024423249c9b1779f523cc4fe757fda2d205844Mark Wei mAttachedToWindow = true; 137d732a611bd661fc2ac3c801a545cfbba0f179484Mark Wei if (mDrawable != null && mDrawable.getKey() == null 138a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev && mDrawable.getPreviousKey() != null && mShouldUnbindOnDetachFromWindow) { 139ad97cd0e0753930ec68f189e6be1023dc0f62f75Mark Wei mDrawable.bind(mDrawable.getPreviousKey()); 1401a340d4fca7babcb67d6cfa754f58c1a756dfca0Mark Wei } 1419024423249c9b1779f523cc4fe757fda2d205844Mark Wei } 1429024423249c9b1779f523cc4fe757fda2d205844Mark Wei 1439024423249c9b1779f523cc4fe757fda2d205844Mark Wei @Override 1449c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei protected void onDetachedFromWindow() { 1459c6ac19d4a3d39b7c2992060957920118ff56a65Mark Wei super.onDetachedFromWindow(); 1469024423249c9b1779f523cc4fe757fda2d205844Mark Wei mAttachedToWindow = false; 147a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev if (HAS_TRANSIENT_STATE_SUPPORTED && !hasTransientState() 148a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev && mShouldUnbindOnDetachFromWindow) { 1495b46c679794d2f4362e8064b0291c578835d75e0Mark Wei unbindDrawable(TEMPORARY); 1509024423249c9b1779f523cc4fe757fda2d205844Mark Wei } 1519024423249c9b1779f523cc4fe757fda2d205844Mark Wei } 1529024423249c9b1779f523cc4fe757fda2d205844Mark Wei 1539024423249c9b1779f523cc4fe757fda2d205844Mark Wei @Override 1549024423249c9b1779f523cc4fe757fda2d205844Mark Wei public void setHasTransientState(boolean hasTransientState) { 1559024423249c9b1779f523cc4fe757fda2d205844Mark Wei super.setHasTransientState(hasTransientState); 156a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev if (!hasTransientState && !mAttachedToWindow && mShouldUnbindOnDetachFromWindow) { 1575b46c679794d2f4362e8064b0291c578835d75e0Mark Wei unbindDrawable(TEMPORARY); 1589024423249c9b1779f523cc4fe757fda2d205844Mark Wei } 159a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei } 160856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei 161856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei @Override 162856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei public void onRtlPropertiesChanged(int layoutDirection) { 163856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei super.onRtlPropertiesChanged(layoutDirection); 164856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei if (mDrawable != null) { 165856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei mDrawable.setLayoutDirectionLocal(layoutDirection); 166856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei } 167856e2a9d72fe3a79cd7bfa5cf443d13a60495c4bMark Wei } 168a23358fbfd62c7aa1c84bfa8395b4dc427a71ce6Mark Wei} 169