193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/* 293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Copyright (C) 2013 The Android Open Source Project 393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Licensed under the Apache License, Version 2.0 (the "License"); 593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * you may not use this file except in compliance with the License. 693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * You may obtain a copy of the License at 793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * http://www.apache.org/licenses/LICENSE-2.0 993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 1093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Unless required by applicable law or agreed to in writing, software 1193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * distributed under the License is distributed on an "AS IS" BASIS, 1293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * See the License for the specific language governing permissions and 1493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * limitations under the License. 1593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 1693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 1793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpackage com.android.bitmap.drawable; 1893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 1993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.animation.Animator; 2093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.animation.AnimatorListenerAdapter; 2193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.animation.ValueAnimator; 2293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.animation.ValueAnimator.AnimatorUpdateListener; 2393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.content.res.Resources; 2493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.Canvas; 25df3da61c8f2f54604376d9761649bdba54aa858bMark Weiimport android.graphics.Color; 2693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.ColorFilter; 2793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.Rect; 2893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.drawable.Drawable; 2993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.os.Handler; 3093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.util.Log; 3193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.view.animation.LinearInterpolator; 3293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 3393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.BitmapCache; 3493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.DecodeAggregator; 3593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.DecodeTask; 369c6ac19d4a3d39b7c2992060957920118ff56a65Mark Weiimport com.android.bitmap.R; 3740662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzsteinimport com.android.bitmap.RequestKey; 3893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.ReusableBitmap; 3993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.Trace; 4093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 4193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/** 4293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * This class encapsulates all functionality needed to display a single image bitmap, 4393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * including request creation/cancelling, data unbinding and re-binding, and fancy animations 4493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * to draw upon state changes. 4593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * <p> 4693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * The actual bitmap decode work is handled by {@link DecodeTask}. 4793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 482e4d0863dba53435372ec96538f2ef3e1c3675bfMark Weipublic class ExtendedBitmapDrawable extends BasicBitmapDrawable implements 492e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei Runnable, Parallaxable, DecodeAggregator.Callback { 50cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei 51b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei public static final int LOAD_STATE_UNINITIALIZED = 0; 52b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei public static final int LOAD_STATE_NOT_YET_LOADED = 1; 53b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei public static final int LOAD_STATE_LOADING = 2; 54b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei public static final int LOAD_STATE_LOADED = 3; 55b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei public static final int LOAD_STATE_FAILED = 4; 56b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei 57b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei public static final boolean DEBUG = false; 58c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei private static final String TAG = ExtendedBitmapDrawable.class.getSimpleName(); 59b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei 605d6521e290594fe0851086b0c27413e9709e437fMark Wei private final Resources mResources; 615030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei private final ExtendedOptions mOpts; 625030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 632e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei // Parallax. 645030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei private float mParallaxFraction = 1f / 2; 6593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 665030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei // State changes. 672e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei private int mLoadState = LOAD_STATE_UNINITIALIZED; 682e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei private Placeholder mPlaceholder; 692e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei private Progress mProgress; 7093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private int mProgressDelayMs; 7193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private final Handler mHandler = new Handler(); 7293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 7393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public ExtendedBitmapDrawable(final Resources res, final BitmapCache cache, 7409f46006437e7de33afdb51192bf0bdc08e97040Mark Wei final boolean limitDensity, ExtendedOptions opts) { 752e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei super(res, cache, limitDensity); 765d6521e290594fe0851086b0c27413e9709e437fMark Wei mResources = res; 7709f46006437e7de33afdb51192bf0bdc08e97040Mark Wei if (opts == null) { 7809f46006437e7de33afdb51192bf0bdc08e97040Mark Wei opts = new ExtendedOptions(0); 7909f46006437e7de33afdb51192bf0bdc08e97040Mark Wei } 805030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei mOpts = opts; 8193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 825d6521e290594fe0851086b0c27413e9709e437fMark Wei onOptsChanged(); 835d6521e290594fe0851086b0c27413e9709e437fMark Wei } 845d6521e290594fe0851086b0c27413e9709e437fMark Wei 855d6521e290594fe0851086b0c27413e9709e437fMark Wei /** 865d6521e290594fe0851086b0c27413e9709e437fMark Wei * Called after a field is changed in an {@link ExtendedOptions}, if that field requests this 875d6521e290594fe0851086b0c27413e9709e437fMark Wei * method to be called. 885d6521e290594fe0851086b0c27413e9709e437fMark Wei */ 895d6521e290594fe0851086b0c27413e9709e437fMark Wei public void onOptsChanged() { 905d6521e290594fe0851086b0c27413e9709e437fMark Wei mOpts.validate(); 915d6521e290594fe0851086b0c27413e9709e437fMark Wei 922e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei // Placeholder and progress. 935d6521e290594fe0851086b0c27413e9709e437fMark Wei if ((mOpts.features & ExtendedOptions.FEATURE_STATE_CHANGES) != 0) { 945d6521e290594fe0851086b0c27413e9709e437fMark Wei final int fadeOutDurationMs = mResources.getInteger(R.integer.bitmap_fade_animation_duration); 955d6521e290594fe0851086b0c27413e9709e437fMark Wei mProgressDelayMs = mResources.getInteger(R.integer.bitmap_progress_animation_delay); 965030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 9788e3100ef41cf50e4f40bbaab661df41e176dae2Mark Wei // Placeholder is not optional because backgroundColor is part of it. 9888e3100ef41cf50e4f40bbaab661df41e176dae2Mark Wei Drawable placeholder = null; 995d6521e290594fe0851086b0c27413e9709e437fMark Wei int placeholderWidth = mResources.getDimensionPixelSize(R.dimen.placeholder_size); 1005d6521e290594fe0851086b0c27413e9709e437fMark Wei int placeholderHeight = mResources.getDimensionPixelSize(R.dimen.placeholder_size); 1015d6521e290594fe0851086b0c27413e9709e437fMark Wei if (mOpts.placeholder != null) { 1025d6521e290594fe0851086b0c27413e9709e437fMark Wei ConstantState constantState = mOpts.placeholder.getConstantState(); 10388e3100ef41cf50e4f40bbaab661df41e176dae2Mark Wei if (constantState != null) { 1045d6521e290594fe0851086b0c27413e9709e437fMark Wei placeholder = constantState.newDrawable(mResources); 105c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } else { 106c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei placeholder = mOpts.placeholder; 107c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } 108b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei 109c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei Rect bounds = mOpts.placeholder.getBounds(); 110c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei if (bounds.width() != 0) { 111c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei placeholderWidth = bounds.width(); 112c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } else if (placeholder.getIntrinsicWidth() != -1) { 113c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei placeholderWidth = placeholder.getIntrinsicWidth(); 114c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } 115c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei if (bounds.height() != 0) { 116c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei placeholderHeight = bounds.height(); 117c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } else if (placeholder.getIntrinsicHeight() != -1) { 118c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei placeholderHeight = placeholder.getIntrinsicHeight(); 11988e3100ef41cf50e4f40bbaab661df41e176dae2Mark Wei } 12088e3100ef41cf50e4f40bbaab661df41e176dae2Mark Wei } 121b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei 1225d6521e290594fe0851086b0c27413e9709e437fMark Wei mPlaceholder = new Placeholder(placeholder, mResources, placeholderWidth, placeholderHeight, 1235d6521e290594fe0851086b0c27413e9709e437fMark Wei fadeOutDurationMs, mOpts); 1245030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei mPlaceholder.setCallback(this); 1254d404fe4edb0b5074ed9d3e90dd7aa942f252692Mark Wei mPlaceholder.setBounds(getBounds()); 1265030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 1275030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei // Progress bar is optional. 1285d6521e290594fe0851086b0c27413e9709e437fMark Wei if (mOpts.progressBar != null) { 1295d6521e290594fe0851086b0c27413e9709e437fMark Wei int progressBarSize = mResources.getDimensionPixelSize(R.dimen.progress_bar_size); 1305d6521e290594fe0851086b0c27413e9709e437fMark Wei mProgress = new Progress(mOpts.progressBar.getConstantState().newDrawable(mResources), mResources, 1315d6521e290594fe0851086b0c27413e9709e437fMark Wei progressBarSize, progressBarSize, fadeOutDurationMs, mOpts); 1325030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei mProgress.setCallback(this); 1334d404fe4edb0b5074ed9d3e90dd7aa942f252692Mark Wei mProgress.setBounds(getBounds()); 1345d6521e290594fe0851086b0c27413e9709e437fMark Wei } else { 1355d6521e290594fe0851086b0c27413e9709e437fMark Wei mProgress = null; 1365030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 1375030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 1385d6521e290594fe0851086b0c27413e9709e437fMark Wei 1395d6521e290594fe0851086b0c27413e9709e437fMark Wei setLoadState(mLoadState); 14093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 14193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 1422e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei @Override 1432e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei public void setParallaxFraction(float fraction) { 1442e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei mParallaxFraction = fraction; 1452e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei invalidateSelf(); 14693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 14793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 1485030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 1495030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Get the ExtendedOptions used to instantiate this ExtendedBitmapDrawable. Any changes made to 1505030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * the parameters inside the options will take effect immediately. 1515030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 1525030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei public ExtendedOptions getExtendedOptions() { 1535030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei return mOpts; 15493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 15593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 1562e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei /** 1572e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei * This sets the drawable to the failed state, which remove all animations from the placeholder. 1582e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei * This is different from unbinding to the uninitialized state, where we expect animations. 1592e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei */ 16093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void showStaticPlaceholder() { 16193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein setLoadState(LOAD_STATE_FAILED); 16293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 16393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 16489e59f00d67791754e44e65413baa95f94056df4Mark Wei /** 16589e59f00d67791754e44e65413baa95f94056df4Mark Wei * Directly sets the decode width and height. The given height should already have had the 16689e59f00d67791754e44e65413baa95f94056df4Mark Wei * parallaxSpeedMultiplier applied to it. 16789e59f00d67791754e44e65413baa95f94056df4Mark Wei */ 16889e59f00d67791754e44e65413baa95f94056df4Mark Wei public void setExactDecodeDimensions(int width, int height) { 16989e59f00d67791754e44e65413baa95f94056df4Mark Wei super.setDecodeDimensions(width, height); 17089e59f00d67791754e44e65413baa95f94056df4Mark Wei } 17189e59f00d67791754e44e65413baa95f94056df4Mark Wei 17289e59f00d67791754e44e65413baa95f94056df4Mark Wei /** 17389e59f00d67791754e44e65413baa95f94056df4Mark Wei * {@inheritDoc} 17489e59f00d67791754e44e65413baa95f94056df4Mark Wei * 17589e59f00d67791754e44e65413baa95f94056df4Mark Wei * The given height should not have had the parallaxSpeedMultiplier applied to it. 17689e59f00d67791754e44e65413baa95f94056df4Mark Wei */ 1772e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei @Override 17889e59f00d67791754e44e65413baa95f94056df4Mark Wei public void setDecodeDimensions(int width, int height) { 17989e59f00d67791754e44e65413baa95f94056df4Mark Wei super.setDecodeDimensions(width, (int) (height * mOpts.parallaxSpeedMultiplier)); 18089e59f00d67791754e44e65413baa95f94056df4Mark Wei } 18193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 18289e59f00d67791754e44e65413baa95f94056df4Mark Wei @Override 18389e59f00d67791754e44e65413baa95f94056df4Mark Wei protected void setImage(final RequestKey key) { 1845030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mCurrKey != null && getDecodeAggregator() != null) { 1855030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei getDecodeAggregator().forget(mCurrKey); 18693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 18793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 18893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mHandler.removeCallbacks(this); 18993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // start from a clean slate on every bind 19093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // this allows the initial transition to be specially instantaneous, so e.g. a cache hit 19193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // doesn't unnecessarily trigger a fade-in 19293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein setLoadState(LOAD_STATE_UNINITIALIZED); 19393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 1942e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei super.setImage(key); 195b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei 196b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei if (key == null) { 197b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei showStaticPlaceholder(); 198b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei } 1992e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei } 2002e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei 2012e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei @Override 2022e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei protected void setBitmap(ReusableBitmap bmp) { 203c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei if (bmp != null) { 204c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei setLoadState(LOAD_STATE_LOADED); 205c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } else { 206c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei onDecodeFailed(); 207c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } 2082e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei 2092e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei super.setBitmap(bmp); 2102e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei } 2112e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei 2122e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei @Override 21341af50eb1ac488572b066629c3954b23c21dfa76Mark Wei protected void loadFileDescriptorFactory() { 2142e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei boolean executeStateChange = shouldExecuteStateChange(); 21519a41ec7aaace2ab0b117d0baaeb544c5667b240Mark Wei if (mCurrKey == null || mDecodeWidth == 0 || mDecodeHeight == 0) { 21619a41ec7aaace2ab0b117d0baaeb544c5667b240Mark Wei return; 21719a41ec7aaace2ab0b117d0baaeb544c5667b240Mark Wei } 21819a41ec7aaace2ab0b117d0baaeb544c5667b240Mark Wei 2192e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei if (executeStateChange) { 22019a41ec7aaace2ab0b117d0baaeb544c5667b240Mark Wei setLoadState(LOAD_STATE_NOT_YET_LOADED); 22193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 2222e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei 22341af50eb1ac488572b066629c3954b23c21dfa76Mark Wei super.loadFileDescriptorFactory(); 2242e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei } 2252e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei 226c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei @Override 227c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei protected void onDecodeFailed() { 228c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei super.onDecodeFailed(); 229c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei 230c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei setLoadState(LOAD_STATE_FAILED); 231c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei } 232c5644927c0e7e121049b063046296ee8a59a4b37Mark Wei 2332e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei protected boolean shouldExecuteStateChange() { 2342e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei // TODO: AttachmentDrawable should override this method to match prev and curr request keys. 2352e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei return /* opts.stateChanges */ true; 23693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 23793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 23893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 2392e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei public float getDrawVerticalCenter() { 2402e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei return mParallaxFraction; 2412e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei } 2422e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei 2432e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei @Override 24489e59f00d67791754e44e65413baa95f94056df4Mark Wei protected final float getDrawVerticalOffsetMultiplier() { 2455030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei return mOpts.parallaxSpeedMultiplier; 2462e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei } 2472e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei 2482e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei @Override 2493a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung protected float getDecodeHorizontalCenter() { 2503a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung return mOpts.decodeHorizontalCenter; 2513a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung } 2523a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung 2533a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung @Override 2542e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei protected float getDecodeVerticalCenter() { 25589e59f00d67791754e44e65413baa95f94056df4Mark Wei return mOpts.decodeVerticalCenter; 25693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 25793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 2585030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei private DecodeAggregator getDecodeAggregator() { 2595030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei return mOpts.decodeAggregator; 2605030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 2615030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 2625030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 2635030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Instead of overriding this method, subclasses should override {@link #onDraw(Canvas)}. 2645030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 2655030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * The reason for this is that we need the placeholder and progress bar to be drawn over our 2665030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * content. Those two drawables fade out, giving the impression that our content is fading in. 2675f42121579221299e02f6d4627725814ed3d0fbfMark Wei * 2685f42121579221299e02f6d4627725814ed3d0fbfMark Wei * Only override this method for custom drawings on top of all the drawable layers. 2695030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 27093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 2715f42121579221299e02f6d4627725814ed3d0fbfMark Wei public void draw(final Canvas canvas) { 27293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final Rect bounds = getBounds(); 27393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (bounds.isEmpty()) { 27493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return; 27593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 27693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 2775030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei onDraw(canvas); 27893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 27993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // Draw the two possible overlay layers in reverse-priority order. 28093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // (each layer will no-op the draw when appropriate) 28193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // This ordering means cross-fade transitions are just fade-outs of each layer. 28209f46006437e7de33afdb51192bf0bdc08e97040Mark Wei if (mProgress != null) onDrawPlaceholderOrProgress(canvas, mProgress); 28309f46006437e7de33afdb51192bf0bdc08e97040Mark Wei if (mPlaceholder != null) onDrawPlaceholderOrProgress(canvas, mPlaceholder); 2845030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 2855030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 2865030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 2875030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Overriding this method to add your own custom drawing. 2885030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 2895030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei protected void onDraw(final Canvas canvas) { 2905030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei super.draw(canvas); 29193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 29293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 29309f46006437e7de33afdb51192bf0bdc08e97040Mark Wei /** 29409f46006437e7de33afdb51192bf0bdc08e97040Mark Wei * Overriding this method to add your own custom placeholder or progress drawing. 29509f46006437e7de33afdb51192bf0bdc08e97040Mark Wei */ 29609f46006437e7de33afdb51192bf0bdc08e97040Mark Wei protected void onDrawPlaceholderOrProgress(final Canvas canvas, final TileDrawable drawable) { 29709f46006437e7de33afdb51192bf0bdc08e97040Mark Wei drawable.draw(canvas); 29809f46006437e7de33afdb51192bf0bdc08e97040Mark Wei } 29909f46006437e7de33afdb51192bf0bdc08e97040Mark Wei 30093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 30193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void setAlpha(int alpha) { 30293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final int old = mPaint.getAlpha(); 3032e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei super.setAlpha(alpha); 3045030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mPlaceholder != null) mPlaceholder.setAlpha(alpha); 3055030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mProgress != null) mProgress.setAlpha(alpha); 30693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (alpha != old) { 30793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein invalidateSelf(); 30893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 30993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 31093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 31193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 31293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void setColorFilter(ColorFilter cf) { 3132e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei super.setColorFilter(cf); 3145030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mPlaceholder != null) mPlaceholder.setColorFilter(cf); 3155030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mProgress != null) mProgress.setColorFilter(cf); 31693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein invalidateSelf(); 31793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 31893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 31993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 32093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein protected void onBoundsChange(Rect bounds) { 32193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein super.onBoundsChange(bounds); 3225030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mPlaceholder != null) mPlaceholder.setBounds(bounds); 3235030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mProgress != null) mProgress.setBounds(bounds); 32493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 32593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 32693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 32740662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein public void onDecodeBegin(final RequestKey key) { 3285030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (getDecodeAggregator() != null) { 3295030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei getDecodeAggregator().expect(key, this); 33093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 33193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein onBecomeFirstExpected(key); 33293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 3332e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei super.onDecodeBegin(key); 33493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 33593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 33693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 33740662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein public void onBecomeFirstExpected(final RequestKey key) { 33893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (!key.equals(mCurrKey)) { 33993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return; 34093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 34193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // normally, we'd transition to the LOADING state now, but we want to delay that a bit 34293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // to minimize excess occurrences of the rotating spinner 34393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mHandler.postDelayed(this, mProgressDelayMs); 34493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 34593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 34693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 34793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void run() { 34893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mLoadState == LOAD_STATE_NOT_YET_LOADED) { 34993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein setLoadState(LOAD_STATE_LOADING); 35093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 35193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 35293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 35393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 35440662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein public void onDecodeComplete(final RequestKey key, final ReusableBitmap result) { 3555030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (getDecodeAggregator() != null) { 3565030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei getDecodeAggregator().execute(key, new Runnable() { 35793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 35893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void run() { 3592e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei ExtendedBitmapDrawable.super.onDecodeComplete(key, result); 36093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 36193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 36293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 36393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public String toString() { 36493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return "DONE"; 36593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 36693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein }); 36793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 3682e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei super.onDecodeComplete(key, result); 36993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 37093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 37193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 37293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 37340662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein public void onDecodeCancel(final RequestKey key) { 3745030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (getDecodeAggregator() != null) { 3755030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei getDecodeAggregator().forget(key); 37693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 3772e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei super.onDecodeCancel(key); 37893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 37993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 3802e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei /** 381b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei * Get the load state of this drawable. Return one of the LOAD_STATE constants. 382b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei */ 383b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei public int getLoadState() { 384b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei return mLoadState; 385b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei } 386b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei 387b6ec2afe9710112214d79b36b2233fef6a52845aMark Wei /** 3882e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei * Each attachment gets its own placeholder and progress indicator, to be shown, hidden, 3892e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei * and animated based on Drawable#setVisible() changes, which are in turn driven by 3902e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei * setLoadState(). 3912e4d0863dba53435372ec96538f2ef3e1c3675bfMark Wei */ 39293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private void setLoadState(int loadState) { 39393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (DEBUG) { 39493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.v(TAG, String.format("IN setLoadState. old=%s new=%s key=%s this=%s", 39593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mLoadState, loadState, mCurrKey, this)); 39693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 39793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 39893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("set load state"); 39993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein switch (loadState) { 40093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // This state differs from LOADED in that the subsequent state transition away from 40193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // UNINITIALIZED will not have a fancy transition. This allows list item binds to 40293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // cached data to take immediate effect without unnecessary whizzery. 40393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein case LOAD_STATE_UNINITIALIZED: 4045030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mPlaceholder != null) mPlaceholder.reset(); 4055030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mProgress != null) mProgress.reset(); 40693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein break; 40793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein case LOAD_STATE_NOT_YET_LOADED: 4085030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mPlaceholder != null) { 4095030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei mPlaceholder.setPulseEnabled(true); 4105030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei mPlaceholder.setVisible(true); 4115030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 4125030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mProgress != null) mProgress.setVisible(false); 41393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein break; 41493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein case LOAD_STATE_LOADING: 4155030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mProgress == null) { 4165030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei // Stay in same visual state as LOAD_STATE_NOT_YET_LOADED. 4175030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei break; 4185030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 4195030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mPlaceholder != null) mPlaceholder.setVisible(false); 4205030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mProgress != null) mProgress.setVisible(true); 42193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein break; 42293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein case LOAD_STATE_LOADED: 4235030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mPlaceholder != null) mPlaceholder.setVisible(false); 4245030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mProgress != null) mProgress.setVisible(false); 42593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein break; 42693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein case LOAD_STATE_FAILED: 4275030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mPlaceholder != null) { 4285030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei mPlaceholder.setPulseEnabled(false); 4295030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei mPlaceholder.setVisible(true); 4305030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 4315030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if (mProgress != null) mProgress.setVisible(false); 43293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein break; 43393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 43493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 43593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 43693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mLoadState = loadState; 43793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein boolean placeholderVisible = mPlaceholder != null && mPlaceholder.isVisible(); 43893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein boolean progressVisible = mProgress != null && mProgress.isVisible(); 43993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 44093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (DEBUG) { 44193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.v(TAG, String.format("OUT stateful setLoadState. new=%s placeholder=%s progress=%s", 44293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein loadState, placeholderVisible, progressVisible)); 44393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 44493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 44593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 44693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private static class Placeholder extends TileDrawable { 44793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 44893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private final ValueAnimator mPulseAnimator; 44993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private boolean mPulseEnabled = true; 45093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private float mPulseAlphaFraction = 1f; 45193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 4525030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei public Placeholder(Drawable placeholder, Resources res, int placeholderWidth, 4535030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei int placeholderHeight, int fadeOutDurationMs, ExtendedOptions opts) { 4545030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei super(placeholder, placeholderWidth, placeholderHeight, fadeOutDurationMs, opts); 4555030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 456c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei if (opts.placeholderAnimationDuration == -1) { 457c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei mPulseAnimator = null; 458c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei } else { 459c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei final long pulseDuration; 460c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei if (opts.placeholderAnimationDuration == 0) { 461c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei pulseDuration = res.getInteger(R.integer.bitmap_placeholder_animation_duration); 462c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei } else { 463c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei pulseDuration = opts.placeholderAnimationDuration; 46493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 465c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei mPulseAnimator = ValueAnimator.ofInt(55, 255).setDuration(pulseDuration); 466c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei mPulseAnimator.setRepeatCount(ValueAnimator.INFINITE); 467c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei mPulseAnimator.setRepeatMode(ValueAnimator.REVERSE); 468c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei mPulseAnimator.addUpdateListener(new AnimatorUpdateListener() { 469c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei @Override 470c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei public void onAnimationUpdate(ValueAnimator animation) { 471c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei mPulseAlphaFraction = ((Integer) animation.getAnimatedValue()) / 255f; 472c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei setInnerAlpha(getCurrentAlpha()); 473c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei } 474c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei }); 475c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei } 47693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mFadeOutAnimator.addListener(new AnimatorListenerAdapter() { 47793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 47893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void onAnimationEnd(Animator animation) { 47993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein stopPulsing(); 48093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 48193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein }); 48293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 48393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 48493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 48593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void setInnerAlpha(final int alpha) { 48693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein super.setInnerAlpha((int) (alpha * mPulseAlphaFraction)); 48793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 48893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 48993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void setPulseEnabled(boolean enabled) { 49093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mPulseEnabled = enabled; 49193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (!mPulseEnabled) { 49293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein stopPulsing(); 493c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei } else { 494c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei startPulsing(); 49593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 49693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 49793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 49893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private void stopPulsing() { 49993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mPulseAnimator != null) { 50093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mPulseAnimator.cancel(); 50193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mPulseAlphaFraction = 1f; 50293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein setInnerAlpha(getCurrentAlpha()); 50393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 50493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 50593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 506c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei private void startPulsing() { 507c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei if (mPulseAnimator != null && !mPulseAnimator.isStarted()) { 508c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei mPulseAnimator.start(); 509c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei } 510c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei } 511c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei 51293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 51393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public boolean setVisible(boolean visible) { 51493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final boolean changed = super.setVisible(visible); 51593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (changed) { 51693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (isVisible()) { 51793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // start 518c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei if (mPulseAnimator != null && mPulseEnabled && !mPulseAnimator.isStarted()) { 51993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mPulseAnimator.start(); 52093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 52193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 52293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // can't cancel the pulsing yet-- wait for the fade-out animation to end 52393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // one exception: if alpha is already zero, there is no fade-out, so stop now 52493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (getCurrentAlpha() == 0) { 52593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein stopPulsing(); 52693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 52793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 52893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 52993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return changed; 53093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 53193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 53293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 53393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 53493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private static class Progress extends TileDrawable { 53593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 53693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private final ValueAnimator mRotateAnimator; 53793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 53893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public Progress(Drawable progress, Resources res, 53993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein int progressBarWidth, int progressBarHeight, int fadeOutDurationMs, 5405030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei ExtendedOptions opts) { 5415030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei super(progress, progressBarWidth, progressBarHeight, fadeOutDurationMs, opts); 54293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 54393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mRotateAnimator = ValueAnimator.ofInt(0, 10000) 54493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein .setDuration(res.getInteger(R.integer.bitmap_progress_animation_duration)); 54593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mRotateAnimator.setInterpolator(new LinearInterpolator()); 54693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mRotateAnimator.setRepeatCount(ValueAnimator.INFINITE); 54793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mRotateAnimator.addUpdateListener(new AnimatorUpdateListener() { 54893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 54993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void onAnimationUpdate(ValueAnimator animation) { 55093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein setLevel((Integer) animation.getAnimatedValue()); 55193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 55293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein }); 55393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mFadeOutAnimator.addListener(new AnimatorListenerAdapter() { 55493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 55593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void onAnimationEnd(Animator animation) { 55693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mRotateAnimator != null) { 55793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mRotateAnimator.cancel(); 55893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 55993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 56093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein }); 56193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 56293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 56393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 56493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public boolean setVisible(boolean visible) { 56593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final boolean changed = super.setVisible(visible); 56693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (changed) { 56793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (isVisible()) { 56893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mRotateAnimator != null) { 56993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mRotateAnimator.start(); 57093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 57193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } else { 57293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // can't cancel the rotate yet-- wait for the fade-out animation to end 57393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // one exception: if alpha is already zero, there is no fade-out, so stop now 57493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (getCurrentAlpha() == 0 && mRotateAnimator != null) { 57593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mRotateAnimator.cancel(); 57693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 57793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 57893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 57993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return changed; 58093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 5815030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 5825030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 5835030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 5845030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * This class contains the features a client can specify, and arguments to those features. 5855030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Clients can later retrieve the ExtendedOptions from an ExtendedBitmapDrawable and change the 5865030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * parameters, which will be reflected immediately. 5875030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 5885030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei public static class ExtendedOptions { 5895030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 5905030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 5915030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Summary: 5925030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * This feature enables you to draw decoded bitmap in order on the screen, to give the 5935030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * visual effect of a single decode thread. 5945030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 5955030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 5965030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Explanation: 5975030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Since DecodeTasks are asynchronous, multiple tasks may finish decoding at different 5985030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * times. To have a smooth user experience, provide a shared {@link DecodeAggregator} to all 5995030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * the ExtendedBitmapDrawables, and the decode aggregator will hold finished decodes so they 6005030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * come back in order. 6015030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 6025030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 6035030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Pros: 6045030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Visual consistency. Images are not popping up randomly all over the place. 6055030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 6065030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 6075030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Cons: 6085030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Artificial delay. Images are not drawn as soon as they are decoded. They must wait 6095030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * for their turn. 6105030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 6115030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 6125030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Requirements: 6135030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Set {@link #decodeAggregator} to a shared {@link DecodeAggregator}. 6145030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 6155030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei public static final int FEATURE_ORDERED_DISPLAY = 1; 6165030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 6175030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 6185030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Summary: 6195030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * This feature enables the image to move in parallax as the user scrolls, to give visual 6205030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * flair to your images. 6215030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 6225030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 6235030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Explanation: 6245030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * When the user scrolls D pixels in the vertical direction, this ExtendedBitmapDrawable 6255030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * shifts its Bitmap f(D) pixels in the vertical direction before drawing to the screen. 6265030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Depending on the function f, the parallax effect can give varying interesting results. 6275030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 6285030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 6295030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Pros: 6305030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Visual pop and playfulness. Feeling of movement. Pleasantly surprise your users. 6315030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 6325030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 6335030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Cons: 6345030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Some users report motion sickness with certain speed multiplier values. Decode height 6355030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * must be greater than visual bounds to account for the parallax. This uses more memory and 6365030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * decoding time. 6375030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 6385030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 6395030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Requirements: 6405030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Set {@link #parallaxSpeedMultiplier} to the ratio between the decoded height and the 64110dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei * visual bound height. Call {@link ExtendedBitmapDrawable#setDecodeDimensions(int, int)} 64210dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei * with the height multiplied by {@link #parallaxSpeedMultiplier}. 64310dddd8a24a80d1d539997d8eaa9763c62bd02adMark Wei * Call {@link ExtendedBitmapDrawable#setParallaxFraction(float)} when the user scrolls. 6445030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 6455030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei public static final int FEATURE_PARALLAX = 1 << 1; 6465030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 6475030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 6485030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Summary: 6495030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * This feature enables fading in between multiple decode states, to give smooth transitions 6505030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * to and from the placeholder, progress bars, and decoded image. 6515030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 6525030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 6535030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Explanation: 6545030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * The states are: {@link ExtendedBitmapDrawable#LOAD_STATE_UNINITIALIZED}, 6555030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * {@link ExtendedBitmapDrawable#LOAD_STATE_NOT_YET_LOADED}, 6565030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * {@link ExtendedBitmapDrawable#LOAD_STATE_LOADING}, 6575030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * {@link ExtendedBitmapDrawable#LOAD_STATE_LOADED}, and 6585030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * {@link ExtendedBitmapDrawable#LOAD_STATE_FAILED}. These states affect whether the 6595030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * placeholder and/or the progress bar is showing and animating. We first show the 6605030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * pulsating placeholder when an image begins decoding. After 2 seconds, we fade in a 6615030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * spinning progress bar. When the decode completes, we fade in the image. 6625030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 6635030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 6645030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Pros: 6655030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Smooth, beautiful transitions avoid perceived jank. Progress indicator informs users that 6665030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * work is being done and the app is not stalled. 6675030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 6685030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 6695030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Cons: 6705030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Very fast decodes' short decode time would be eclipsed by the animation duration. Static 6715030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * placeholder could be accomplished by {@link BasicBitmapDrawable} without the added 6725030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * complexity of states. 6735030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 6745030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 6755030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Requirements: 6765030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Set {@link #backgroundColor} to the color used for the background of the placeholder and 6775030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * progress bar. Use the alternative constructor to populate {@link #placeholder} and 678c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei * {@link #progressBar}. Optionally set {@link #placeholderAnimationDuration}. 6795030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 6805030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei public static final int FEATURE_STATE_CHANGES = 1 << 2; 6815030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 6825030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 6835030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Non-changeable bit field describing the features you want the 6845030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * {@link ExtendedBitmapDrawable} to support. 6855030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 6865030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <p/> 6875030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Example: 6885030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * <code> 6895030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * opts.features = FEATURE_ORDERED_DISPLAY | FEATURE_PARALLAX | FEATURE_STATE_CHANGES; 6905030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * </code> 6915030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 6925030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei public final int features; 6935030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 6945030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 69589e59f00d67791754e44e65413baa95f94056df4Mark Wei * Optional field for general decoding. 69689e59f00d67791754e44e65413baa95f94056df4Mark Wei * 69789e59f00d67791754e44e65413baa95f94056df4Mark Wei * This field determines which section of the source image to decode from. A value of 0 6983a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * indicates a preference for the far left of the source, while a value of 1 indicates a 6993a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * preference for the far right of the source. A value of .5 will result in the center 7003a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * of the source being decoded. 7013a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung */ 7023a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung public float decodeHorizontalCenter = 1f / 2; 7033a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung 7043a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung /** 7053a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * Optional field for general decoding. 7063a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * 7073a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung * This field determines which section of the source image to decode from. A value of 0 70889e59f00d67791754e44e65413baa95f94056df4Mark Wei * indicates a preference for the very top of the source, while a value of 1 indicates a 70989e59f00d67791754e44e65413baa95f94056df4Mark Wei * preference for the very bottom of the source. A value of .5 will result in the center 71089e59f00d67791754e44e65413baa95f94056df4Mark Wei * of the source being decoded. 71189e59f00d67791754e44e65413baa95f94056df4Mark Wei * 71289e59f00d67791754e44e65413baa95f94056df4Mark Wei * This should not be confused with {@link #setParallaxFraction(float)}. This field 71389e59f00d67791754e44e65413baa95f94056df4Mark Wei * determines the general section for decode. The parallax fraction then determines the 71489e59f00d67791754e44e65413baa95f94056df4Mark Wei * slice from within that section for display. 71589e59f00d67791754e44e65413baa95f94056df4Mark Wei */ 716a8b1e1f5cad36086e89c052007473609c379ccbdOleksandr Kyreiev public float decodeVerticalCenter = 1f / 2; 71789e59f00d67791754e44e65413baa95f94056df4Mark Wei 71889e59f00d67791754e44e65413baa95f94056df4Mark Wei /** 7195030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Required field if {@link #FEATURE_ORDERED_DISPLAY} is supported. 7205030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 7215030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei public DecodeAggregator decodeAggregator = null; 7225030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 7235030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 7245030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Required field if {@link #FEATURE_PARALLAX} is supported. 7255030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 7265030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * A value of 1.5f gives a subtle parallax, and is a good value to 7275030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * start with. 2.0f gives a more obvious parallax, arguably exaggerated. Some users report 7285030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * motion sickness with 2.0f. A value of 1.0f is synonymous with no parallax. Be careful not 7295030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * to set too high a value, since we will start cropping the widths if the image's height is 7305030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * not sufficient. 7315030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 7325030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei public float parallaxSpeedMultiplier = 1; 7335030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 7345030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 735df3da61c8f2f54604376d9761649bdba54aa858bMark Wei * Optional field if {@link #FEATURE_STATE_CHANGES} is supported. Must be an opaque color. 7365030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 7375030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * See {@link android.graphics.Color}. 7385030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 7395030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei public int backgroundColor = 0; 7405030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 7415030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 7425d6521e290594fe0851086b0c27413e9709e437fMark Wei * Optional field if {@link #FEATURE_STATE_CHANGES} is supported. 7435d6521e290594fe0851086b0c27413e9709e437fMark Wei * 7445d6521e290594fe0851086b0c27413e9709e437fMark Wei * If you modify this field you must call 7455d6521e290594fe0851086b0c27413e9709e437fMark Wei * {@link ExtendedBitmapDrawable#onOptsChanged(Resources, ExtendedOptions)} on the 7465d6521e290594fe0851086b0c27413e9709e437fMark Wei * appropriate ExtendedBitmapDrawable. 7475030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 7485d6521e290594fe0851086b0c27413e9709e437fMark Wei public Drawable placeholder; 7495030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 7505030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 751c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei * Optional field if {@link #FEATURE_STATE_CHANGES} is supported. 752c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei * 753c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei * Special value 0 means default animation duration. Special value -1 means disable the 754c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei * animation (placeholder will be at maximum alpha always). Any value > 0 defines the 755c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei * duration in milliseconds. 756c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei */ 757c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei public int placeholderAnimationDuration = 0; 758c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei 759c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei /** 7605d6521e290594fe0851086b0c27413e9709e437fMark Wei * Optional field if {@link #FEATURE_STATE_CHANGES} is supported. 7615d6521e290594fe0851086b0c27413e9709e437fMark Wei * 7625d6521e290594fe0851086b0c27413e9709e437fMark Wei * If you modify this field you must call 7635d6521e290594fe0851086b0c27413e9709e437fMark Wei * {@link ExtendedBitmapDrawable#onOptsChanged(Resources, ExtendedOptions)} on the 7645d6521e290594fe0851086b0c27413e9709e437fMark Wei * appropriate ExtendedBitmapDrawable. 7655030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 7665d6521e290594fe0851086b0c27413e9709e437fMark Wei public Drawable progressBar; 7675030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 7685030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 7695030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Use this constructor when all the feature parameters are changeable. 7705030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 7715030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei public ExtendedOptions(final int features) { 7725030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei this(features, null, null); 7735030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 7745030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei 7755030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 7765030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Use this constructor when you have to specify non-changeable feature parameters. 7775030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 7785030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei public ExtendedOptions(final int features, final Drawable placeholder, 7795030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei final Drawable progressBar) { 7805030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei this.features = features; 7815030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei this.placeholder = placeholder; 7825030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei this.progressBar = progressBar; 7835030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 78493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 7855030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei /** 7865030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * Validate this ExtendedOptions instance to make sure that all the required fields are set 7875030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * for the requested features. 7885030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * 7895030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei * This will throw an IllegalStateException if validation fails. 7905030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei */ 7915030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei private void validate() 7925030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei throws IllegalStateException { 7933a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung if (decodeHorizontalCenter < 0 || decodeHorizontalCenter > 1) { 7943a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung throw new IllegalStateException( 7953a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung "ExtendedOptions: decodeHorizontalCenter must be within 0 and 1, " + 7963a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung "inclusive"); 7973a79e2002f9f6114b549c4bc2cc08bb10e75a4d2James Kung } 79889e59f00d67791754e44e65413baa95f94056df4Mark Wei if (decodeVerticalCenter < 0 || decodeVerticalCenter > 1) { 79989e59f00d67791754e44e65413baa95f94056df4Mark Wei throw new IllegalStateException( 80089e59f00d67791754e44e65413baa95f94056df4Mark Wei "ExtendedOptions: decodeVerticalCenter must be within 0 and 1, inclusive"); 80189e59f00d67791754e44e65413baa95f94056df4Mark Wei } 8025030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei if ((features & FEATURE_ORDERED_DISPLAY) != 0 && decodeAggregator == null) { 8035030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei throw new IllegalStateException( 8045030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei "ExtendedOptions: To support FEATURE_ORDERED_DISPLAY, " 8055030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei + "decodeAggregator must be set."); 8065030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 8074a1464aad9c626bd63821697b215a16ee21db824Mark Wei if ((features & FEATURE_PARALLAX) != 0 && parallaxSpeedMultiplier <= 1) { 8085030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei throw new IllegalStateException( 8095030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei "ExtendedOptions: To support FEATURE_PARALLAX, " 8104a1464aad9c626bd63821697b215a16ee21db824Mark Wei + "parallaxSpeedMultiplier must be greater than 1."); 8115030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 812c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei if ((features & FEATURE_STATE_CHANGES) != 0) { 813c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei if (backgroundColor == 0 814c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei && placeholder == null) { 815c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei throw new IllegalStateException( 816c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei "ExtendedOptions: To support FEATURE_STATE_CHANGES, " 817c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei + "either backgroundColor or placeholder must be set."); 818c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei } 819c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei if (placeholderAnimationDuration < -1) { 820c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei throw new IllegalStateException( 821c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei "ExtendedOptions: To support FEATURE_STATE_CHANGES, " 822c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei + "placeholderAnimationDuration must be set correctly."); 823c4ba226c78b8478de6ac8e293d7f9bc64cba36ecMark Wei } 824df3da61c8f2f54604376d9761649bdba54aa858bMark Wei if (backgroundColor != 0 && Color.alpha(backgroundColor) != 255) { 825df3da61c8f2f54604376d9761649bdba54aa858bMark Wei throw new IllegalStateException( 826df3da61c8f2f54604376d9761649bdba54aa858bMark Wei "ExtendedOptions: To support FEATURE_STATE_CHANGES, " 827df3da61c8f2f54604376d9761649bdba54aa858bMark Wei + "backgroundColor must be set to an opaque color."); 828df3da61c8f2f54604376d9761649bdba54aa858bMark Wei } 8295030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 8305030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei } 83193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 83293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein} 833