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 */
1417993c442c26161f684d6c0c6867a746f3148548Craig Stoutpackage android.support.v17.leanback.app;
1517993c442c26161f684d6c0c6867a746f3148548Craig Stout
1660c3b420827d0520509387f1abe3e3d8168e2279Dake Guimport java.lang.ref.WeakReference;
1760c3b420827d0520509387f1abe3e3d8168e2279Dake Gu
1870acb0c19be3831a2080e4f902324de16bfbf62eTor Norbyeimport android.support.annotation.ColorInt;
19d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stoutimport android.graphics.PixelFormat;
20f684b94c5f316e9735abc298e00c3f61642b821eCraig Stoutimport android.graphics.PorterDuff;
21f684b94c5f316e9735abc298e00c3f61642b821eCraig Stoutimport android.graphics.PorterDuffColorFilter;
2217993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.support.v17.leanback.R;
233d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stoutimport android.animation.Animator;
247e22f555da71f49a32420965817c760522b95963Craig Stoutimport android.animation.ValueAnimator;
2517993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.app.Activity;
2617993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.content.Context;
277f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.content.res.Resources;
2817993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.content.res.TypedArray;
2917993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.Bitmap;
307f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.graphics.Canvas;
3117993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.Color;
327f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.graphics.ColorFilter;
3317993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.Matrix;
347f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.graphics.Paint;
3517993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.drawable.ColorDrawable;
3617993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.drawable.Drawable;
3717993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.drawable.LayerDrawable;
3817993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.os.Handler;
392590c39739945451f80dcf8667709b93293fc8bcCraig Stoutimport android.support.v17.leanback.widget.BackgroundHelper;
400f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stoutimport android.support.v4.view.animation.FastOutLinearInInterpolator;
4117993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.util.Log;
4217993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.LayoutInflater;
4317993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.View;
4417993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.ViewGroup;
4517993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.Window;
4617993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.WindowManager;
477e22f555da71f49a32420965817c760522b95963Craig Stoutimport android.view.animation.Interpolator;
480f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stoutimport android.view.animation.AnimationUtils;
49fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Guimport android.support.v4.app.FragmentActivity;
5060c3b420827d0520509387f1abe3e3d8168e2279Dake Guimport android.support.v4.content.ContextCompat;
5117993c442c26161f684d6c0c6867a746f3148548Craig Stout
5217993c442c26161f684d6c0c6867a746f3148548Craig Stout/**
53146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * Supports background image continuity between multiple Activities.
5417993c442c26161f684d6c0c6867a746f3148548Craig Stout *
55146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>An Activity should instantiate a BackgroundManager and {@link #attach}
56146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * to the Activity's window.  When the Activity is started, the background is
5717993c442c26161f684d6c0c6867a746f3148548Craig Stout * initialized to the current background values stored in a continuity service.
5817993c442c26161f684d6c0c6867a746f3148548Craig Stout * The background continuity service is updated as the background is updated.
5917993c442c26161f684d6c0c6867a746f3148548Craig Stout *
60146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>At some point, for example when it is stopped, the Activity may release
61146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * its background state.
622e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout *
63146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>When an Activity is resumed, if the BackgroundManager has not been
64146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * released, the continuity service is updated from the BackgroundManager state.
65146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * If the BackgroundManager was released, the BackgroundManager inherits the
66146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * current state from the continuity service.
6717993c442c26161f684d6c0c6867a746f3148548Craig Stout *
68146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>When the last Activity is destroyed, the background state is reset.
6917993c442c26161f684d6c0c6867a746f3148548Craig Stout *
70146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>Backgrounds consist of several layers, from back to front:
71146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <ul>
72146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   <li>the background Drawable of the theme</li>
73146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   <li>a solid color (set via {@link #setColor})</li>
74146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   <li>two Drawables, previous and current (set via {@link #setBitmap} or
75146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   {@link #setDrawable}), which may be in transition</li>
76146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * </ul>
7717993c442c26161f684d6c0c6867a746f3148548Craig Stout *
78146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>BackgroundManager holds references to potentially large bitmap Drawables.
79146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * Call {@link #release} to release these references when the Activity is not
8017993c442c26161f684d6c0c6867a746f3148548Craig Stout * visible.
8117993c442c26161f684d6c0c6867a746f3148548Craig Stout */
82146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn// TODO: support for multiple app processes requires a proper android service
83146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn// instead of the shared memory "service" implemented here. Such a service could
84146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn// support continuity between fragments of different applications if desired.
8517993c442c26161f684d6c0c6867a746f3148548Craig Stoutpublic final class BackgroundManager {
86f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
87f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    interface FragmentStateQueriable {
88f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        public boolean isResumed();
89f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    }
90f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
9117993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final String TAG = "BackgroundManager";
9217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final boolean DEBUG = false;
9317993c442c26161f684d6c0c6867a746f3148548Craig Stout
9417993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final int FULL_ALPHA = 255;
9517993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final int DIM_ALPHA_ON_SOLID = (int) (0.8f * FULL_ALPHA);
9617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final int CHANGE_BG_DELAY_MS = 500;
973d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout    private static final int FADE_DURATION = 500;
9817993c442c26161f684d6c0c6867a746f3148548Craig Stout
9917993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
10017993c442c26161f684d6c0c6867a746f3148548Craig Stout     * Using a separate window for backgrounds can improve graphics performance by
10117993c442c26161f684d6c0c6867a746f3148548Craig Stout     * leveraging hardware display layers.
10217993c442c26161f684d6c0c6867a746f3148548Craig Stout     * TODO: support a leanback configuration option.
10317993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
10417993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final boolean USE_SEPARATE_WINDOW = false;
10517993c442c26161f684d6c0c6867a746f3148548Craig Stout
10617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final String WINDOW_NAME = "BackgroundManager";
1077f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu    private static final String FRAGMENT_TAG = BackgroundManager.class.getCanonicalName();
10817993c442c26161f684d6c0c6867a746f3148548Craig Stout
10917993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Context mContext;
11017993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Handler mHandler;
11117993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Window mWindow;
11217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private WindowManager mWindowManager;
11317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private View mBgView;
11417993c442c26161f684d6c0c6867a746f3148548Craig Stout    private BackgroundContinuityService mService;
11517993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mThemeDrawableResourceId;
116f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    private FragmentStateQueriable mFragmentState;
11717993c442c26161f684d6c0c6867a746f3148548Craig Stout
11817993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mHeightPx;
11917993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mWidthPx;
12017993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Drawable mBackgroundDrawable;
12117993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mBackgroundColor;
12217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private boolean mAttached;
1230f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private long mLastSetTime;
1240f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
1250f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final Interpolator mAccelerateInterpolator;
1260f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final Interpolator mDecelerateInterpolator;
1270f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final ValueAnimator mAnimator;
1280f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final ValueAnimator mDimAnimator;
12917993c442c26161f684d6c0c6867a746f3148548Craig Stout
1307f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    private static class BitmapDrawable extends Drawable {
1317f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1323d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        static class ConstantState extends Drawable.ConstantState {
1333d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            Bitmap mBitmap;
1343d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            Matrix mMatrix;
1353d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            Paint mPaint;
1363d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1373d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            @Override
1383d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            public Drawable newDrawable() {
1393d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                return new BitmapDrawable(null, mBitmap, mMatrix);
1403d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            }
1413d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1423d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            @Override
1433d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            public int getChangingConfigurations() {
1443d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                return 0;
1453d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            }
1463d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
1473d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1483d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        private ConstantState mState = new ConstantState();
1497f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1507f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        BitmapDrawable(Resources resources, Bitmap bitmap) {
1517f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            this(resources, bitmap, null);
1527f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1537f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1547f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        BitmapDrawable(Resources resources, Bitmap bitmap, Matrix matrix) {
1553d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mState.mBitmap = bitmap;
1563d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mState.mMatrix = matrix != null ? matrix : new Matrix();
1573d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mState.mPaint = new Paint();
1583d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mState.mPaint.setFilterBitmap(true);
1597f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1607f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1617f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        Bitmap getBitmap() {
1623d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            return mState.mBitmap;
1637f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1647f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1657f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1667f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public void draw(Canvas canvas) {
1673d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (mState.mBitmap == null) {
1687f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                return;
1697f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            }
170f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (mState.mPaint.getAlpha() < FULL_ALPHA && mState.mPaint.getColorFilter() != null) {
171f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                throw new IllegalStateException("Can't draw with translucent alpha and color filter");
172f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            }
1733d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            canvas.drawBitmap(mState.mBitmap, mState.mMatrix, mState.mPaint);
1747f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1757f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1767f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1777f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public int getOpacity() {
178d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return android.graphics.PixelFormat.TRANSLUCENT;
1797f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1807f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1817f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1827f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public void setAlpha(int alpha) {
1833d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (mState.mPaint.getAlpha() != alpha) {
1843d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                mState.mPaint.setAlpha(alpha);
1857f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                invalidateSelf();
1867f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            }
1877f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1887f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
189f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        /**
190f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout         * Does not invalidateSelf to avoid recursion issues.
191f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout         * Caller must ensure appropriate invalidation.
192f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout         */
1937f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1947f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public void setColorFilter(ColorFilter cf) {
195f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mState.mPaint.setColorFilter(cf);
196f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
197f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
198f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        public ColorFilter getColorFilter() {
199f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            return mState.mPaint.getColorFilter();
2007f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
2013d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
2023d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        @Override
2033d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        public ConstantState getConstantState() {
2043d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            return mState;
2053d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
2067f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    }
2077f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
2087f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    private static class DrawableWrapper {
209d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        private int mAlpha = FULL_ALPHA;
210d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        private Drawable mDrawable;
211f36902ae811a12506f54faa261cb653f45a27612Craig Stout        private ColorFilter mColorFilter;
2127e22f555da71f49a32420965817c760522b95963Craig Stout
21317993c442c26161f684d6c0c6867a746f3148548Craig Stout        public DrawableWrapper(Drawable drawable) {
21417993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = drawable;
215d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            updateAlpha();
216f36902ae811a12506f54faa261cb653f45a27612Craig Stout            updateColorFilter();
217d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
218d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public DrawableWrapper(DrawableWrapper wrapper, Drawable drawable) {
219d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mDrawable = drawable;
220d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mAlpha = wrapper.getAlpha();
221d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            updateAlpha();
222f36902ae811a12506f54faa261cb653f45a27612Craig Stout            mColorFilter = wrapper.getColorFilter();
223f36902ae811a12506f54faa261cb653f45a27612Craig Stout            updateColorFilter();
22417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
225f36902ae811a12506f54faa261cb653f45a27612Craig Stout
22617993c442c26161f684d6c0c6867a746f3148548Craig Stout        public Drawable getDrawable() {
22717993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mDrawable;
22817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
22917993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setAlpha(int alpha) {
23017993c442c26161f684d6c0c6867a746f3148548Craig Stout            mAlpha = alpha;
231d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            updateAlpha();
23217993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
23317993c442c26161f684d6c0c6867a746f3148548Craig Stout        public int getAlpha() {
23417993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mAlpha;
23517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
236d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        private void updateAlpha() {
237d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mDrawable.setAlpha(mAlpha);
238d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
239f36902ae811a12506f54faa261cb653f45a27612Craig Stout
240f36902ae811a12506f54faa261cb653f45a27612Craig Stout        public ColorFilter getColorFilter() {
241f36902ae811a12506f54faa261cb653f45a27612Craig Stout            return mColorFilter;
242f36902ae811a12506f54faa261cb653f45a27612Craig Stout        }
243f36902ae811a12506f54faa261cb653f45a27612Craig Stout        public void setColorFilter(ColorFilter colorFilter) {
244f36902ae811a12506f54faa261cb653f45a27612Craig Stout            mColorFilter = colorFilter;
245f36902ae811a12506f54faa261cb653f45a27612Craig Stout            updateColorFilter();
246f36902ae811a12506f54faa261cb653f45a27612Craig Stout        }
247f36902ae811a12506f54faa261cb653f45a27612Craig Stout        private void updateColorFilter() {
248f36902ae811a12506f54faa261cb653f45a27612Craig Stout            mDrawable.setColorFilter(mColorFilter);
249f36902ae811a12506f54faa261cb653f45a27612Craig Stout        }
250f36902ae811a12506f54faa261cb653f45a27612Craig Stout
25117993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setColor(int color) {
25217993c442c26161f684d6c0c6867a746f3148548Craig Stout            ((ColorDrawable) mDrawable).setColor(color);
25317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
25417993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
25517993c442c26161f684d6c0c6867a746f3148548Craig Stout
256f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    static class TranslucentLayerDrawable extends LayerDrawable {
257d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        private DrawableWrapper[] mWrapper;
258d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        private Paint mPaint = new Paint();
259d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
260d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public TranslucentLayerDrawable(Drawable[] drawables) {
261d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            super(drawables);
262d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            int count = drawables.length;
263d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mWrapper = new DrawableWrapper[count];
264d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < count; i++) {
265d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                mWrapper[i] = new DrawableWrapper(drawables[i]);
266d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
267d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
268d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
269d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
270d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public void setAlpha(int alpha) {
271d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            if (mPaint.getAlpha() != alpha) {
272f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                int previousAlpha = mPaint.getAlpha();
273d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                mPaint.setAlpha(alpha);
274d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                invalidateSelf();
275f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                onAlphaChanged(previousAlpha, alpha);
276d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
277d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
278d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
2792590c39739945451f80dcf8667709b93293fc8bcCraig Stout        // Queried by system transitions
2802590c39739945451f80dcf8667709b93293fc8bcCraig Stout        public int getAlpha() {
2812590c39739945451f80dcf8667709b93293fc8bcCraig Stout            return mPaint.getAlpha();
2822590c39739945451f80dcf8667709b93293fc8bcCraig Stout        }
2832590c39739945451f80dcf8667709b93293fc8bcCraig Stout
284f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        protected void onAlphaChanged(int oldAlpha, int newAlpha) {
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            }
296f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            invalidateSelf();
297d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return drawable;
298d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
299d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
300d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
301d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public int getOpacity() {
302d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return PixelFormat.TRANSLUCENT;
303d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
304d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
305d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
306d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public boolean setDrawableByLayerId(int id, Drawable drawable) {
307d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return updateDrawable(id, drawable) != null;
308d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
309d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
310d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public DrawableWrapper updateDrawable(int id, Drawable drawable) {
311d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            super.setDrawableByLayerId(id, drawable);
312d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < getNumberOfLayers(); i++) {
313d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (getId(i) == id) {
314d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    mWrapper[i] = new DrawableWrapper(drawable);
315f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                    // Must come after mWrapper was updated so it can be seen by updateColorFilter
316f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                    invalidateSelf();
317d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    return mWrapper[i];
318d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                }
319d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
320d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return null;
321d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
322d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
323d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public void clearDrawable(int id, Context context) {
324d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < getNumberOfLayers(); i++) {
325d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (getId(i) == id) {
326d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    mWrapper[i] = null;
327d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    super.setDrawableByLayerId(id, createEmptyDrawable(context));
328d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    break;
329d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                }
330d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
331d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
332d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
333d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public DrawableWrapper findWrapperById(int id) {
334d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < getNumberOfLayers(); i++) {
335d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (getId(i) == id) {
336d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    return mWrapper[i];
337d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                }
338d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
339d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return null;
340d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
341d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
342d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
343d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public void draw(Canvas canvas) {
344d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            if (mPaint.getAlpha() < FULL_ALPHA) {
345d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(),
346d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                        mPaint, Canvas.ALL_SAVE_FLAG);
347d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
348d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            super.draw(canvas);
349d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            if (mPaint.getAlpha() < FULL_ALPHA) {
350d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                canvas.restore();
351d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
352d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
353d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout    }
354d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
355f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    /**
356f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout     * Optimizes drawing when the dim drawable is an alpha-only color and imagein is opaque.
357f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout     * When the layer drawable is translucent (activity transition) then we can avoid the slow
358f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout     * saveLayer/restore draw path.
359f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout     */
360f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    private class OptimizedTranslucentLayerDrawable extends TranslucentLayerDrawable {
361f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        private PorterDuffColorFilter mColorFilter;
362f36902ae811a12506f54faa261cb653f45a27612Craig Stout        private boolean mUpdatingColorFilter;
363f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
364f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        public OptimizedTranslucentLayerDrawable(Drawable[] drawables) {
365f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            super(drawables);
366f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
367f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
368f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        @Override
369f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        protected void onAlphaChanged(int oldAlpha, int newAlpha) {
370f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (newAlpha == FULL_ALPHA && oldAlpha < FULL_ALPHA) {
371f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                if (DEBUG) Log.v(TAG, "transition complete");
372f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                postChangeRunnable();
373f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            }
374f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
375f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
376f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        @Override
377f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        public void invalidateSelf() {
378f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            super.invalidateSelf();
379f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            updateColorFilter();
380f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
381f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
382f36902ae811a12506f54faa261cb653f45a27612Craig Stout        @Override
383f36902ae811a12506f54faa261cb653f45a27612Craig Stout        public void invalidateDrawable(Drawable who) {
384f36902ae811a12506f54faa261cb653f45a27612Craig Stout            if (!mUpdatingColorFilter) {
385f36902ae811a12506f54faa261cb653f45a27612Craig Stout                invalidateSelf();
386f36902ae811a12506f54faa261cb653f45a27612Craig Stout            }
387f36902ae811a12506f54faa261cb653f45a27612Craig Stout        }
388f36902ae811a12506f54faa261cb653f45a27612Craig Stout
389f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        private void updateColorFilter() {
390f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            DrawableWrapper dimWrapper = findWrapperById(R.id.background_dim);
391f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            DrawableWrapper imageInWrapper = findWrapperById(R.id.background_imagein);
392f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            DrawableWrapper imageOutWrapper = findWrapperById(R.id.background_imageout);
393f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
394f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mColorFilter = null;
395f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (imageInWrapper != null && imageInWrapper.getAlpha() == FULL_ALPHA &&
396f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                    dimWrapper.getDrawable() instanceof ColorDrawable) {
397f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                int dimColor = ((ColorDrawable) dimWrapper.getDrawable()).getColor();
398f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                if (Color.red(dimColor) == 0 &&
399f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                        Color.green(dimColor) == 0 &&
400f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                        Color.blue(dimColor) == 0) {
401f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                    int dimAlpha = 255 - Color.alpha(dimColor);
402f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                    int color = Color.argb(getAlpha(), dimAlpha, dimAlpha, dimAlpha);
403f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                    mColorFilter = new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY);
404f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                }
405f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            }
406f36902ae811a12506f54faa261cb653f45a27612Craig Stout            mUpdatingColorFilter = true;
407f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (imageInWrapper != null) {
408f36902ae811a12506f54faa261cb653f45a27612Craig Stout                imageInWrapper.setColorFilter(mColorFilter);
409f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            }
410f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (imageOutWrapper != null) {
411f36902ae811a12506f54faa261cb653f45a27612Craig Stout                imageOutWrapper.setColorFilter(null);
412f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            }
413f36902ae811a12506f54faa261cb653f45a27612Craig Stout            mUpdatingColorFilter = false;
414f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
415f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
416f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        @Override
417f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        public void draw(Canvas canvas) {
418f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            DrawableWrapper imageInWrapper = findWrapperById(R.id.background_imagein);
419f36902ae811a12506f54faa261cb653f45a27612Craig Stout            if (imageInWrapper != null && imageInWrapper.getDrawable() != null &&
420f36902ae811a12506f54faa261cb653f45a27612Craig Stout                    imageInWrapper.getColorFilter() != null) {
421f36902ae811a12506f54faa261cb653f45a27612Craig Stout                imageInWrapper.getDrawable().draw(canvas);
422f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            } else {
423f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                super.draw(canvas);
424f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            }
425f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
426f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    }
427f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
428f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    private TranslucentLayerDrawable createOptimizedTranslucentLayerDrawable(
429f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            LayerDrawable layerDrawable) {
430f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        int numChildren = layerDrawable.getNumberOfLayers();
431f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        Drawable[] drawables = new Drawable[numChildren];
432f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        for (int i = 0; i < numChildren; i++) {
433f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            drawables[i] = layerDrawable.getDrawable(i);
434f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
435f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        TranslucentLayerDrawable result = new OptimizedTranslucentLayerDrawable(drawables);
436f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        for (int i = 0; i < numChildren; i++) {
437f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            result.setId(i, layerDrawable.getId(i));
438f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
439f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        return result;
440f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    }
441f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
442d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout    private TranslucentLayerDrawable mLayerDrawable;
4430f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private Drawable mDimDrawable;
44417993c442c26161f684d6c0c6867a746f3148548Craig Stout    private ChangeBackgroundRunnable mChangeRunnable;
445f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    private boolean mChangeRunnablePending;
44617993c442c26161f684d6c0c6867a746f3148548Craig Stout
4470f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final Animator.AnimatorListener mAnimationListener = new Animator.AnimatorListener() {
448f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        final Runnable mRunnable = new Runnable() {
449f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            @Override
450f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            public void run() {
451f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout                postChangeRunnable();
452f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            }
453f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        };
454f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
4550f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
4560f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationStart(Animator animation) {
4570f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
4580f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
4590f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationRepeat(Animator animation) {
4600f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
4610f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
4620f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationEnd(Animator animation) {
463f988bc054a2e0ccefacd8c76cbcf47a1ab88e6b1Craig Stout            if (mLayerDrawable != null) {
464f988bc054a2e0ccefacd8c76cbcf47a1ab88e6b1Craig Stout                mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
465f988bc054a2e0ccefacd8c76cbcf47a1ab88e6b1Craig Stout            }
466f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mHandler.post(mRunnable);
4670f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
4680f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
4690f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationCancel(Animator animation) {
4700f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
4710f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    };
4720f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
4730f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final ValueAnimator.AnimatorUpdateListener mAnimationUpdateListener =
4740f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            new ValueAnimator.AnimatorUpdateListener() {
4750f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
4760f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationUpdate(ValueAnimator animation) {
4770f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            int fadeInAlpha = (Integer) animation.getAnimatedValue();
4782590c39739945451f80dcf8667709b93293fc8bcCraig Stout            DrawableWrapper imageInWrapper = getImageInWrapper();
4792590c39739945451f80dcf8667709b93293fc8bcCraig Stout            if (imageInWrapper != null) {
4802590c39739945451f80dcf8667709b93293fc8bcCraig Stout                imageInWrapper.setAlpha(fadeInAlpha);
4812590c39739945451f80dcf8667709b93293fc8bcCraig Stout            } else {
4822590c39739945451f80dcf8667709b93293fc8bcCraig Stout                DrawableWrapper imageOutWrapper = getImageOutWrapper();
4832590c39739945451f80dcf8667709b93293fc8bcCraig Stout                if (imageOutWrapper != null) {
4842590c39739945451f80dcf8667709b93293fc8bcCraig Stout                    imageOutWrapper.setAlpha(255 - fadeInAlpha);
4852590c39739945451f80dcf8667709b93293fc8bcCraig Stout                }
4860f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            }
4870f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
4880f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    };
4890f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
4900f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final ValueAnimator.AnimatorUpdateListener mDimUpdateListener =
4910f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            new ValueAnimator.AnimatorUpdateListener() {
4920f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
4930f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationUpdate(ValueAnimator animation) {
4942590c39739945451f80dcf8667709b93293fc8bcCraig Stout            DrawableWrapper dimWrapper = getDimWrapper();
4952590c39739945451f80dcf8667709b93293fc8bcCraig Stout            if (dimWrapper != null) {
4962590c39739945451f80dcf8667709b93293fc8bcCraig Stout                dimWrapper.setAlpha((Integer) animation.getAnimatedValue());
4970f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            }
4980f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
4990f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    };
5000f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
50117993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
50217993c442c26161f684d6c0c6867a746f3148548Craig Stout     * Shared memory continuity service.
50317993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
50417993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static class BackgroundContinuityService {
50517993c442c26161f684d6c0c6867a746f3148548Craig Stout        private static final String TAG = "BackgroundContinuityService";
50617993c442c26161f684d6c0c6867a746f3148548Craig Stout        private static boolean DEBUG = BackgroundManager.DEBUG;
50717993c442c26161f684d6c0c6867a746f3148548Craig Stout
50817993c442c26161f684d6c0c6867a746f3148548Craig Stout        private static BackgroundContinuityService sService = new BackgroundContinuityService();
50917993c442c26161f684d6c0c6867a746f3148548Craig Stout
51017993c442c26161f684d6c0c6867a746f3148548Craig Stout        private int mColor;
51117993c442c26161f684d6c0c6867a746f3148548Craig Stout        private Drawable mDrawable;
51217993c442c26161f684d6c0c6867a746f3148548Craig Stout        private int mCount;
51317993c442c26161f684d6c0c6867a746f3148548Craig Stout
51460c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        /** Single cache of theme drawable */
51560c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        private int mLastThemeDrawableId;
516363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout        private WeakReference<Drawable.ConstantState> mLastThemeDrawableState;
51760c3b420827d0520509387f1abe3e3d8168e2279Dake Gu
51817993c442c26161f684d6c0c6867a746f3148548Craig Stout        private BackgroundContinuityService() {
51917993c442c26161f684d6c0c6867a746f3148548Craig Stout            reset();
52017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
52117993c442c26161f684d6c0c6867a746f3148548Craig Stout
52217993c442c26161f684d6c0c6867a746f3148548Craig Stout        private void reset() {
52317993c442c26161f684d6c0c6867a746f3148548Craig Stout            mColor = Color.TRANSPARENT;
52417993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = null;
52517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
52617993c442c26161f684d6c0c6867a746f3148548Craig Stout
52717993c442c26161f684d6c0c6867a746f3148548Craig Stout        public static BackgroundContinuityService getInstance() {
52817993c442c26161f684d6c0c6867a746f3148548Craig Stout            final int count = sService.mCount++;
52917993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "Returning instance with new count " + count);
53017993c442c26161f684d6c0c6867a746f3148548Craig Stout            return sService;
53117993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
53217993c442c26161f684d6c0c6867a746f3148548Craig Stout
53317993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void unref() {
53417993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (mCount <= 0) throw new IllegalStateException("Can't unref, count " + mCount);
53517993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (--mCount == 0) {
53617993c442c26161f684d6c0c6867a746f3148548Craig Stout                if (DEBUG) Log.v(TAG, "mCount is zero, resetting");
53717993c442c26161f684d6c0c6867a746f3148548Craig Stout                reset();
53817993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
53917993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
54017993c442c26161f684d6c0c6867a746f3148548Craig Stout        public int getColor() {
54117993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mColor;
54217993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
54317993c442c26161f684d6c0c6867a746f3148548Craig Stout        public Drawable getDrawable() {
54417993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mDrawable;
54517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
54617993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setColor(int color) {
54717993c442c26161f684d6c0c6867a746f3148548Craig Stout            mColor = color;
54817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
54917993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setDrawable(Drawable drawable) {
55017993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = drawable;
55117993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
55260c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        public Drawable getThemeDrawable(Context context, int themeDrawableId) {
55360c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            Drawable drawable = null;
554363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout            if (mLastThemeDrawableState != null && mLastThemeDrawableId == themeDrawableId) {
555363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                Drawable.ConstantState drawableState = mLastThemeDrawableState.get();
556363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                if (DEBUG) Log.v(TAG, "got cached theme drawable state " + drawableState);
557363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                if (drawableState != null) {
558363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                    drawable = drawableState.newDrawable();
559363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                }
56060c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            }
56160c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            if (drawable == null) {
56260c3b420827d0520509387f1abe3e3d8168e2279Dake Gu                drawable = ContextCompat.getDrawable(context, themeDrawableId);
563363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                if (DEBUG) Log.v(TAG, "loaded theme drawable " + drawable);
564363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                mLastThemeDrawableState = new WeakReference<Drawable.ConstantState>(
565363191eb688c10be4f8ffe10c41da1664168d1feCraig Stout                        drawable.getConstantState());
56660c3b420827d0520509387f1abe3e3d8168e2279Dake Gu                mLastThemeDrawableId = themeDrawableId;
56760c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            }
568459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout            // No mutate required because this drawable is never manipulated.
569459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout            return drawable;
57060c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        }
57117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
57217993c442c26161f684d6c0c6867a746f3148548Craig Stout
57317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Drawable getThemeDrawable() {
57417993c442c26161f684d6c0c6867a746f3148548Craig Stout        Drawable drawable = null;
57517993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mThemeDrawableResourceId != -1) {
57660c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            drawable = mService.getThemeDrawable(mContext, mThemeDrawableResourceId);
57717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
57817993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (drawable == null) {
579d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            drawable = createEmptyDrawable(mContext);
58017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
58117993c442c26161f684d6c0c6867a746f3148548Craig Stout        return drawable;
58217993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
58317993c442c26161f684d6c0c6867a746f3148548Craig Stout
58417993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
585a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Returns the BackgroundManager associated with the given Activity.
5867f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu     * <p>
587146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * The BackgroundManager will be created on-demand for each individual
588146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Activity. Subsequent calls will return the same BackgroundManager created
589146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * for this Activity.
5907f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu     */
5917f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu    public static BackgroundManager getInstance(Activity activity) {
592fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        if (activity instanceof FragmentActivity) {
593fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            return getSupportInstance((FragmentActivity) activity);
594fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        }
5957f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
5967f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                .findFragmentByTag(FRAGMENT_TAG);
5977f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        if (fragment != null) {
5987f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            BackgroundManager manager = fragment.getBackgroundManager();
5997f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            if (manager != null) {
6007f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                return manager;
6017f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            }
6027f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            // manager is null: this is a fragment restored by FragmentManager,
6037f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            // fall through to create a BackgroundManager attach to it.
6047f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        }
605fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        return new BackgroundManager(activity, false);
606fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu    }
607fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu
608fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu    private static BackgroundManager getSupportInstance(FragmentActivity activity) {
609fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        BackgroundSupportFragment fragment = (BackgroundSupportFragment) activity
610fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu                .getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
611fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        if (fragment != null) {
612fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            BackgroundManager manager = fragment.getBackgroundManager();
613fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            if (manager != null) {
614fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu                return manager;
615fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            }
616fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            // manager is null: this is a fragment restored by FragmentManager,
617fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            // fall through to create a BackgroundManager attach to it.
618fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        }
619fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        return new BackgroundManager(activity, true);
6207f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu    }
6217f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu
622fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu    private BackgroundManager(Activity activity, boolean isSupportFragmentActivity) {
62317993c442c26161f684d6c0c6867a746f3148548Craig Stout        mContext = activity;
62417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mService = BackgroundContinuityService.getInstance();
62517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mHeightPx = mContext.getResources().getDisplayMetrics().heightPixels;
62617993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWidthPx = mContext.getResources().getDisplayMetrics().widthPixels;
62717993c442c26161f684d6c0c6867a746f3148548Craig Stout        mHandler = new Handler();
62817993c442c26161f684d6c0c6867a746f3148548Craig Stout
6290f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        Interpolator defaultInterpolator = new FastOutLinearInInterpolator();
6300f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAccelerateInterpolator = AnimationUtils.loadInterpolator(mContext,
6310f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                android.R.anim.accelerate_interpolator);
6320f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mDecelerateInterpolator = AnimationUtils.loadInterpolator(mContext,
6330f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                android.R.anim.decelerate_interpolator);
6340f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
6350f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator = ValueAnimator.ofInt(0, FULL_ALPHA);
6360f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.addListener(mAnimationListener);
6370f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.addUpdateListener(mAnimationUpdateListener);
6380f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.setInterpolator(defaultInterpolator);
6390f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
6400f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mDimAnimator = new ValueAnimator();
6410f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mDimAnimator.addUpdateListener(mDimUpdateListener);
6420f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
64317993c442c26161f684d6c0c6867a746f3148548Craig Stout        TypedArray ta = activity.getTheme().obtainStyledAttributes(new int[] {
64417993c442c26161f684d6c0c6867a746f3148548Craig Stout                android.R.attr.windowBackground });
64517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mThemeDrawableResourceId = ta.getResourceId(0, -1);
64617993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mThemeDrawableResourceId < 0) {
64717993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "BackgroundManager no window background resource!");
64817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
64917993c442c26161f684d6c0c6867a746f3148548Craig Stout        ta.recycle();
65017993c442c26161f684d6c0c6867a746f3148548Craig Stout
651fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        if (isSupportFragmentActivity) {
652fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            createSupportFragment((FragmentActivity) activity);
653fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        } else {
654fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            createFragment(activity);
655fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        }
65617993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
65717993c442c26161f684d6c0c6867a746f3148548Craig Stout
65817993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void createFragment(Activity activity) {
65917993c442c26161f684d6c0c6867a746f3148548Craig Stout        // Use a fragment to ensure the background manager gets detached properly.
660b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu        BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
6617f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                .findFragmentByTag(FRAGMENT_TAG);
662b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu        if (fragment == null) {
663b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu            fragment = new BackgroundFragment();
6647f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            activity.getFragmentManager().beginTransaction().add(fragment, FRAGMENT_TAG).commit();
6657f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        } else {
6667f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            if (fragment.getBackgroundManager() != null) {
6677f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                throw new IllegalStateException("Created duplicated BackgroundManager for same " +
6687f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                        "activity, please use getInstance() instead");
6697f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            }
670b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu        }
67117993c442c26161f684d6c0c6867a746f3148548Craig Stout        fragment.setBackgroundManager(this);
672f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        mFragmentState = fragment;
67317993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
67417993c442c26161f684d6c0c6867a746f3148548Craig Stout
675fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu    private void createSupportFragment(FragmentActivity activity) {
676fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        // Use a fragment to ensure the background manager gets detached properly.
677fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        BackgroundSupportFragment fragment = (BackgroundSupportFragment) activity
678fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu                .getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
679fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        if (fragment == null) {
680fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            fragment = new BackgroundSupportFragment();
681fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            activity.getSupportFragmentManager().beginTransaction().add(fragment, FRAGMENT_TAG)
682fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu                    .commit();
683fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        } else {
684fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            if (fragment.getBackgroundManager() != null) {
685fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu                throw new IllegalStateException("Created duplicated BackgroundManager for same " +
686fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu                    "activity, please use getInstance() instead");
687fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            }
688fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        }
689fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        fragment.setBackgroundManager(this);
690f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        mFragmentState = fragment;
691fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu    }
692fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu
6932590c39739945451f80dcf8667709b93293fc8bcCraig Stout    private DrawableWrapper getImageInWrapper() {
6942590c39739945451f80dcf8667709b93293fc8bcCraig Stout        return mLayerDrawable == null ? null :
6952590c39739945451f80dcf8667709b93293fc8bcCraig Stout                mLayerDrawable.findWrapperById(R.id.background_imagein);
6962590c39739945451f80dcf8667709b93293fc8bcCraig Stout    }
6972590c39739945451f80dcf8667709b93293fc8bcCraig Stout
6982590c39739945451f80dcf8667709b93293fc8bcCraig Stout    private DrawableWrapper getImageOutWrapper() {
6992590c39739945451f80dcf8667709b93293fc8bcCraig Stout        return mLayerDrawable == null ? null :
7002590c39739945451f80dcf8667709b93293fc8bcCraig Stout                mLayerDrawable.findWrapperById(R.id.background_imageout);
7012590c39739945451f80dcf8667709b93293fc8bcCraig Stout    }
7022590c39739945451f80dcf8667709b93293fc8bcCraig Stout
7032590c39739945451f80dcf8667709b93293fc8bcCraig Stout    private DrawableWrapper getDimWrapper() {
7042590c39739945451f80dcf8667709b93293fc8bcCraig Stout        return mLayerDrawable == null ? null :
7052590c39739945451f80dcf8667709b93293fc8bcCraig Stout                mLayerDrawable.findWrapperById(R.id.background_dim);
7062590c39739945451f80dcf8667709b93293fc8bcCraig Stout    }
7072590c39739945451f80dcf8667709b93293fc8bcCraig Stout
7082590c39739945451f80dcf8667709b93293fc8bcCraig Stout    private DrawableWrapper getColorWrapper() {
7092590c39739945451f80dcf8667709b93293fc8bcCraig Stout        return mLayerDrawable == null ? null :
7102590c39739945451f80dcf8667709b93293fc8bcCraig Stout                mLayerDrawable.findWrapperById(R.id.background_color);
7112590c39739945451f80dcf8667709b93293fc8bcCraig Stout    }
7122590c39739945451f80dcf8667709b93293fc8bcCraig Stout
71317993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
714f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout     * Synchronizes state when the owning Activity is started.
715f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout     * At that point the view becomes visible.
71617993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
717f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    void onActivityStart() {
7182e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        if (mService == null) {
7192e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            return;
7202e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        }
7212e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        if (mLayerDrawable == null) {
722f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (DEBUG) Log.v(TAG, "onActivityStart " + this +
7233d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                    " released state, syncing with service");
7242e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            syncWithService();
7252e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        } else {
726f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (DEBUG) Log.v(TAG, "onActivityStart " + this + " updating service color "
7272e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                    + mBackgroundColor + " drawable " + mBackgroundDrawable);
7282e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mService.setColor(mBackgroundColor);
7292e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mService.setDrawable(mBackgroundDrawable);
7302e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        }
73117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
73217993c442c26161f684d6c0c6867a746f3148548Craig Stout
733f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    void onResume() {
734f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        if (DEBUG) Log.v(TAG, "onResume " + this);
735f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        postChangeRunnable();
736f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    }
737f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
73817993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void syncWithService() {
73917993c442c26161f684d6c0c6867a746f3148548Craig Stout        int color = mService.getColor();
74017993c442c26161f684d6c0c6867a746f3148548Craig Stout        Drawable drawable = mService.getDrawable();
74117993c442c26161f684d6c0c6867a746f3148548Craig Stout
74217993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "syncWithService color " + Integer.toHexString(color)
74317993c442c26161f684d6c0c6867a746f3148548Craig Stout                + " drawable " + drawable);
74417993c442c26161f684d6c0c6867a746f3148548Craig Stout
74517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBackgroundColor = color;
7463d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        mBackgroundDrawable = drawable == null ? null :
7473d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            drawable.getConstantState().newDrawable().mutate();
7482e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
7492e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        updateImmediate();
75017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
75117993c442c26161f684d6c0c6867a746f3148548Craig Stout
75217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void lazyInit() {
75317993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mLayerDrawable != null) {
75417993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
75517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
75617993c442c26161f684d6c0c6867a746f3148548Craig Stout
757d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        LayerDrawable layerDrawable = (LayerDrawable)
758d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                ContextCompat.getDrawable(mContext, R.drawable.lb_background).mutate();
759f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        mLayerDrawable = createOptimizedTranslucentLayerDrawable(layerDrawable);
7602590c39739945451f80dcf8667709b93293fc8bcCraig Stout        BackgroundHelper.setBackgroundPreservingAlpha(mBgView, mLayerDrawable);
76117993c442c26161f684d6c0c6867a746f3148548Craig Stout
762d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
763d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        mLayerDrawable.updateDrawable(R.id.background_theme, getThemeDrawable());
764c149abce7f8a46f7c54211b5f97c5cd9ee729357Dake Gu
7650f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        updateDimWrapper();
7660f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
7670f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
7680f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private void updateDimWrapper() {
7690f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        if (mDimDrawable == null) {
7700f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mDimDrawable = getDefaultDimLayer();
7710f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
772d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        Drawable dimDrawable = mDimDrawable.getConstantState().newDrawable(
773d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                mContext.getResources()).mutate();
7742590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (mLayerDrawable != null) {
7752590c39739945451f80dcf8667709b93293fc8bcCraig Stout            mLayerDrawable.updateDrawable(R.id.background_dim, dimDrawable);
7762590c39739945451f80dcf8667709b93293fc8bcCraig Stout        }
77717993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
77817993c442c26161f684d6c0c6867a746f3148548Craig Stout
77917993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
780a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Makes the background visible on the given Window.  The background manager must be attached
7810f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * when the background is set.
78217993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
78317993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void attach(Window window) {
78417993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (USE_SEPARATE_WINDOW) {
78517993c442c26161f684d6c0c6867a746f3148548Craig Stout            attachBehindWindow(window);
78617993c442c26161f684d6c0c6867a746f3148548Craig Stout        } else {
78717993c442c26161f684d6c0c6867a746f3148548Craig Stout            attachToView(window.getDecorView());
78817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
78917993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
79017993c442c26161f684d6c0c6867a746f3148548Craig Stout
791459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout    /**
792459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout     * Sets the resource id for the drawable to be shown when there is no background set.
793459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout     * Overrides the window background drawable from the theme. This should
794459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout     * be called before attaching.
795459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout     */
796459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout    public void setThemeDrawableResourceId(int resourceId) {
797459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout        mThemeDrawableResourceId = resourceId;
798459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout    }
799459af78be7413b944e2ff0a6f231a8b7b5de3aadCraig Stout
80017993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void attachBehindWindow(Window window) {
80117993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "attachBehindWindow " + window);
80217993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindow = window;
80317993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindowManager = window.getWindowManager();
80417993c442c26161f684d6c0c6867a746f3148548Craig Stout
80517993c442c26161f684d6c0c6867a746f3148548Craig Stout        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
80617993c442c26161f684d6c0c6867a746f3148548Craig Stout                // Media window sits behind the main application window
80717993c442c26161f684d6c0c6867a746f3148548Craig Stout                WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA,
80817993c442c26161f684d6c0c6867a746f3148548Craig Stout                // Avoid default to software format RGBA
80917993c442c26161f684d6c0c6867a746f3148548Craig Stout                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
81017993c442c26161f684d6c0c6867a746f3148548Craig Stout                android.graphics.PixelFormat.TRANSLUCENT);
81117993c442c26161f684d6c0c6867a746f3148548Craig Stout        params.setTitle(WINDOW_NAME);
81217993c442c26161f684d6c0c6867a746f3148548Craig Stout        params.width = ViewGroup.LayoutParams.MATCH_PARENT;
81317993c442c26161f684d6c0c6867a746f3148548Craig Stout        params.height = ViewGroup.LayoutParams.MATCH_PARENT;
81417993c442c26161f684d6c0c6867a746f3148548Craig Stout
81517993c442c26161f684d6c0c6867a746f3148548Craig Stout        View backgroundView = LayoutInflater.from(mContext).inflate(
81617993c442c26161f684d6c0c6867a746f3148548Craig Stout                R.layout.lb_background_window, null);
81717993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindowManager.addView(backgroundView, params);
81817993c442c26161f684d6c0c6867a746f3148548Craig Stout
81917993c442c26161f684d6c0c6867a746f3148548Craig Stout        attachToView(backgroundView);
82017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
82117993c442c26161f684d6c0c6867a746f3148548Craig Stout
82217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void attachToView(View sceneRoot) {
82317993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBgView = sceneRoot;
82417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mAttached = true;
8252e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        syncWithService();
82617993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
82717993c442c26161f684d6c0c6867a746f3148548Craig Stout
82817993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
8290f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Returns true if the background manager is currently attached; false otherwise.
8300f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     */
8310f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    public boolean isAttached() {
8320f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        return mAttached;
8330f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
8340f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
8350f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    /**
836146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Release references to Drawables and put the BackgroundManager into the
837146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * detached state. Called when the associated Activity is destroyed.
83817993c442c26161f684d6c0c6867a746f3148548Craig Stout     * @hide
83917993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
84017993c442c26161f684d6c0c6867a746f3148548Craig Stout    void detach() {
8413d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        if (DEBUG) Log.v(TAG, "detach " + this);
84217993c442c26161f684d6c0c6867a746f3148548Craig Stout        release();
84317993c442c26161f684d6c0c6867a746f3148548Craig Stout
84417993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mWindowManager != null && mBgView != null) {
84517993c442c26161f684d6c0c6867a746f3148548Craig Stout            mWindowManager.removeViewImmediate(mBgView);
84617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
84717993c442c26161f684d6c0c6867a746f3148548Craig Stout
84817993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindowManager = null;
84917993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindow = null;
85017993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBgView = null;
85117993c442c26161f684d6c0c6867a746f3148548Craig Stout        mAttached = false;
85217993c442c26161f684d6c0c6867a746f3148548Craig Stout
85317993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mService != null) {
85417993c442c26161f684d6c0c6867a746f3148548Craig Stout            mService.unref();
85517993c442c26161f684d6c0c6867a746f3148548Craig Stout            mService = null;
85617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
85717993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
85817993c442c26161f684d6c0c6867a746f3148548Craig Stout
85917993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
860146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Release references to Drawables. Typically called to reduce memory
861146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * overhead when not visible.
8622e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout     * <p>
863f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout     * When an Activity is started, if the BackgroundManager has not been
864146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * released, the continuity service is updated from the BackgroundManager
865146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * state. If the BackgroundManager was released, the BackgroundManager
866146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * inherits the current state from the continuity service.
86717993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
86817993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void release() {
8693d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        if (DEBUG) Log.v(TAG, "release " + this);
8702e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        if (mLayerDrawable != null) {
871d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mLayerDrawable.clearDrawable(R.id.background_imagein, mContext);
872d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
873d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mLayerDrawable.clearDrawable(R.id.background_theme, mContext);
8742e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mLayerDrawable = null;
8752e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        }
87617993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mChangeRunnable != null) {
8770f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mHandler.removeCallbacks(mChangeRunnable);
87817993c442c26161f684d6c0c6867a746f3148548Craig Stout            mChangeRunnable = null;
87917993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
88017993c442c26161f684d6c0c6867a746f3148548Craig Stout        releaseBackgroundBitmap();
88117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
88217993c442c26161f684d6c0c6867a746f3148548Craig Stout
88317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void releaseBackgroundBitmap() {
88417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBackgroundDrawable = null;
88517993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
88617993c442c26161f684d6c0c6867a746f3148548Craig Stout
887f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    private void setBackgroundDrawable(Drawable drawable) {
888f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        mBackgroundDrawable = drawable;
889f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        mService.setDrawable(mBackgroundDrawable);
890f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    }
891f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
8920f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    /**
8930f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Sets the drawable used as a dim layer.
8940f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     */
8950f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    public void setDimLayer(Drawable drawable) {
8960f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mDimDrawable = drawable;
8970f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        updateDimWrapper();
8980f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
8990f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
9000f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    /**
9010f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Returns the drawable used as a dim layer.
9020f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     */
9030f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    public Drawable getDimLayer() {
9040f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        return mDimDrawable;
9050f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
9060f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
9070f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    /**
9080f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Returns the default drawable used as a dim layer.
9090f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     */
9100f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    public Drawable getDefaultDimLayer() {
9110f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        return ContextCompat.getDrawable(mContext, R.color.lb_background_protection);
9120f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
9130f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
914f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    private void postChangeRunnable() {
915f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        if (mChangeRunnable == null || !mChangeRunnablePending) {
916f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            return;
917f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
918f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
919f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // Postpone a pending change runnable until: no existing change animation in progress &&
920f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // activity is resumed (in the foreground) && layerdrawable fully opaque.
921f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // If the layerdrawable is translucent then an activity transition is in progress
922f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // and we want to use the optimized drawing path for performance reasons (see
923f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // OptimizedTranslucentLayerDrawable).
924f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        if (mAnimator.isStarted()) {
925f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (DEBUG) Log.v(TAG, "animation in progress");
926f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        } else if (!mFragmentState.isResumed()) {
927f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (DEBUG) Log.v(TAG, "not resumed");
928f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        } else if (mLayerDrawable.getAlpha() < FULL_ALPHA) {
929f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (DEBUG) Log.v(TAG, "in transition, alpha " + mLayerDrawable.getAlpha());
930f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        } else {
931f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            long delayMs = getRunnableDelay();
932f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (DEBUG) Log.v(TAG, "posting runnable delayMs " + delayMs);
933f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mLastSetTime = System.currentTimeMillis();
934f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mHandler.postDelayed(mChangeRunnable, delayMs);
935f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mChangeRunnablePending = false;
936f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        }
937f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout    }
938f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout
93917993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void updateImmediate() {
94017993c442c26161f684d6c0c6867a746f3148548Craig Stout        lazyInit();
94117993c442c26161f684d6c0c6867a746f3148548Craig Stout
9422590c39739945451f80dcf8667709b93293fc8bcCraig Stout        DrawableWrapper colorWrapper = getColorWrapper();
9432590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (colorWrapper != null) {
9442590c39739945451f80dcf8667709b93293fc8bcCraig Stout            colorWrapper.setColor(mBackgroundColor);
9452590c39739945451f80dcf8667709b93293fc8bcCraig Stout        }
9462590c39739945451f80dcf8667709b93293fc8bcCraig Stout        DrawableWrapper dimWrapper = getDimWrapper();
9472590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (dimWrapper != null) {
9482590c39739945451f80dcf8667709b93293fc8bcCraig Stout            dimWrapper.setAlpha(mBackgroundColor == Color.TRANSPARENT ? 0 : DIM_ALPHA_ON_SOLID);
94917993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
95017993c442c26161f684d6c0c6867a746f3148548Craig Stout        showWallpaper(mBackgroundColor == Color.TRANSPARENT);
95117993c442c26161f684d6c0c6867a746f3148548Craig Stout
95217993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mBackgroundDrawable == null) {
953d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mLayerDrawable.clearDrawable(R.id.background_imagein, mContext);
95417993c442c26161f684d6c0c6867a746f3148548Craig Stout        } else {
95517993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "Background drawable is available");
9562590c39739945451f80dcf8667709b93293fc8bcCraig Stout            mLayerDrawable.updateDrawable(
957d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    R.id.background_imagein, mBackgroundDrawable);
9582590c39739945451f80dcf8667709b93293fc8bcCraig Stout            if (dimWrapper != null) {
9592590c39739945451f80dcf8667709b93293fc8bcCraig Stout                dimWrapper.setAlpha(FULL_ALPHA);
96017993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
96117993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
96217993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
96317993c442c26161f684d6c0c6867a746f3148548Craig Stout
96417993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
965a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the background to the given color. The timing for when this becomes
966146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * visible in the app is undefined and may take place after a small delay.
96717993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
96870acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye    public void setColor(@ColorInt int color) {
96917993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "setColor " + Integer.toHexString(color));
97017993c442c26161f684d6c0c6867a746f3148548Craig Stout
97117993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBackgroundColor = color;
97217993c442c26161f684d6c0c6867a746f3148548Craig Stout        mService.setColor(mBackgroundColor);
97317993c442c26161f684d6c0c6867a746f3148548Craig Stout
9742590c39739945451f80dcf8667709b93293fc8bcCraig Stout        DrawableWrapper colorWrapper = getColorWrapper();
9752590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (colorWrapper != null) {
9762590c39739945451f80dcf8667709b93293fc8bcCraig Stout            colorWrapper.setColor(mBackgroundColor);
97717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
97817993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
97917993c442c26161f684d6c0c6867a746f3148548Craig Stout
98017993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
981a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the given drawable into the background. The provided Drawable will be
9825a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * used unmodified as the background, without any scaling or cropping
9835a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * applied to it. The timing for when this becomes visible in the app is
9845a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * undefined and may take place after a small delay.
98517993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
98617993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void setDrawable(Drawable drawable) {
98717993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "setBackgroundDrawable " + drawable);
98817993c442c26161f684d6c0c6867a746f3148548Craig Stout        setDrawableInternal(drawable);
98917993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
99017993c442c26161f684d6c0c6867a746f3148548Craig Stout
99117993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void setDrawableInternal(Drawable drawable) {
9925a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        if (!mAttached) {
9935a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            throw new IllegalStateException("Must attach before setting background drawable");
9945a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        }
99517993c442c26161f684d6c0c6867a746f3148548Craig Stout
99617993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mChangeRunnable != null) {
997d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout            if (sameDrawable(drawable, mChangeRunnable.mDrawable)) {
9980f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                if (DEBUG) Log.v(TAG, "new drawable same as pending");
999d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout                return;
1000d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout            }
10010f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mHandler.removeCallbacks(mChangeRunnable);
1002f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            mChangeRunnable = null;
100317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
1004d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
1005f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // If layer drawable is null then the activity hasn't started yet.
1006f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // If the layer drawable alpha is zero then the activity transition hasn't started yet.
1007f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // In these cases we can update the background immediately and let activity transition
1008f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        // fade it in.
1009f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        if (mLayerDrawable == null || mLayerDrawable.getAlpha() == 0) {
1010f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            if (DEBUG) Log.v(TAG, "setDrawableInternal null or alpha is zero");
1011f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            setBackgroundDrawable(drawable);
1012d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            updateImmediate();
1013d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return;
1014d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
1015d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
101617993c442c26161f684d6c0c6867a746f3148548Craig Stout        mChangeRunnable = new ChangeBackgroundRunnable(drawable);
1017f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        mChangeRunnablePending = true;
101817993c442c26161f684d6c0c6867a746f3148548Craig Stout
1019f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout        postChangeRunnable();
102017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
102117993c442c26161f684d6c0c6867a746f3148548Craig Stout
10220f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private long getRunnableDelay() {
10230f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        return Math.max(0, mLastSetTime + CHANGE_BG_DELAY_MS - System.currentTimeMillis());
10240f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
10250f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
102617993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
1027a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the given bitmap into the background. When using setBitmap to set the
10285a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * background, the provided bitmap will be scaled and cropped to correctly
10295a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * fit within the dimensions of the view. The timing for when this becomes
1030146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * visible in the app is undefined and may take place after a small delay.
103117993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
103217993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void setBitmap(Bitmap bitmap) {
10335a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        if (DEBUG) {
10345a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            Log.v(TAG, "setBitmap " + bitmap);
10355a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        }
10365a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
10375a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        if (bitmap == null) {
10385a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            setDrawableInternal(null);
10395a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            return;
10405a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        }
104117993c442c26161f684d6c0c6867a746f3148548Craig Stout
104217993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
10435a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            if (DEBUG) {
10445a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima                Log.v(TAG, "invalid bitmap width or height");
10455a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            }
104617993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
104717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
104817993c442c26161f684d6c0c6867a746f3148548Craig Stout
10497f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        Matrix matrix = null;
105017993c442c26161f684d6c0c6867a746f3148548Craig Stout
10517f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if ((bitmap.getWidth() != mWidthPx || bitmap.getHeight() != mHeightPx)) {
10525a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            int dwidth = bitmap.getWidth();
10535a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            int dheight = bitmap.getHeight();
10545a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            float scale;
10555a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
10567f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            // Scale proportionately to fit width and height.
10575a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            if (dwidth * mHeightPx > mWidthPx * dheight) {
10585a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima                scale = (float) mHeightPx / (float) dheight;
10595a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            } else {
10605a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima                scale = (float) mWidthPx / (float) dwidth;
10615a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            }
10625a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
10635a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            int subX = Math.min((int) (mWidthPx / scale), dwidth);
10647f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            int dx = Math.max(0, (dwidth - subX) / 2);
10655a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
10667f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            matrix = new Matrix();
10677f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            matrix.setScale(scale, scale);
10687f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            matrix.preTranslate(-dx, 0);
10697f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
10707f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            if (DEBUG) Log.v(TAG, "original image size " + bitmap.getWidth() + "x" + bitmap.getHeight() +
10717f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                    " scale " + scale + " dx " + dx);
107217993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
107317993c442c26161f684d6c0c6867a746f3148548Craig Stout
10747f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap, matrix);
107517993c442c26161f684d6c0c6867a746f3148548Craig Stout
107617993c442c26161f684d6c0c6867a746f3148548Craig Stout        setDrawableInternal(bitmapDrawable);
107717993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
107817993c442c26161f684d6c0c6867a746f3148548Craig Stout
107917993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void applyBackgroundChanges() {
1080d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        if (!mAttached) {
108117993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
108217993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
108317993c442c26161f684d6c0c6867a746f3148548Craig Stout
108417993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "applyBackgroundChanges drawable " + mBackgroundDrawable);
108517993c442c26161f684d6c0c6867a746f3148548Craig Stout
10860f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        int dimAlpha = -1;
108717993c442c26161f684d6c0c6867a746f3148548Craig Stout
10882590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (getImageOutWrapper() != null) {
10890f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            dimAlpha = mBackgroundColor == Color.TRANSPARENT ? 0 : DIM_ALPHA_ON_SOLID;
109017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
109117993c442c26161f684d6c0c6867a746f3148548Craig Stout
10922590c39739945451f80dcf8667709b93293fc8bcCraig Stout        DrawableWrapper imageInWrapper = getImageInWrapper();
10932590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (imageInWrapper == null && mBackgroundDrawable != null) {
109417993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "creating new imagein drawable");
10952590c39739945451f80dcf8667709b93293fc8bcCraig Stout            imageInWrapper = mLayerDrawable.updateDrawable(
1096d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    R.id.background_imagein, mBackgroundDrawable);
10972590c39739945451f80dcf8667709b93293fc8bcCraig Stout            if (DEBUG) Log.v(TAG, "imageInWrapper animation starting");
10982590c39739945451f80dcf8667709b93293fc8bcCraig Stout            imageInWrapper.setAlpha(0);
10992e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            dimAlpha = FULL_ALPHA;
110017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
110117993c442c26161f684d6c0c6867a746f3148548Craig Stout
11020f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.setDuration(FADE_DURATION);
11030f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.start();
11040f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
11052590c39739945451f80dcf8667709b93293fc8bcCraig Stout        DrawableWrapper dimWrapper = getDimWrapper();
11062590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (dimWrapper != null && dimAlpha >= 0) {
110717993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "dimwrapper animation starting to " + dimAlpha);
11080f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mDimAnimator.cancel();
11092590c39739945451f80dcf8667709b93293fc8bcCraig Stout            mDimAnimator.setIntValues(dimWrapper.getAlpha(), dimAlpha);
11100f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mDimAnimator.setDuration(FADE_DURATION);
11110f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mDimAnimator.setInterpolator(
11120f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                    dimAlpha == FULL_ALPHA ? mDecelerateInterpolator : mAccelerateInterpolator);
11130f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mDimAnimator.start();
111417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
111517993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
111617993c442c26161f684d6c0c6867a746f3148548Craig Stout
111717993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
1118146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Returns the current background color.
111917993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
112070acb0c19be3831a2080e4f902324de16bfbf62eTor Norbye    @ColorInt
112117993c442c26161f684d6c0c6867a746f3148548Craig Stout    public final int getColor() {
112217993c442c26161f684d6c0c6867a746f3148548Craig Stout        return mBackgroundColor;
112317993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
112417993c442c26161f684d6c0c6867a746f3148548Craig Stout
112517993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
1126146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Returns the current background {@link Drawable}.
112717993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
112817993c442c26161f684d6c0c6867a746f3148548Craig Stout    public Drawable getDrawable() {
112917993c442c26161f684d6c0c6867a746f3148548Craig Stout        return mBackgroundDrawable;
113017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
113117993c442c26161f684d6c0c6867a746f3148548Craig Stout
11327f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    private boolean sameDrawable(Drawable first, Drawable second) {
11337f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if (first == null || second == null) {
11347f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            return false;
11357f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
11367f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if (first == second) {
11377f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            return true;
11387f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
11397f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if (first instanceof BitmapDrawable && second instanceof BitmapDrawable) {
11407f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            if (((BitmapDrawable) first).getBitmap().sameAs(((BitmapDrawable) second).getBitmap())) {
11417f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                return true;
11427f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            }
11437f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
11447f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        return false;
11457f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    }
11467f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
114717993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
114817993c442c26161f684d6c0c6867a746f3148548Craig Stout     * Task which changes the background.
114917993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
115017993c442c26161f684d6c0c6867a746f3148548Craig Stout    class ChangeBackgroundRunnable implements Runnable {
115117993c442c26161f684d6c0c6867a746f3148548Craig Stout        private Drawable mDrawable;
115217993c442c26161f684d6c0c6867a746f3148548Craig Stout
115317993c442c26161f684d6c0c6867a746f3148548Craig Stout        ChangeBackgroundRunnable(Drawable drawable) {
115417993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = drawable;
115517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
115617993c442c26161f684d6c0c6867a746f3148548Craig Stout
115717993c442c26161f684d6c0c6867a746f3148548Craig Stout        @Override
115817993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void run() {
11590f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            runTask();
11600f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mChangeRunnable = null;
116117993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
116217993c442c26161f684d6c0c6867a746f3148548Craig Stout
116317993c442c26161f684d6c0c6867a746f3148548Craig Stout        private void runTask() {
1164d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            if (mLayerDrawable == null) {
1165d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (DEBUG) Log.v(TAG, "runTask while released - should not happen");
1166d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                return;
1167d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
116817993c442c26161f684d6c0c6867a746f3148548Craig Stout
11697f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            if (sameDrawable(mDrawable, mBackgroundDrawable)) {
11700f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                if (DEBUG) Log.v(TAG, "new drawable same as current");
11712e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                return;
117217993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
117317993c442c26161f684d6c0c6867a746f3148548Craig Stout
11742e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            releaseBackgroundBitmap();
11752e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
11762590c39739945451f80dcf8667709b93293fc8bcCraig Stout            DrawableWrapper imageInWrapper = getImageInWrapper();
11772590c39739945451f80dcf8667709b93293fc8bcCraig Stout            if (imageInWrapper != null) {
11780f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                if (DEBUG) Log.v(TAG, "moving image in to image out");
11792e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                // Order is important! Setting a drawable "removes" the
11802e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                // previous one from the view
1181d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                mLayerDrawable.clearDrawable(R.id.background_imagein, mContext);
11822590c39739945451f80dcf8667709b93293fc8bcCraig Stout                mLayerDrawable.updateDrawable(R.id.background_imageout,
11832590c39739945451f80dcf8667709b93293fc8bcCraig Stout                        imageInWrapper.getDrawable());
118417993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
11852e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
1186f684b94c5f316e9735abc298e00c3f61642b821eCraig Stout            setBackgroundDrawable(mDrawable);
11872e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            applyBackgroundChanges();
118817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
118917993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
119017993c442c26161f684d6c0c6867a746f3148548Craig Stout
1191d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout    private static Drawable createEmptyDrawable(Context context) {
119217993c442c26161f684d6c0c6867a746f3148548Craig Stout        Bitmap bitmap = null;
1193d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        return new BitmapDrawable(context.getResources(), bitmap);
119417993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
119517993c442c26161f684d6c0c6867a746f3148548Craig Stout
119617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void showWallpaper(boolean show) {
119717993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mWindow == null) {
119817993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
119917993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
120017993c442c26161f684d6c0c6867a746f3148548Craig Stout
120117993c442c26161f684d6c0c6867a746f3148548Craig Stout        WindowManager.LayoutParams layoutParams = mWindow.getAttributes();
120217993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (show) {
120317993c442c26161f684d6c0c6867a746f3148548Craig Stout            if ((layoutParams.flags & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
120417993c442c26161f684d6c0c6867a746f3148548Craig Stout                return;
120517993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
120617993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "showing wallpaper");
120717993c442c26161f684d6c0c6867a746f3148548Craig Stout            layoutParams.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
120817993c442c26161f684d6c0c6867a746f3148548Craig Stout        } else {
120917993c442c26161f684d6c0c6867a746f3148548Craig Stout            if ((layoutParams.flags & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) == 0) {
121017993c442c26161f684d6c0c6867a746f3148548Craig Stout                return;
121117993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
121217993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "hiding wallpaper");
121317993c442c26161f684d6c0c6867a746f3148548Craig Stout            layoutParams.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
121417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
121517993c442c26161f684d6c0c6867a746f3148548Craig Stout
121617993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindow.setAttributes(layoutParams);
121717993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
121817993c442c26161f684d6c0c6867a746f3148548Craig Stout}
1219