117993c442c26161f684d6c0c6867a746f3148548Craig Stout/*
217993c442c26161f684d6c0c6867a746f3148548Craig Stout * Copyright (C) 2014 The Android Open Source Project
317993c442c26161f684d6c0c6867a746f3148548Craig Stout *
417993c442c26161f684d6c0c6867a746f3148548Craig Stout * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
517993c442c26161f684d6c0c6867a746f3148548Craig Stout * in compliance with the License. You may obtain a copy of the License at
617993c442c26161f684d6c0c6867a746f3148548Craig Stout *
717993c442c26161f684d6c0c6867a746f3148548Craig Stout * http://www.apache.org/licenses/LICENSE-2.0
817993c442c26161f684d6c0c6867a746f3148548Craig Stout *
917993c442c26161f684d6c0c6867a746f3148548Craig Stout * Unless required by applicable law or agreed to in writing, software distributed under the License
1017993c442c26161f684d6c0c6867a746f3148548Craig Stout * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
1117993c442c26161f684d6c0c6867a746f3148548Craig Stout * or implied. See the License for the specific language governing permissions and limitations under
1217993c442c26161f684d6c0c6867a746f3148548Craig Stout * the License.
1317993c442c26161f684d6c0c6867a746f3148548Craig Stout */
14ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.leanback.app;
1517993c442c26161f684d6c0c6867a746f3148548Craig Stout
163d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stoutimport android.animation.Animator;
177e22f555da71f49a32420965817c760522b95963Craig Stoutimport android.animation.ValueAnimator;
1817993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.app.Activity;
1917993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.content.Context;
207f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.content.res.Resources;
2117993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.content.res.TypedArray;
2217993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.Bitmap;
237f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.graphics.Canvas;
2417993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.Color;
257f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.graphics.ColorFilter;
2617993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.Matrix;
277f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.graphics.Paint;
283103f63e99d47573823957f7aa34308555873221Aurimas Liutikasimport android.graphics.PixelFormat;
2917993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.drawable.ColorDrawable;
3017993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.drawable.Drawable;
3117993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.drawable.LayerDrawable;
32181c8847d5a1169e26755ed690131333b7fff7e9Dake Guimport android.os.Build;
3317993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.os.Handler;
3417993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.util.Log;
3517993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.View;
3617993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.Window;
370f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stoutimport android.view.animation.AnimationUtils;
383103f63e99d47573823957f7aa34308555873221Aurimas Liutikasimport android.view.animation.Interpolator;
393103f63e99d47573823957f7aa34308555873221Aurimas Liutikas
408619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.annotation.ColorInt;
418619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.annotation.NonNull;
428619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.core.content.ContextCompat;
438619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.core.graphics.drawable.DrawableCompat;
448619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.interpolator.view.animation.FastOutLinearInInterpolator;
458619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.leanback.R;
468619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.leanback.widget.BackgroundHelper;
478619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikas
483103f63e99d47573823957f7aa34308555873221Aurimas Liutikasimport java.lang.ref.WeakReference;
4917993c442c26161f684d6c0c6867a746f3148548Craig Stout
5017993c442c26161f684d6c0c6867a746f3148548Craig Stout/**
51146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * Supports background image continuity between multiple Activities.
5217993c442c26161f684d6c0c6867a746f3148548Craig Stout *
53146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>An Activity should instantiate a BackgroundManager and {@link #attach}
54146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * to the Activity's window.  When the Activity is started, the background is
5517993c442c26161f684d6c0c6867a746f3148548Craig Stout * initialized to the current background values stored in a continuity service.
5617993c442c26161f684d6c0c6867a746f3148548Craig Stout * The background continuity service is updated as the background is updated.
5717993c442c26161f684d6c0c6867a746f3148548Craig Stout *
58146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>At some point, for example when it is stopped, the Activity may release
59146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * its background state.
602e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout *
61146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>When an Activity is resumed, if the BackgroundManager has not been
62146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * released, the continuity service is updated from the BackgroundManager state.
63146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * If the BackgroundManager was released, the BackgroundManager inherits the
64146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * current state from the continuity service.
6517993c442c26161f684d6c0c6867a746f3148548Craig Stout *
66146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>When the last Activity is destroyed, the background state is reset.
6717993c442c26161f684d6c0c6867a746f3148548Craig Stout *
68146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>Backgrounds consist of several layers, from back to front:
69146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <ul>
70146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   <li>the background Drawable of the theme</li>
71146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   <li>a solid color (set via {@link #setColor})</li>
72146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   <li>two Drawables, previous and current (set via {@link #setBitmap} or
73146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   {@link #setDrawable}), which may be in transition</li>
74146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * </ul>
7517993c442c26161f684d6c0c6867a746f3148548Craig Stout *
76146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>BackgroundManager holds references to potentially large bitmap Drawables.
77146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * Call {@link #release} to release these references when the Activity is not
7817993c442c26161f684d6c0c6867a746f3148548Craig Stout * visible.
7917993c442c26161f684d6c0c6867a746f3148548Craig Stout */
80146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn// TODO: support for multiple app processes requires a proper android service
81146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn// instead of the shared memory "service" implemented here. Such a service could
82146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn// support continuity between fragments of different applications if desired.
8317993c442c26161f684d6c0c6867a746f3148548Craig Stoutpublic final class BackgroundManager {
84f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
8599ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    static final String TAG = "BackgroundManager";
8699ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    static final boolean DEBUG = false;
8717993c442c26161f684d6c0c6867a746f3148548Craig Stout
8899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    static final int FULL_ALPHA = 255;
8917993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final int CHANGE_BG_DELAY_MS = 500;
903d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout    private static final int FADE_DURATION = 500;
9117993c442c26161f684d6c0c6867a746f3148548Craig Stout
927f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu    private static final String FRAGMENT_TAG = BackgroundManager.class.getCanonicalName();
9317993c442c26161f684d6c0c6867a746f3148548Craig Stout
940908efd712e79f77e0cf9307bd5c32753c855561Dake Gu    Activity mContext;
9599ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    Handler mHandler;
9617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private View mBgView;
9717993c442c26161f684d6c0c6867a746f3148548Craig Stout    private BackgroundContinuityService mService;
9817993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mThemeDrawableResourceId;
99181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    private BackgroundFragment mFragmentState;
100181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    private boolean mAutoReleaseOnStop = true;
10117993c442c26161f684d6c0c6867a746f3148548Craig Stout
10217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mHeightPx;
10317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mWidthPx;
104181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    int mBackgroundColor;
10599ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    Drawable mBackgroundDrawable;
10617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private boolean mAttached;
1070f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private long mLastSetTime;
1080f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
1090f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final Interpolator mAccelerateInterpolator;
1100f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final Interpolator mDecelerateInterpolator;
111181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    final ValueAnimator mAnimator;
11217993c442c26161f684d6c0c6867a746f3148548Craig Stout
113181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    static class BitmapDrawable extends Drawable {
1147f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
115181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        static final class ConstantState extends Drawable.ConstantState {
116181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            final Bitmap mBitmap;
117181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            final Matrix mMatrix;
118181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            final Paint mPaint = new Paint();
119181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
120181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            ConstantState(Bitmap bitmap, Matrix matrix) {
121181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                mBitmap = bitmap;
122181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                mMatrix = matrix != null ? matrix : new Matrix();
123181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                mPaint.setFilterBitmap(true);
124181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            }
125181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
126181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            ConstantState(ConstantState copyFrom) {
127181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                mBitmap = copyFrom.mBitmap;
128181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                mMatrix = copyFrom.mMatrix != null ? new Matrix(copyFrom.mMatrix) : new Matrix();
129181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                if (copyFrom.mPaint.getAlpha() != FULL_ALPHA) {
130181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    mPaint.setAlpha(copyFrom.mPaint.getAlpha());
131181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                }
132181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                if (copyFrom.mPaint.getColorFilter() != null) {
133181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    mPaint.setColorFilter(copyFrom.mPaint.getColorFilter());
134181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                }
135181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                mPaint.setFilterBitmap(true);
136181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            }
1373d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1383d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            @Override
1393d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            public Drawable newDrawable() {
140181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                return new BitmapDrawable(this);
1413d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            }
1423d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1433d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            @Override
1443d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            public int getChangingConfigurations() {
1453d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                return 0;
1463d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            }
1473d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
1483d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
149181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        ConstantState mState;
150181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        boolean mMutated;
1517f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1527f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        BitmapDrawable(Resources resources, Bitmap bitmap) {
1537f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            this(resources, bitmap, null);
1547f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1557f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1567f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        BitmapDrawable(Resources resources, Bitmap bitmap, Matrix matrix) {
157181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            mState = new ConstantState(bitmap, matrix);
158181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        }
159181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
160181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        BitmapDrawable(ConstantState state) {
161181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            mState = state;
1627f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1637f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1647f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        Bitmap getBitmap() {
1653d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            return mState.mBitmap;
1667f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1677f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1687f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1697f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public void draw(Canvas canvas) {
1703d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (mState.mBitmap == null) {
1717f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                return;
1727f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            }
173f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (mState.mPaint.getAlpha() < FULL_ALPHA && mState.mPaint.getColorFilter() != null) {
174f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                throw new IllegalStateException("Can't draw with translucent alpha and color filter");
175f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            }
1763d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            canvas.drawBitmap(mState.mBitmap, mState.mMatrix, mState.mPaint);
1777f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1787f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1797f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1807f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public int getOpacity() {
181d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return android.graphics.PixelFormat.TRANSLUCENT;
1827f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1837f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1847f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1857f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public void setAlpha(int alpha) {
186181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            mutate();
1873d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (mState.mPaint.getAlpha() != alpha) {
1883d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                mState.mPaint.setAlpha(alpha);
1897f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                invalidateSelf();
1907f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            }
1917f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1927f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
193f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        /**
194f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout         * Does not invalidateSelf to avoid recursion issues.
195f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout         * Caller must ensure appropriate invalidation.
196f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout         */
1977f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1987f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public void setColorFilter(ColorFilter cf) {
199181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            mutate();
200f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mState.mPaint.setColorFilter(cf);
201181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            invalidateSelf();
202f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
203f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
204e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas        @Override
205f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        public ColorFilter getColorFilter() {
206f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            return mState.mPaint.getColorFilter();
2077f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
2083d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
2093d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        @Override
2103d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        public ConstantState getConstantState() {
2113d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            return mState;
2123d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
213181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
214181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        @NonNull
215181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        @Override
216181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        public Drawable mutate() {
217181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            if (!mMutated) {
218181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                mMutated = true;
219181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                mState = new ConstantState(mState);
220181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            }
221181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            return this;
222181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        }
2237f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    }
2247f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
225181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    static final class DrawableWrapper {
226181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        int mAlpha = FULL_ALPHA;
227181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        final Drawable mDrawable;
2287e22f555da71f49a32420965817c760522b95963Craig Stout
22917993c442c26161f684d6c0c6867a746f3148548Craig Stout        public DrawableWrapper(Drawable drawable) {
23017993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = drawable;
231d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
232d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public DrawableWrapper(DrawableWrapper wrapper, Drawable drawable) {
233d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mDrawable = drawable;
234181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            mAlpha = wrapper.mAlpha;
23517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
236f36902ae811a12506f54faa261cb653f45a27612Craig Stout
23717993c442c26161f684d6c0c6867a746f3148548Craig Stout        public Drawable getDrawable() {
23817993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mDrawable;
23917993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
240f36902ae811a12506f54faa261cb653f45a27612Craig Stout
24117993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setColor(int color) {
24217993c442c26161f684d6c0c6867a746f3148548Craig Stout            ((ColorDrawable) mDrawable).setColor(color);
24317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
24417993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
24517993c442c26161f684d6c0c6867a746f3148548Craig Stout
246181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    static final class TranslucentLayerDrawable extends LayerDrawable {
247181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        DrawableWrapper[] mWrapper;
248181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        int mAlpha = FULL_ALPHA;
249181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        boolean mSuspendInvalidation;
2506be5511d17efdbb935e2a025337834fc698ce723Dake Gu        WeakReference<BackgroundManager> mManagerWeakReference;
251d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
2526be5511d17efdbb935e2a025337834fc698ce723Dake Gu        TranslucentLayerDrawable(BackgroundManager manager, Drawable[] drawables) {
253d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            super(drawables);
2546be5511d17efdbb935e2a025337834fc698ce723Dake Gu            mManagerWeakReference = new WeakReference(manager);
255d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            int count = drawables.length;
256d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mWrapper = new DrawableWrapper[count];
257d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < count; i++) {
258d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                mWrapper[i] = new DrawableWrapper(drawables[i]);
259d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
260d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
261d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
262d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
263d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public void setAlpha(int alpha) {
2646be5511d17efdbb935e2a025337834fc698ce723Dake Gu            if (mAlpha != alpha) {
2656be5511d17efdbb935e2a025337834fc698ce723Dake Gu                mAlpha = alpha;
2666be5511d17efdbb935e2a025337834fc698ce723Dake Gu                invalidateSelf();
2676be5511d17efdbb935e2a025337834fc698ce723Dake Gu                BackgroundManager manager = mManagerWeakReference.get();
2686be5511d17efdbb935e2a025337834fc698ce723Dake Gu                if (manager != null) {
2696be5511d17efdbb935e2a025337834fc698ce723Dake Gu                    manager.postChangeRunnable();
2706be5511d17efdbb935e2a025337834fc698ce723Dake Gu                }
2716be5511d17efdbb935e2a025337834fc698ce723Dake Gu            }
272181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        }
273181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
274181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        void setWrapperAlpha(int wrapperIndex, int alpha) {
275181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            if (mWrapper[wrapperIndex] != null) {
276181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                mWrapper[wrapperIndex].mAlpha = alpha;
277d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                invalidateSelf();
278d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
279d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
280d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
2812590c39739945451f80dcf8667709b93293fc8bcCraig Stout        // Queried by system transitions
282e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas        @Override
2832590c39739945451f80dcf8667709b93293fc8bcCraig Stout        public int getAlpha() {
284181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            return mAlpha;
285f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
286f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
287d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
288d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public Drawable mutate() {
289d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            Drawable drawable = super.mutate();
290d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            int count = getNumberOfLayers();
291d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < count; i++) {
292d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (mWrapper[i] != null) {
293d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    mWrapper[i] = new DrawableWrapper(mWrapper[i], getDrawable(i));
294d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                }
295d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
296d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return drawable;
297d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
298d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
299d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
300d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public int getOpacity() {
301d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return PixelFormat.TRANSLUCENT;
302d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
303d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
304d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
305d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public boolean setDrawableByLayerId(int id, Drawable drawable) {
306d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return updateDrawable(id, drawable) != null;
307d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
308d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
309d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public DrawableWrapper updateDrawable(int id, Drawable drawable) {
310d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            super.setDrawableByLayerId(id, drawable);
311d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < getNumberOfLayers(); i++) {
312d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (getId(i) == id) {
313d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    mWrapper[i] = new DrawableWrapper(drawable);
314f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                    // Must come after mWrapper was updated so it can be seen by updateColorFilter
315f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                    invalidateSelf();
316d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    return mWrapper[i];
317d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                }
318d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
319d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return null;
320d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
321d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
322d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public void clearDrawable(int id, Context context) {
323d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < getNumberOfLayers(); i++) {
324d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (getId(i) == id) {
325d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    mWrapper[i] = null;
326181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    if (!(getDrawable(i) instanceof EmptyDrawable)) {
327181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        super.setDrawableByLayerId(id, createEmptyDrawable(context));
328181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    }
329d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    break;
330d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                }
331d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
332d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
333d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
334181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        public int findWrapperIndexById(int id) {
335d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < getNumberOfLayers(); i++) {
336d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (getId(i) == id) {
337181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    return i;
338d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                }
339d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
340181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            return -1;
341f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
342f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
343f36902ae811a12506f54faa261cb653f45a27612Craig Stout        @Override
344f36902ae811a12506f54faa261cb653f45a27612Craig Stout        public void invalidateDrawable(Drawable who) {
345181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            // Prevent invalidate when temporarily change child drawable's alpha in draw()
346181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            if (!mSuspendInvalidation) {
347181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                super.invalidateDrawable(who);
348f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            }
349f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
350f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
351f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        @Override
352f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        public void draw(Canvas canvas) {
353181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            for (int i = 0; i < mWrapper.length; i++) {
354181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                final Drawable d;
355181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                // For each child drawable, we multiple Wrapper's alpha and LayerDrawable's alpha
356181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                // temporarily using mSuspendInvalidation to suppress invalidate event.
357181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                if (mWrapper[i] != null && (d = mWrapper[i].getDrawable()) != null) {
358181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    int alpha = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
359181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                            ? DrawableCompat.getAlpha(d) : FULL_ALPHA;
360181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    final int savedAlpha = alpha;
361181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    int multiple = 0;
362181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    if (mAlpha < FULL_ALPHA) {
363181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        alpha = alpha * mAlpha;
364181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        multiple++;
365181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    }
366181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    if (mWrapper[i].mAlpha < FULL_ALPHA) {
367181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        alpha = alpha * mWrapper[i].mAlpha;
368181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        multiple++;
369181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    }
370181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    if (multiple == 0) {
371181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        d.draw(canvas);
372181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    } else {
373181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        if (multiple == 1) {
374181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                            alpha = alpha / FULL_ALPHA;
375181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        } else if (multiple == 2) {
376181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                            alpha = alpha / (FULL_ALPHA * FULL_ALPHA);
377181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        }
378181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        try {
379181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                            mSuspendInvalidation = true;
380181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                            d.setAlpha(alpha);
381181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                            d.draw(canvas);
382181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                            d.setAlpha(savedAlpha);
383181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        } finally {
384181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                            mSuspendInvalidation = false;
385181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        }
386181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    }
387181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                }
388f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            }
389f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
390f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    }
391f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
392181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    TranslucentLayerDrawable createTranslucentLayerDrawable(
393f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            LayerDrawable layerDrawable) {
394f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        int numChildren = layerDrawable.getNumberOfLayers();
395f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        Drawable[] drawables = new Drawable[numChildren];
396f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        for (int i = 0; i < numChildren; i++) {
397f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            drawables[i] = layerDrawable.getDrawable(i);
398f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
3996be5511d17efdbb935e2a025337834fc698ce723Dake Gu        TranslucentLayerDrawable result = new TranslucentLayerDrawable(this, drawables);
400f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        for (int i = 0; i < numChildren; i++) {
401f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            result.setId(i, layerDrawable.getId(i));
402f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
403f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        return result;
404f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    }
405f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
40699ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    TranslucentLayerDrawable mLayerDrawable;
407181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    int mImageInWrapperIndex;
408181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    int mImageOutWrapperIndex;
40999ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    ChangeBackgroundRunnable mChangeRunnable;
410f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    private boolean mChangeRunnablePending;
41117993c442c26161f684d6c0c6867a746f3148548Craig Stout
4120f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final Animator.AnimatorListener mAnimationListener = new Animator.AnimatorListener() {
413f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        final Runnable mRunnable = new Runnable() {
414f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            @Override
415f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            public void run() {
416f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                postChangeRunnable();
417f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            }
418f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        };
419f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
4200f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
4210f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationStart(Animator animation) {
4220f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
4230f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
4240f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationRepeat(Animator animation) {
4250f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
4260f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
4270f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationEnd(Animator animation) {
428f988bc054a2e0ccefacd8c76cbcf47a1ab88e6b1Craig Stout            if (mLayerDrawable != null) {
429f988bc054a2e0ccefacd8c76cbcf47a1ab88e6b1Craig Stout                mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
430f988bc054a2e0ccefacd8c76cbcf47a1ab88e6b1Craig Stout            }
431f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mHandler.post(mRunnable);
4320f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
4330f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
4340f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationCancel(Animator animation) {
4350f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
4360f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    };
4370f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
4380f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final ValueAnimator.AnimatorUpdateListener mAnimationUpdateListener =
4390f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            new ValueAnimator.AnimatorUpdateListener() {
4400f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
4410f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationUpdate(ValueAnimator animation) {
4420f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            int fadeInAlpha = (Integer) animation.getAnimatedValue();
443181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            if (mImageInWrapperIndex != -1) {
444181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                mLayerDrawable.setWrapperAlpha(mImageInWrapperIndex, fadeInAlpha);
4450f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            }
4460f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
4470f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    };
4480f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
44917993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
45017993c442c26161f684d6c0c6867a746f3148548Craig Stout     * Shared memory continuity service.
45117993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
45217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static class BackgroundContinuityService {
453181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        private static final String TAG = "BackgroundContinuity";
454f8a82a95a1a962ec05536f7196fcee0f1384a497Jake Wharton        private static final boolean DEBUG = BackgroundManager.DEBUG;
45517993c442c26161f684d6c0c6867a746f3148548Craig Stout
45617993c442c26161f684d6c0c6867a746f3148548Craig Stout        private static BackgroundContinuityService sService = new BackgroundContinuityService();
45717993c442c26161f684d6c0c6867a746f3148548Craig Stout
45817993c442c26161f684d6c0c6867a746f3148548Craig Stout        private int mColor;
45917993c442c26161f684d6c0c6867a746f3148548Craig Stout        private Drawable mDrawable;
46017993c442c26161f684d6c0c6867a746f3148548Craig Stout        private int mCount;
46117993c442c26161f684d6c0c6867a746f3148548Craig Stout
46260c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        /** Single cache of theme drawable */
46360c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        private int mLastThemeDrawableId;
464363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout        private WeakReference<Drawable.ConstantState> mLastThemeDrawableState;
46560c3b420827d0520509387f1abe3e3d8168e2279Dake Gu
46617993c442c26161f684d6c0c6867a746f3148548Craig Stout        private BackgroundContinuityService() {
46717993c442c26161f684d6c0c6867a746f3148548Craig Stout            reset();
46817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
46917993c442c26161f684d6c0c6867a746f3148548Craig Stout
47017993c442c26161f684d6c0c6867a746f3148548Craig Stout        private void reset() {
47117993c442c26161f684d6c0c6867a746f3148548Craig Stout            mColor = Color.TRANSPARENT;
47217993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = null;
47317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
47417993c442c26161f684d6c0c6867a746f3148548Craig Stout
47517993c442c26161f684d6c0c6867a746f3148548Craig Stout        public static BackgroundContinuityService getInstance() {
47617993c442c26161f684d6c0c6867a746f3148548Craig Stout            final int count = sService.mCount++;
47717993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "Returning instance with new count " + count);
47817993c442c26161f684d6c0c6867a746f3148548Craig Stout            return sService;
47917993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
48017993c442c26161f684d6c0c6867a746f3148548Craig Stout
48117993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void unref() {
48217993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (mCount <= 0) throw new IllegalStateException("Can't unref, count " + mCount);
48317993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (--mCount == 0) {
48417993c442c26161f684d6c0c6867a746f3148548Craig Stout                if (DEBUG) Log.v(TAG, "mCount is zero, resetting");
48517993c442c26161f684d6c0c6867a746f3148548Craig Stout                reset();
48617993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
48717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
48817993c442c26161f684d6c0c6867a746f3148548Craig Stout        public int getColor() {
48917993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mColor;
49017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
49117993c442c26161f684d6c0c6867a746f3148548Craig Stout        public Drawable getDrawable() {
49217993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mDrawable;
49317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
49417993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setColor(int color) {
49517993c442c26161f684d6c0c6867a746f3148548Craig Stout            mColor = color;
496181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            mDrawable = null;
49717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
49817993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setDrawable(Drawable drawable) {
49917993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = drawable;
50017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
50160c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        public Drawable getThemeDrawable(Context context, int themeDrawableId) {
50260c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            Drawable drawable = null;
503363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout            if (mLastThemeDrawableState != null && mLastThemeDrawableId == themeDrawableId) {
504363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                Drawable.ConstantState drawableState = mLastThemeDrawableState.get();
505363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                if (DEBUG) Log.v(TAG, "got cached theme drawable state " + drawableState);
506363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                if (drawableState != null) {
507363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                    drawable = drawableState.newDrawable();
508363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                }
50960c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            }
51060c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            if (drawable == null) {
51160c3b420827d0520509387f1abe3e3d8168e2279Dake Gu                drawable = ContextCompat.getDrawable(context, themeDrawableId);
512363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                if (DEBUG) Log.v(TAG, "loaded theme drawable " + drawable);
513363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                mLastThemeDrawableState = new WeakReference<Drawable.ConstantState>(
514363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                        drawable.getConstantState());
51560c3b420827d0520509387f1abe3e3d8168e2279Dake Gu                mLastThemeDrawableId = themeDrawableId;
51660c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            }
517459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout            // No mutate required because this drawable is never manipulated.
518459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout            return drawable;
51960c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        }
52017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
52117993c442c26161f684d6c0c6867a746f3148548Craig Stout
522181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    Drawable getDefaultDrawable() {
523181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        if (mBackgroundColor != Color.TRANSPARENT) {
524181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            return new ColorDrawable(mBackgroundColor);
525181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        } else {
526181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            return getThemeDrawable();
527181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        }
528181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    }
529181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
53017993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Drawable getThemeDrawable() {
53117993c442c26161f684d6c0c6867a746f3148548Craig Stout        Drawable drawable = null;
53217993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mThemeDrawableResourceId != -1) {
53360c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            drawable = mService.getThemeDrawable(mContext, mThemeDrawableResourceId);
53417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
53517993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (drawable == null) {
536d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            drawable = createEmptyDrawable(mContext);
53717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
53817993c442c26161f684d6c0c6867a746f3148548Craig Stout        return drawable;
53917993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
54017993c442c26161f684d6c0c6867a746f3148548Craig Stout
54117993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
542a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Returns the BackgroundManager associated with the given Activity.
5437f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu     * <p>
544146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * The BackgroundManager will be created on-demand for each individual
545146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Activity. Subsequent calls will return the same BackgroundManager created
546146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * for this Activity.
5477f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu     */
5487f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu    public static BackgroundManager getInstance(Activity activity) {
5497f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
5507f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                .findFragmentByTag(FRAGMENT_TAG);
5517f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        if (fragment != null) {
5527f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            BackgroundManager manager = fragment.getBackgroundManager();
5537f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            if (manager != null) {
5547f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                return manager;
5557f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            }
5567f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            // manager is null: this is a fragment restored by FragmentManager,
5577f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            // fall through to create a BackgroundManager attach to it.
5587f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        }
559be542c8fdb736143369ea8b2ca5cb9ab76282e04Dake Gu        return new BackgroundManager(activity);
5607f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu    }
5617f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu
562be542c8fdb736143369ea8b2ca5cb9ab76282e04Dake Gu    private BackgroundManager(Activity activity) {
56317993c442c26161f684d6c0c6867a746f3148548Craig Stout        mContext = activity;
56417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mService = BackgroundContinuityService.getInstance();
56517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mHeightPx = mContext.getResources().getDisplayMetrics().heightPixels;
56617993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWidthPx = mContext.getResources().getDisplayMetrics().widthPixels;
56717993c442c26161f684d6c0c6867a746f3148548Craig Stout        mHandler = new Handler();
56817993c442c26161f684d6c0c6867a746f3148548Craig Stout
5690f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        Interpolator defaultInterpolator = new FastOutLinearInInterpolator();
5700f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAccelerateInterpolator = AnimationUtils.loadInterpolator(mContext,
5710f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                android.R.anim.accelerate_interpolator);
5720f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mDecelerateInterpolator = AnimationUtils.loadInterpolator(mContext,
5730f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                android.R.anim.decelerate_interpolator);
5740f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
5750f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator = ValueAnimator.ofInt(0, FULL_ALPHA);
5760f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.addListener(mAnimationListener);
5770f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.addUpdateListener(mAnimationUpdateListener);
5780f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.setInterpolator(defaultInterpolator);
5790f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
58017993c442c26161f684d6c0c6867a746f3148548Craig Stout        TypedArray ta = activity.getTheme().obtainStyledAttributes(new int[] {
58117993c442c26161f684d6c0c6867a746f3148548Craig Stout                android.R.attr.windowBackground });
58217993c442c26161f684d6c0c6867a746f3148548Craig Stout        mThemeDrawableResourceId = ta.getResourceId(0, -1);
58317993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mThemeDrawableResourceId < 0) {
58417993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "BackgroundManager no window background resource!");
58517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
58617993c442c26161f684d6c0c6867a746f3148548Craig Stout        ta.recycle();
58717993c442c26161f684d6c0c6867a746f3148548Craig Stout
588be542c8fdb736143369ea8b2ca5cb9ab76282e04Dake Gu        createFragment(activity);
58917993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
59017993c442c26161f684d6c0c6867a746f3148548Craig Stout
59117993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void createFragment(Activity activity) {
59217993c442c26161f684d6c0c6867a746f3148548Craig Stout        // Use a fragment to ensure the background manager gets detached properly.
593b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu        BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
5947f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                .findFragmentByTag(FRAGMENT_TAG);
595b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu        if (fragment == null) {
596b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu            fragment = new BackgroundFragment();
5977f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            activity.getFragmentManager().beginTransaction().add(fragment, FRAGMENT_TAG).commit();
5987f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        } else {
5997f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            if (fragment.getBackgroundManager() != null) {
6003103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                throw new IllegalStateException("Created duplicated BackgroundManager for same "
6013103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                        + "activity, please use getInstance() instead");
602fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            }
603fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        }
604fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        fragment.setBackgroundManager(this);
605f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        mFragmentState = fragment;
606fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu    }
607fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu
60899ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    DrawableWrapper getImageInWrapper() {
6093103f63e99d47573823957f7aa34308555873221Aurimas Liutikas        return mLayerDrawable == null
610181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                ? null : mLayerDrawable.mWrapper[mImageInWrapperIndex];
6112590c39739945451f80dcf8667709b93293fc8bcCraig Stout    }
6122590c39739945451f80dcf8667709b93293fc8bcCraig Stout
61399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    DrawableWrapper getImageOutWrapper() {
6143103f63e99d47573823957f7aa34308555873221Aurimas Liutikas        return mLayerDrawable == null
615181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                ? null : mLayerDrawable.mWrapper[mImageOutWrapperIndex];
6162590c39739945451f80dcf8667709b93293fc8bcCraig Stout    }
6172590c39739945451f80dcf8667709b93293fc8bcCraig Stout
61817993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
619f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout     * Synchronizes state when the owning Activity is started.
620f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout     * At that point the view becomes visible.
62117993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
622f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    void onActivityStart() {
623181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        updateImmediate();
624181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    }
625181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
626181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    void onStop() {
627181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        if (isAutoReleaseOnStop()) {
628181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            release();
6292e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        }
63017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
63117993c442c26161f684d6c0c6867a746f3148548Craig Stout
632f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    void onResume() {
633f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        if (DEBUG) Log.v(TAG, "onResume " + this);
634f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        postChangeRunnable();
635f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    }
636f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
63717993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void syncWithService() {
63817993c442c26161f684d6c0c6867a746f3148548Craig Stout        int color = mService.getColor();
63917993c442c26161f684d6c0c6867a746f3148548Craig Stout        Drawable drawable = mService.getDrawable();
64017993c442c26161f684d6c0c6867a746f3148548Craig Stout
64117993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "syncWithService color " + Integer.toHexString(color)
64217993c442c26161f684d6c0c6867a746f3148548Craig Stout                + " drawable " + drawable);
64317993c442c26161f684d6c0c6867a746f3148548Craig Stout
64417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBackgroundColor = color;
6453d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        mBackgroundDrawable = drawable == null ? null :
6463d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            drawable.getConstantState().newDrawable().mutate();
6472e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
6482e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        updateImmediate();
64917993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
65017993c442c26161f684d6c0c6867a746f3148548Craig Stout
65117993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
6524702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Makes the background visible on the given Window. The background manager must be attached
6530f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * when the background is set.
65417993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
65517993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void attach(Window window) {
6560908efd712e79f77e0cf9307bd5c32753c855561Dake Gu        attachToViewInternal(window.getDecorView());
65717993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
65817993c442c26161f684d6c0c6867a746f3148548Craig Stout
659459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout    /**
660459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout     * Sets the resource id for the drawable to be shown when there is no background set.
661459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout     * Overrides the window background drawable from the theme. This should
662459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout     * be called before attaching.
663459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout     */
664459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout    public void setThemeDrawableResourceId(int resourceId) {
665459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout        mThemeDrawableResourceId = resourceId;
666459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout    }
667459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout
6684702556bfd15c9819a7b2af759aee0f719cd631fsusnata    /**
6694702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Adds the composite drawable to the given view.
6704702556bfd15c9819a7b2af759aee0f719cd631fsusnata     */
6714702556bfd15c9819a7b2af759aee0f719cd631fsusnata    public void attachToView(View sceneRoot) {
6720908efd712e79f77e0cf9307bd5c32753c855561Dake Gu        attachToViewInternal(sceneRoot);
67311e04bce2e1bf30011dff2ea2406c0dd89be83a3Dake Gu        // clear background to reduce overdraw since the View will act as background.
67411e04bce2e1bf30011dff2ea2406c0dd89be83a3Dake Gu        // Activity transition below O has ghost effect for null window background where we
67511e04bce2e1bf30011dff2ea2406c0dd89be83a3Dake Gu        // need set a transparent background to force redraw the whole window.
67611e04bce2e1bf30011dff2ea2406c0dd89be83a3Dake Gu        mContext.getWindow().getDecorView().setBackground(
6777301f0cca4f9dc9249cd660c05d5b2107f5b3d04Aurimas Liutikas                Build.VERSION.SDK_INT >= 26 ? null : new ColorDrawable(Color.TRANSPARENT));
6780908efd712e79f77e0cf9307bd5c32753c855561Dake Gu    }
6790908efd712e79f77e0cf9307bd5c32753c855561Dake Gu
6800908efd712e79f77e0cf9307bd5c32753c855561Dake Gu    void attachToViewInternal(View sceneRoot) {
681181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        if (mAttached) {
682181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            throw new IllegalStateException("Already attached to " + mBgView);
683181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        }
68417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBgView = sceneRoot;
68517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mAttached = true;
6862e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        syncWithService();
68717993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
68817993c442c26161f684d6c0c6867a746f3148548Craig Stout
68917993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
6900f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Returns true if the background manager is currently attached; false otherwise.
6910f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     */
6920f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    public boolean isAttached() {
6930f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        return mAttached;
6940f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
6950f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
6960f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    /**
697146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Release references to Drawables and put the BackgroundManager into the
698146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * detached state. Called when the associated Activity is destroyed.
69917993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
70017993c442c26161f684d6c0c6867a746f3148548Craig Stout    void detach() {
7013d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        if (DEBUG) Log.v(TAG, "detach " + this);
70217993c442c26161f684d6c0c6867a746f3148548Craig Stout        release();
70317993c442c26161f684d6c0c6867a746f3148548Craig Stout
70417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBgView = null;
70517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mAttached = false;
70617993c442c26161f684d6c0c6867a746f3148548Craig Stout
70717993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mService != null) {
70817993c442c26161f684d6c0c6867a746f3148548Craig Stout            mService.unref();
70917993c442c26161f684d6c0c6867a746f3148548Craig Stout            mService = null;
71017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
71117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
71217993c442c26161f684d6c0c6867a746f3148548Craig Stout
71317993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
714181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * Release references to Drawable/Bitmap. Typically called in Activity onStop() to reduce memory
715181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * overhead when not visible. It's app's responsibility to restore the drawable/bitmap in
716181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * Activity onStart(). The method is automatically called in onStop() when
717181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * {@link #isAutoReleaseOnStop()} is true.
718181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * @see #setAutoReleaseOnStop(boolean)
71917993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
72017993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void release() {
7213d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        if (DEBUG) Log.v(TAG, "release " + this);
72292d8453dfc8ee5153e5d207618c4555d0a14e8f7Kazuki Nara        if (mChangeRunnable != null) {
72392d8453dfc8ee5153e5d207618c4555d0a14e8f7Kazuki Nara            mHandler.removeCallbacks(mChangeRunnable);
72492d8453dfc8ee5153e5d207618c4555d0a14e8f7Kazuki Nara            mChangeRunnable = null;
72592d8453dfc8ee5153e5d207618c4555d0a14e8f7Kazuki Nara        }
72692d8453dfc8ee5153e5d207618c4555d0a14e8f7Kazuki Nara        if (mAnimator.isStarted()) {
72792d8453dfc8ee5153e5d207618c4555d0a14e8f7Kazuki Nara            mAnimator.cancel();
72892d8453dfc8ee5153e5d207618c4555d0a14e8f7Kazuki Nara        }
7292e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        if (mLayerDrawable != null) {
730d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mLayerDrawable.clearDrawable(R.id.background_imagein, mContext);
731d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
7322e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mLayerDrawable = null;
7332e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        }
73417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBackgroundDrawable = null;
73517993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
73617993c442c26161f684d6c0c6867a746f3148548Craig Stout
7370f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    /**
7380f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Sets the drawable used as a dim layer.
739181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * @deprecated No longer support dim layer.
7400f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     */
741181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    @Deprecated
7420f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    public void setDimLayer(Drawable drawable) {
7430f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
7440f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
7450f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    /**
7460f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Returns the drawable used as a dim layer.
747181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * @deprecated No longer support dim layer.
7480f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     */
749181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    @Deprecated
7500f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    public Drawable getDimLayer() {
751181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        return null;
7520f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
7530f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
7540f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    /**
7550f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Returns the default drawable used as a dim layer.
756181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * @deprecated No longer support dim layer.
7570f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     */
758181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    @Deprecated
7590f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    public Drawable getDefaultDimLayer() {
7600f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        return ContextCompat.getDrawable(mContext, R.color.lb_background_protection);
7610f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
7620f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
76399ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    void postChangeRunnable() {
764f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        if (mChangeRunnable == null || !mChangeRunnablePending) {
765f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            return;
766f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
767f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
768f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // Postpone a pending change runnable until: no existing change animation in progress &&
769f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // activity is resumed (in the foreground) && layerdrawable fully opaque.
770f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // If the layerdrawable is translucent then an activity transition is in progress
771f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // and we want to use the optimized drawing path for performance reasons (see
772f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // OptimizedTranslucentLayerDrawable).
773f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        if (mAnimator.isStarted()) {
774f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (DEBUG) Log.v(TAG, "animation in progress");
775f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        } else if (!mFragmentState.isResumed()) {
776f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (DEBUG) Log.v(TAG, "not resumed");
777f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        } else if (mLayerDrawable.getAlpha() < FULL_ALPHA) {
778f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (DEBUG) Log.v(TAG, "in transition, alpha " + mLayerDrawable.getAlpha());
779f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        } else {
780f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            long delayMs = getRunnableDelay();
781f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (DEBUG) Log.v(TAG, "posting runnable delayMs " + delayMs);
782f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mLastSetTime = System.currentTimeMillis();
783f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mHandler.postDelayed(mChangeRunnable, delayMs);
784f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mChangeRunnablePending = false;
785f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
786f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    }
787f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
788181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    private void lazyInit() {
789181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        if (mLayerDrawable != null) {
790181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            return;
7912590c39739945451f80dcf8667709b93293fc8bcCraig Stout        }
792181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
793181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        LayerDrawable layerDrawable = (LayerDrawable)
794181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                ContextCompat.getDrawable(mContext, R.drawable.lb_background).mutate();
795181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        mLayerDrawable = createTranslucentLayerDrawable(layerDrawable);
796181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        mImageInWrapperIndex = mLayerDrawable.findWrapperIndexById(R.id.background_imagein);
797181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        mImageOutWrapperIndex = mLayerDrawable.findWrapperIndexById(R.id.background_imageout);
798181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        BackgroundHelper.setBackgroundPreservingAlpha(mBgView, mLayerDrawable);
799181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    }
800181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
801181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    private void updateImmediate() {
802181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        if (!mAttached) {
803181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            return;
80417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
805181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        lazyInit();
80617993c442c26161f684d6c0c6867a746f3148548Craig Stout
80717993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mBackgroundDrawable == null) {
808181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            if (DEBUG) Log.v(TAG, "Use defefault background");
809181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            mLayerDrawable.updateDrawable(R.id.background_imagein, getDefaultDrawable());
81017993c442c26161f684d6c0c6867a746f3148548Craig Stout        } else {
811181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            if (DEBUG) Log.v(TAG, "Background drawable is available " + mBackgroundDrawable);
812181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            mLayerDrawable.updateDrawable(R.id.background_imagein, mBackgroundDrawable);
81317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
814181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
81517993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
81617993c442c26161f684d6c0c6867a746f3148548Craig Stout
81717993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
818a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the background to the given color. The timing for when this becomes
819146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * visible in the app is undefined and may take place after a small delay.
82017993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
82170acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye    public void setColor(@ColorInt int color) {
82217993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "setColor " + Integer.toHexString(color));
82317993c442c26161f684d6c0c6867a746f3148548Craig Stout
824181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        mService.setColor(color);
82517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBackgroundColor = color;
826181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        mBackgroundDrawable = null;
827181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        if (mLayerDrawable == null) {
828181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            return;
82917993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
830181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        setDrawableInternal(getDefaultDrawable());
83117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
83217993c442c26161f684d6c0c6867a746f3148548Craig Stout
83317993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
834a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the given drawable into the background. The provided Drawable will be
8355a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * used unmodified as the background, without any scaling or cropping
8365a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * applied to it. The timing for when this becomes visible in the app is
8375a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * undefined and may take place after a small delay.
83817993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
83917993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void setDrawable(Drawable drawable) {
84017993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "setBackgroundDrawable " + drawable);
841181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
842181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        mService.setDrawable(drawable);
843181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        mBackgroundDrawable = drawable;
844181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        if (mLayerDrawable == null) {
845181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            return;
846181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        }
847181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        if (drawable == null) {
848181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            setDrawableInternal(getDefaultDrawable());
849181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        } else {
850181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            setDrawableInternal(drawable);
851181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        }
852181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    }
853181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
854181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    /**
855181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * Clears the Drawable set by {@link #setDrawable(Drawable)} or {@link #setBitmap(Bitmap)}.
856181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * BackgroundManager will show a solid color set by {@link #setColor(int)} or theme drawable
857181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * if color is not provided.
858181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     */
859181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    public void clearDrawable() {
860181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        setDrawable(null);
86117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
86217993c442c26161f684d6c0c6867a746f3148548Craig Stout
86317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void setDrawableInternal(Drawable drawable) {
8645a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        if (!mAttached) {
8655a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            throw new IllegalStateException("Must attach before setting background drawable");
8665a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        }
86717993c442c26161f684d6c0c6867a746f3148548Craig Stout
86817993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mChangeRunnable != null) {
869d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout            if (sameDrawable(drawable, mChangeRunnable.mDrawable)) {
8700f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                if (DEBUG) Log.v(TAG, "new drawable same as pending");
871d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout                return;
872d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout            }
8730f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mHandler.removeCallbacks(mChangeRunnable);
874f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mChangeRunnable = null;
87517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
876d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
87717993c442c26161f684d6c0c6867a746f3148548Craig Stout        mChangeRunnable = new ChangeBackgroundRunnable(drawable);
878f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        mChangeRunnablePending = true;
87917993c442c26161f684d6c0c6867a746f3148548Craig Stout
880f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        postChangeRunnable();
88117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
88217993c442c26161f684d6c0c6867a746f3148548Craig Stout
8830f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private long getRunnableDelay() {
8840f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        return Math.max(0, mLastSetTime + CHANGE_BG_DELAY_MS - System.currentTimeMillis());
8850f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
8860f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
88717993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
8884702556bfd15c9819a7b2af759aee0f719cd631fsusnata     * Sets the given bitmap into the background. When using setCoverImageBitmap to set the
8895a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * background, the provided bitmap will be scaled and cropped to correctly
8905a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * fit within the dimensions of the view. The timing for when this becomes
891146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * visible in the app is undefined and may take place after a small delay.
89217993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
89317993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void setBitmap(Bitmap bitmap) {
8945a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        if (DEBUG) {
8954702556bfd15c9819a7b2af759aee0f719cd631fsusnata            Log.v(TAG, "setCoverImageBitmap " + bitmap);
8965a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        }
8975a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
8985a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        if (bitmap == null) {
899181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            setDrawable(null);
9005a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            return;
9015a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        }
90217993c442c26161f684d6c0c6867a746f3148548Craig Stout
90317993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
9045a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            if (DEBUG) {
9055a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima                Log.v(TAG, "invalid bitmap width or height");
9065a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            }
90717993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
90817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
90917993c442c26161f684d6c0c6867a746f3148548Craig Stout
9107f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        Matrix matrix = null;
91117993c442c26161f684d6c0c6867a746f3148548Craig Stout
9127f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if ((bitmap.getWidth() != mWidthPx || bitmap.getHeight() != mHeightPx)) {
9135a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            int dwidth = bitmap.getWidth();
9145a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            int dheight = bitmap.getHeight();
9155a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            float scale;
9165a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
9177f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            // Scale proportionately to fit width and height.
9185a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            if (dwidth * mHeightPx > mWidthPx * dheight) {
9195a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima                scale = (float) mHeightPx / (float) dheight;
9205a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            } else {
9215a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima                scale = (float) mWidthPx / (float) dwidth;
9225a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            }
9235a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
9245a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            int subX = Math.min((int) (mWidthPx / scale), dwidth);
9257f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            int dx = Math.max(0, (dwidth - subX) / 2);
9265a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
9277f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            matrix = new Matrix();
9287f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            matrix.setScale(scale, scale);
9297f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            matrix.preTranslate(-dx, 0);
9307f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
9313103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            if (DEBUG) {
9323103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                Log.v(TAG, "original image size " + bitmap.getWidth() + "x" + bitmap.getHeight()
9333103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                        + " scale " + scale + " dx " + dx);
9343103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            }
93517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
93617993c442c26161f684d6c0c6867a746f3148548Craig Stout
9377f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap, matrix);
93817993c442c26161f684d6c0c6867a746f3148548Craig Stout
939181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        setDrawable(bitmapDrawable);
94017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
94117993c442c26161f684d6c0c6867a746f3148548Craig Stout
942181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    /**
943181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * Enable or disable call release() in Activity onStop(). Default is true.
944181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * @param autoReleaseOnStop True to call release() in Activity onStop(), false otherwise.
945181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     */
946181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    public void setAutoReleaseOnStop(boolean autoReleaseOnStop) {
947181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        mAutoReleaseOnStop = autoReleaseOnStop;
948181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    }
9490f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
950181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    /**
951181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     * @return True if release() in Activity.onStop(), false otherwise.
952181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu     */
953181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    public boolean isAutoReleaseOnStop() {
954181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        return mAutoReleaseOnStop;
95517993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
95617993c442c26161f684d6c0c6867a746f3148548Craig Stout
95717993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
958146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Returns the current background color.
95917993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
96070acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye    @ColorInt
96117993c442c26161f684d6c0c6867a746f3148548Craig Stout    public final int getColor() {
96217993c442c26161f684d6c0c6867a746f3148548Craig Stout        return mBackgroundColor;
96317993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
96417993c442c26161f684d6c0c6867a746f3148548Craig Stout
96517993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
966146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Returns the current background {@link Drawable}.
96717993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
96817993c442c26161f684d6c0c6867a746f3148548Craig Stout    public Drawable getDrawable() {
96917993c442c26161f684d6c0c6867a746f3148548Craig Stout        return mBackgroundDrawable;
97017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
97117993c442c26161f684d6c0c6867a746f3148548Craig Stout
97299ec8b0cb375f7e5577ea3ec9f09e6ff7a95de0dAurimas Liutikas    boolean sameDrawable(Drawable first, Drawable second) {
9737f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if (first == null || second == null) {
9747f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            return false;
9757f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
9767f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if (first == second) {
9777f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            return true;
9787f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
9797f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if (first instanceof BitmapDrawable && second instanceof BitmapDrawable) {
9807f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            if (((BitmapDrawable) first).getBitmap().sameAs(((BitmapDrawable) second).getBitmap())) {
9817f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                return true;
9827f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            }
9837f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
984181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        if (first instanceof ColorDrawable && second instanceof ColorDrawable) {
985181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            if (((ColorDrawable) first).getColor() == ((ColorDrawable) second).getColor()) {
986181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                return true;
987181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            }
988181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        }
9897f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        return false;
9907f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    }
9917f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
99217993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
99317993c442c26161f684d6c0c6867a746f3148548Craig Stout     * Task which changes the background.
99417993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
995181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    final class ChangeBackgroundRunnable implements Runnable {
996181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        final Drawable mDrawable;
99717993c442c26161f684d6c0c6867a746f3148548Craig Stout
99817993c442c26161f684d6c0c6867a746f3148548Craig Stout        ChangeBackgroundRunnable(Drawable drawable) {
99917993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = drawable;
100017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
100117993c442c26161f684d6c0c6867a746f3148548Craig Stout
100217993c442c26161f684d6c0c6867a746f3148548Craig Stout        @Override
100317993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void run() {
10040f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            runTask();
10050f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mChangeRunnable = null;
100617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
100717993c442c26161f684d6c0c6867a746f3148548Craig Stout
100817993c442c26161f684d6c0c6867a746f3148548Craig Stout        private void runTask() {
1009d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            if (mLayerDrawable == null) {
1010d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (DEBUG) Log.v(TAG, "runTask while released - should not happen");
1011d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                return;
1012d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
101317993c442c26161f684d6c0c6867a746f3148548Craig Stout
10142590c39739945451f80dcf8667709b93293fc8bcCraig Stout            DrawableWrapper imageInWrapper = getImageInWrapper();
10152590c39739945451f80dcf8667709b93293fc8bcCraig Stout            if (imageInWrapper != null) {
1016181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                if (sameDrawable(mDrawable, imageInWrapper.getDrawable())) {
1017181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    if (DEBUG) Log.v(TAG, "new drawable same as current");
1018181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                    return;
1019181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                }
1020181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
10210f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                if (DEBUG) Log.v(TAG, "moving image in to image out");
10222e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                // Order is important! Setting a drawable "removes" the
10232e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                // previous one from the view
1024d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                mLayerDrawable.clearDrawable(R.id.background_imagein, mContext);
10252590c39739945451f80dcf8667709b93293fc8bcCraig Stout                mLayerDrawable.updateDrawable(R.id.background_imageout,
10262590c39739945451f80dcf8667709b93293fc8bcCraig Stout                        imageInWrapper.getDrawable());
102717993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
10282e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
10292e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            applyBackgroundChanges();
103017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
103117993c442c26161f684d6c0c6867a746f3148548Craig Stout
1032181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        void applyBackgroundChanges() {
1033181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            if (!mAttached) {
103417993c442c26161f684d6c0c6867a746f3148548Craig Stout                return;
103517993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
1036181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
1037181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            if (DEBUG) Log.v(TAG, "applyBackgroundChanges drawable " + mDrawable);
1038181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
1039181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            DrawableWrapper imageInWrapper = getImageInWrapper();
1040181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            if (imageInWrapper == null && mDrawable != null) {
1041181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                if (DEBUG) Log.v(TAG, "creating new imagein drawable");
1042181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                imageInWrapper = mLayerDrawable.updateDrawable(
1043181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                        R.id.background_imagein, mDrawable);
1044181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                if (DEBUG) Log.v(TAG, "imageInWrapper animation starting");
1045181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu                mLayerDrawable.setWrapperAlpha(mImageInWrapperIndex, 0);
104617993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
1047181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
1048181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            mAnimator.setDuration(FADE_DURATION);
1049181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            mAnimator.start();
1050181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
105117993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
105217993c442c26161f684d6c0c6867a746f3148548Craig Stout
105317993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
1054181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
1055181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    static class EmptyDrawable extends BitmapDrawable {
1056181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        EmptyDrawable(Resources res) {
1057181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu            super(res, (Bitmap) null);
1058181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        }
1059181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    }
1060181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
1061181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    static Drawable createEmptyDrawable(Context context) {
1062181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu        return new EmptyDrawable(context.getResources());
1063181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu    }
1064181c8847d5a1169e26755ed690131333b7fff7e9Dake Gu
106517993c442c26161f684d6c0c6867a746f3148548Craig Stout}
1066