BackgroundManager.java revision 2590c39739945451f80dcf8667709b93293fc8bc
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
18d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stoutimport android.graphics.PixelFormat;
1917993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.support.v17.leanback.R;
203d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stoutimport android.animation.Animator;
217e22f555da71f49a32420965817c760522b95963Craig Stoutimport android.animation.ValueAnimator;
2217993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.app.Activity;
2317993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.content.Context;
247f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.content.res.Resources;
2517993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.content.res.TypedArray;
2617993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.Bitmap;
277f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.graphics.Canvas;
2817993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.Color;
297f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.graphics.ColorFilter;
3017993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.Matrix;
317f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.graphics.Paint;
3217993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.drawable.ColorDrawable;
3317993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.drawable.Drawable;
3417993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.drawable.LayerDrawable;
3517993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.os.Handler;
362590c39739945451f80dcf8667709b93293fc8bcCraig Stoutimport android.support.v17.leanback.widget.BackgroundHelper;
370f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stoutimport android.support.v4.view.animation.FastOutLinearInInterpolator;
3817993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.util.Log;
3917993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.LayoutInflater;
4017993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.View;
4117993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.ViewGroup;
4217993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.Window;
4317993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.WindowManager;
447e22f555da71f49a32420965817c760522b95963Craig Stoutimport android.view.animation.Interpolator;
450f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stoutimport android.view.animation.AnimationUtils;
46fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Guimport android.support.v4.app.FragmentActivity;
4760c3b420827d0520509387f1abe3e3d8168e2279Dake Guimport android.support.v4.content.ContextCompat;
4817993c442c26161f684d6c0c6867a746f3148548Craig Stout
4917993c442c26161f684d6c0c6867a746f3148548Craig Stout/**
50146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * Supports background image continuity between multiple Activities.
5117993c442c26161f684d6c0c6867a746f3148548Craig Stout *
52146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>An Activity should instantiate a BackgroundManager and {@link #attach}
53146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * to the Activity's window.  When the Activity is started, the background is
5417993c442c26161f684d6c0c6867a746f3148548Craig Stout * initialized to the current background values stored in a continuity service.
5517993c442c26161f684d6c0c6867a746f3148548Craig Stout * The background continuity service is updated as the background is updated.
5617993c442c26161f684d6c0c6867a746f3148548Craig Stout *
57146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>At some point, for example when it is stopped, the Activity may release
58146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * its background state.
592e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout *
60146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>When an Activity is resumed, if the BackgroundManager has not been
61146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * released, the continuity service is updated from the BackgroundManager state.
62146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * If the BackgroundManager was released, the BackgroundManager inherits the
63146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * current state from the continuity service.
6417993c442c26161f684d6c0c6867a746f3148548Craig Stout *
65146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>When the last Activity is destroyed, the background state is reset.
6617993c442c26161f684d6c0c6867a746f3148548Craig Stout *
67146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>Backgrounds consist of several layers, from back to front:
68146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <ul>
69146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   <li>the background Drawable of the theme</li>
70146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   <li>a solid color (set via {@link #setColor})</li>
71146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   <li>two Drawables, previous and current (set via {@link #setBitmap} or
72146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   {@link #setDrawable}), which may be in transition</li>
73146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * </ul>
7417993c442c26161f684d6c0c6867a746f3148548Craig Stout *
75146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>BackgroundManager holds references to potentially large bitmap Drawables.
76146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * Call {@link #release} to release these references when the Activity is not
7717993c442c26161f684d6c0c6867a746f3148548Craig Stout * visible.
7817993c442c26161f684d6c0c6867a746f3148548Craig Stout */
79146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn// TODO: support for multiple app processes requires a proper android service
80146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn// instead of the shared memory "service" implemented here. Such a service could
81146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn// support continuity between fragments of different applications if desired.
8217993c442c26161f684d6c0c6867a746f3148548Craig Stoutpublic final class BackgroundManager {
8317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final String TAG = "BackgroundManager";
8417993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final boolean DEBUG = false;
8517993c442c26161f684d6c0c6867a746f3148548Craig Stout
8617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final int FULL_ALPHA = 255;
8717993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final int DIM_ALPHA_ON_SOLID = (int) (0.8f * FULL_ALPHA);
8817993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final int CHANGE_BG_DELAY_MS = 500;
893d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout    private static final int FADE_DURATION = 500;
9017993c442c26161f684d6c0c6867a746f3148548Craig Stout
9117993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
9217993c442c26161f684d6c0c6867a746f3148548Craig Stout     * Using a separate window for backgrounds can improve graphics performance by
9317993c442c26161f684d6c0c6867a746f3148548Craig Stout     * leveraging hardware display layers.
9417993c442c26161f684d6c0c6867a746f3148548Craig Stout     * TODO: support a leanback configuration option.
9517993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
9617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final boolean USE_SEPARATE_WINDOW = false;
9717993c442c26161f684d6c0c6867a746f3148548Craig Stout
9817993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final String WINDOW_NAME = "BackgroundManager";
997f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu    private static final String FRAGMENT_TAG = BackgroundManager.class.getCanonicalName();
10017993c442c26161f684d6c0c6867a746f3148548Craig Stout
10117993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Context mContext;
10217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Handler mHandler;
10317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Window mWindow;
10417993c442c26161f684d6c0c6867a746f3148548Craig Stout    private WindowManager mWindowManager;
10517993c442c26161f684d6c0c6867a746f3148548Craig Stout    private View mBgView;
10617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private BackgroundContinuityService mService;
10717993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mThemeDrawableResourceId;
10817993c442c26161f684d6c0c6867a746f3148548Craig Stout
10917993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mHeightPx;
11017993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mWidthPx;
11117993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Drawable mBackgroundDrawable;
11217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mBackgroundColor;
11317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private boolean mAttached;
1140f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private long mLastSetTime;
1150f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
1160f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final Interpolator mAccelerateInterpolator;
1170f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final Interpolator mDecelerateInterpolator;
1180f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final ValueAnimator mAnimator;
1190f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final ValueAnimator mDimAnimator;
12017993c442c26161f684d6c0c6867a746f3148548Craig Stout
1217f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    private static class BitmapDrawable extends Drawable {
1227f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1233d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        static class ConstantState extends Drawable.ConstantState {
1243d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            Bitmap mBitmap;
1253d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            Matrix mMatrix;
1263d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            Paint mPaint;
1273d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1283d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            @Override
1293d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            public Drawable newDrawable() {
1303d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                return new BitmapDrawable(null, mBitmap, mMatrix);
1313d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            }
1323d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1333d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            @Override
1343d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            public int getChangingConfigurations() {
1353d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                return 0;
1363d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            }
1373d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
1383d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1393d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        private ConstantState mState = new ConstantState();
1407f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1417f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        BitmapDrawable(Resources resources, Bitmap bitmap) {
1427f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            this(resources, bitmap, null);
1437f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1447f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1457f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        BitmapDrawable(Resources resources, Bitmap bitmap, Matrix matrix) {
1463d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mState.mBitmap = bitmap;
1473d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mState.mMatrix = matrix != null ? matrix : new Matrix();
1483d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mState.mPaint = new Paint();
1493d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mState.mPaint.setFilterBitmap(true);
1507f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1517f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1527f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        Bitmap getBitmap() {
1533d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            return mState.mBitmap;
1547f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1557f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1567f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1577f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public void draw(Canvas canvas) {
1583d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (mState.mBitmap == null) {
1597f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                return;
1607f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            }
1613d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            canvas.drawBitmap(mState.mBitmap, mState.mMatrix, mState.mPaint);
1627f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1637f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1647f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1657f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public int getOpacity() {
166d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return android.graphics.PixelFormat.TRANSLUCENT;
1677f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1687f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1697f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1707f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public void setAlpha(int alpha) {
1713d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (mState.mPaint.getAlpha() != alpha) {
1723d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                mState.mPaint.setAlpha(alpha);
1737f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                invalidateSelf();
1747f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            }
1757f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1767f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1777f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1787f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public void setColorFilter(ColorFilter cf) {
1797f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            // Abstract in Drawable, not implemented
1807f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1813d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1823d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        @Override
1833d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        public ConstantState getConstantState() {
1843d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            return mState;
1853d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
1867f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    }
1877f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1887f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    private static class DrawableWrapper {
189d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        private int mAlpha = FULL_ALPHA;
190d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        private Drawable mDrawable;
1917e22f555da71f49a32420965817c760522b95963Craig Stout
19217993c442c26161f684d6c0c6867a746f3148548Craig Stout        public DrawableWrapper(Drawable drawable) {
19317993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = drawable;
194d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            updateAlpha();
195d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
196d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public DrawableWrapper(DrawableWrapper wrapper, Drawable drawable) {
197d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mDrawable = drawable;
198d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mAlpha = wrapper.getAlpha();
199d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            updateAlpha();
20017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
20117993c442c26161f684d6c0c6867a746f3148548Craig Stout        public Drawable getDrawable() {
20217993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mDrawable;
20317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
20417993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setAlpha(int alpha) {
20517993c442c26161f684d6c0c6867a746f3148548Craig Stout            mAlpha = alpha;
206d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            updateAlpha();
20717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
20817993c442c26161f684d6c0c6867a746f3148548Craig Stout        public int getAlpha() {
20917993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mAlpha;
21017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
211d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        private void updateAlpha() {
212d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mDrawable.setAlpha(mAlpha);
213d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
21417993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setColor(int color) {
21517993c442c26161f684d6c0c6867a746f3148548Craig Stout            ((ColorDrawable) mDrawable).setColor(color);
21617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
21717993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
21817993c442c26161f684d6c0c6867a746f3148548Craig Stout
219d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout    private static class TranslucentLayerDrawable extends LayerDrawable {
220d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        private DrawableWrapper[] mWrapper;
221d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        private Paint mPaint = new Paint();
222d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
223d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public static TranslucentLayerDrawable create(LayerDrawable layerDrawable) {
224d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            int numChildren = layerDrawable.getNumberOfLayers();
225d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            Drawable[] drawables = new Drawable[numChildren];
226d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < numChildren; i++) {
227d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                drawables[i] = layerDrawable.getDrawable(i);
228d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
229d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            TranslucentLayerDrawable result = new TranslucentLayerDrawable(drawables);
230d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < numChildren; i++) {
231d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                result.setId(i, layerDrawable.getId(i));
232d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
233d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return result;
234d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
235d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
236d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public TranslucentLayerDrawable(Drawable[] drawables) {
237d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            super(drawables);
238d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            int count = drawables.length;
239d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mWrapper = new DrawableWrapper[count];
240d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < count; i++) {
241d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                mWrapper[i] = new DrawableWrapper(drawables[i]);
242d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
243d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
244d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
245d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
246d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public void setAlpha(int alpha) {
247d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            if (mPaint.getAlpha() != alpha) {
248d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                mPaint.setAlpha(alpha);
249d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                invalidateSelf();
250d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
251d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
252d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
2532590c39739945451f80dcf8667709b93293fc8bcCraig Stout        // Queried by system transitions
2542590c39739945451f80dcf8667709b93293fc8bcCraig Stout        public int getAlpha() {
2552590c39739945451f80dcf8667709b93293fc8bcCraig Stout            return mPaint.getAlpha();
2562590c39739945451f80dcf8667709b93293fc8bcCraig Stout        }
2572590c39739945451f80dcf8667709b93293fc8bcCraig Stout
258d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
259d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public Drawable mutate() {
260d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            Drawable drawable = super.mutate();
261d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            int count = getNumberOfLayers();
262d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < count; i++) {
263d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (mWrapper[i] != null) {
264d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    mWrapper[i] = new DrawableWrapper(mWrapper[i], getDrawable(i));
265d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                }
266d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
267d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return drawable;
268d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
269d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
270d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
271d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public int getOpacity() {
272d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return PixelFormat.TRANSLUCENT;
273d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
274d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
275d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
276d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public boolean setDrawableByLayerId(int id, Drawable drawable) {
277d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return updateDrawable(id, drawable) != null;
278d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
279d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
280d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public DrawableWrapper updateDrawable(int id, Drawable drawable) {
281d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            super.setDrawableByLayerId(id, drawable);
282d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < getNumberOfLayers(); i++) {
283d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (getId(i) == id) {
284d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    mWrapper[i] = new DrawableWrapper(drawable);
285d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    return mWrapper[i];
286d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                }
287d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
288d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return null;
289d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
290d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
291d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public void clearDrawable(int id, Context context) {
292d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < getNumberOfLayers(); i++) {
293d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (getId(i) == id) {
294d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    mWrapper[i] = null;
295d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    super.setDrawableByLayerId(id, createEmptyDrawable(context));
296d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    break;
297d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                }
298d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
299d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
300d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
301d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public DrawableWrapper findWrapperById(int id) {
302d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            for (int i = 0; i < getNumberOfLayers(); i++) {
303d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (getId(i) == id) {
304d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    return mWrapper[i];
305d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                }
306d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
307d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return null;
308d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
309d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
310d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        @Override
311d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        public void draw(Canvas canvas) {
312d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            if (mPaint.getAlpha() < FULL_ALPHA) {
313d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(),
314d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                        mPaint, Canvas.ALL_SAVE_FLAG);
315d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
316d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            super.draw(canvas);
317d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            if (mPaint.getAlpha() < FULL_ALPHA) {
318d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                canvas.restore();
319d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
320d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
321d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout    }
322d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
323d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout    private TranslucentLayerDrawable mLayerDrawable;
3240f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private Drawable mDimDrawable;
32517993c442c26161f684d6c0c6867a746f3148548Craig Stout    private ChangeBackgroundRunnable mChangeRunnable;
32617993c442c26161f684d6c0c6867a746f3148548Craig Stout
3270f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final Animator.AnimatorListener mAnimationListener = new Animator.AnimatorListener() {
3280f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
3290f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationStart(Animator animation) {
3300f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
3310f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
3320f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationRepeat(Animator animation) {
3330f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
3340f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
3350f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationEnd(Animator animation) {
3362590c39739945451f80dcf8667709b93293fc8bcCraig Stout            // imageInWrapper should be full alpha, but imageOutWrapper may not be 0 alpha
3372590c39739945451f80dcf8667709b93293fc8bcCraig Stout            DrawableWrapper imageOutWrapper = getImageOutWrapper();
3382590c39739945451f80dcf8667709b93293fc8bcCraig Stout            if (imageOutWrapper != null) {
3392590c39739945451f80dcf8667709b93293fc8bcCraig Stout                imageOutWrapper.setAlpha(0);
340d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
3410f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            if (mChangeRunnable != null) {
3420f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                long delayMs = getRunnableDelay();
3430f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                if (DEBUG) Log.v(TAG, "animation ended, found change runnable delayMs " + delayMs);
3440f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                mHandler.postDelayed(mChangeRunnable, delayMs);
3450f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            }
3460f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
3470f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
3480f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationCancel(Animator animation) {
3490f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
3500f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    };
3510f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
3520f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final ValueAnimator.AnimatorUpdateListener mAnimationUpdateListener =
3530f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            new ValueAnimator.AnimatorUpdateListener() {
3540f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
3550f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationUpdate(ValueAnimator animation) {
3560f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            int fadeInAlpha = (Integer) animation.getAnimatedValue();
3572590c39739945451f80dcf8667709b93293fc8bcCraig Stout            DrawableWrapper imageInWrapper = getImageInWrapper();
3582590c39739945451f80dcf8667709b93293fc8bcCraig Stout            if (imageInWrapper != null) {
3592590c39739945451f80dcf8667709b93293fc8bcCraig Stout                imageInWrapper.setAlpha(fadeInAlpha);
3602590c39739945451f80dcf8667709b93293fc8bcCraig Stout            } else {
3612590c39739945451f80dcf8667709b93293fc8bcCraig Stout                DrawableWrapper imageOutWrapper = getImageOutWrapper();
3622590c39739945451f80dcf8667709b93293fc8bcCraig Stout                if (imageOutWrapper != null) {
3632590c39739945451f80dcf8667709b93293fc8bcCraig Stout                    imageOutWrapper.setAlpha(255 - fadeInAlpha);
3642590c39739945451f80dcf8667709b93293fc8bcCraig Stout                }
3650f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            }
3660f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
3670f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    };
3680f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
3690f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private final ValueAnimator.AnimatorUpdateListener mDimUpdateListener =
3700f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            new ValueAnimator.AnimatorUpdateListener() {
3710f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        @Override
3720f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        public void onAnimationUpdate(ValueAnimator animation) {
3732590c39739945451f80dcf8667709b93293fc8bcCraig Stout            DrawableWrapper dimWrapper = getDimWrapper();
3742590c39739945451f80dcf8667709b93293fc8bcCraig Stout            if (dimWrapper != null) {
3752590c39739945451f80dcf8667709b93293fc8bcCraig Stout                dimWrapper.setAlpha((Integer) animation.getAnimatedValue());
3760f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            }
3770f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
3780f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    };
3790f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
38017993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
38117993c442c26161f684d6c0c6867a746f3148548Craig Stout     * Shared memory continuity service.
38217993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
38317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static class BackgroundContinuityService {
38417993c442c26161f684d6c0c6867a746f3148548Craig Stout        private static final String TAG = "BackgroundContinuityService";
38517993c442c26161f684d6c0c6867a746f3148548Craig Stout        private static boolean DEBUG = BackgroundManager.DEBUG;
38617993c442c26161f684d6c0c6867a746f3148548Craig Stout
38717993c442c26161f684d6c0c6867a746f3148548Craig Stout        private static BackgroundContinuityService sService = new BackgroundContinuityService();
38817993c442c26161f684d6c0c6867a746f3148548Craig Stout
38917993c442c26161f684d6c0c6867a746f3148548Craig Stout        private int mColor;
39017993c442c26161f684d6c0c6867a746f3148548Craig Stout        private Drawable mDrawable;
39117993c442c26161f684d6c0c6867a746f3148548Craig Stout        private int mCount;
39217993c442c26161f684d6c0c6867a746f3148548Craig Stout
39360c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        /** Single cache of theme drawable */
39460c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        private int mLastThemeDrawableId;
39560c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        private WeakReference<Drawable> mLastThemeDrawable;
39660c3b420827d0520509387f1abe3e3d8168e2279Dake Gu
39717993c442c26161f684d6c0c6867a746f3148548Craig Stout        private BackgroundContinuityService() {
39817993c442c26161f684d6c0c6867a746f3148548Craig Stout            reset();
39917993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
40017993c442c26161f684d6c0c6867a746f3148548Craig Stout
40117993c442c26161f684d6c0c6867a746f3148548Craig Stout        private void reset() {
40217993c442c26161f684d6c0c6867a746f3148548Craig Stout            mColor = Color.TRANSPARENT;
40317993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = null;
40417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
40517993c442c26161f684d6c0c6867a746f3148548Craig Stout
40617993c442c26161f684d6c0c6867a746f3148548Craig Stout        public static BackgroundContinuityService getInstance() {
40717993c442c26161f684d6c0c6867a746f3148548Craig Stout            final int count = sService.mCount++;
40817993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "Returning instance with new count " + count);
40917993c442c26161f684d6c0c6867a746f3148548Craig Stout            return sService;
41017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
41117993c442c26161f684d6c0c6867a746f3148548Craig Stout
41217993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void unref() {
41317993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (mCount <= 0) throw new IllegalStateException("Can't unref, count " + mCount);
41417993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (--mCount == 0) {
41517993c442c26161f684d6c0c6867a746f3148548Craig Stout                if (DEBUG) Log.v(TAG, "mCount is zero, resetting");
41617993c442c26161f684d6c0c6867a746f3148548Craig Stout                reset();
41717993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
41817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
41917993c442c26161f684d6c0c6867a746f3148548Craig Stout        public int getColor() {
42017993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mColor;
42117993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
42217993c442c26161f684d6c0c6867a746f3148548Craig Stout        public Drawable getDrawable() {
42317993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mDrawable;
42417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
42517993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setColor(int color) {
42617993c442c26161f684d6c0c6867a746f3148548Craig Stout            mColor = color;
42717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
42817993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setDrawable(Drawable drawable) {
42917993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = drawable;
43017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
43160c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        public Drawable getThemeDrawable(Context context, int themeDrawableId) {
43260c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            Drawable drawable = null;
43360c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            if (mLastThemeDrawable != null && mLastThemeDrawableId == themeDrawableId) {
43460c3b420827d0520509387f1abe3e3d8168e2279Dake Gu                drawable = mLastThemeDrawable.get();
43560c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            }
43660c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            if (drawable == null) {
43760c3b420827d0520509387f1abe3e3d8168e2279Dake Gu                drawable = ContextCompat.getDrawable(context, themeDrawableId);
43860c3b420827d0520509387f1abe3e3d8168e2279Dake Gu                mLastThemeDrawable = new WeakReference<Drawable>(drawable);
43960c3b420827d0520509387f1abe3e3d8168e2279Dake Gu                mLastThemeDrawableId = themeDrawableId;
44060c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            }
44160c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            return drawable.getConstantState().newDrawable(context.getResources()).mutate();
44260c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        }
44317993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
44417993c442c26161f684d6c0c6867a746f3148548Craig Stout
44517993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Drawable getThemeDrawable() {
44617993c442c26161f684d6c0c6867a746f3148548Craig Stout        Drawable drawable = null;
44717993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mThemeDrawableResourceId != -1) {
44860c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            drawable = mService.getThemeDrawable(mContext, mThemeDrawableResourceId);
44917993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
45017993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (drawable == null) {
451d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            drawable = createEmptyDrawable(mContext);
45217993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
45317993c442c26161f684d6c0c6867a746f3148548Craig Stout        return drawable;
45417993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
45517993c442c26161f684d6c0c6867a746f3148548Craig Stout
45617993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
457146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Get the BackgroundManager associated with the Activity.
4587f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu     * <p>
459146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * The BackgroundManager will be created on-demand for each individual
460146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Activity. Subsequent calls will return the same BackgroundManager created
461146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * for this Activity.
4627f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu     */
4637f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu    public static BackgroundManager getInstance(Activity activity) {
464fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        if (activity instanceof FragmentActivity) {
465fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            return getSupportInstance((FragmentActivity) activity);
466fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        }
4677f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
4687f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                .findFragmentByTag(FRAGMENT_TAG);
4697f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        if (fragment != null) {
4707f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            BackgroundManager manager = fragment.getBackgroundManager();
4717f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            if (manager != null) {
4727f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                return manager;
4737f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            }
4747f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            // manager is null: this is a fragment restored by FragmentManager,
4757f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            // fall through to create a BackgroundManager attach to it.
4767f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        }
477fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        return new BackgroundManager(activity, false);
478fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu    }
479fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu
480fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu    private static BackgroundManager getSupportInstance(FragmentActivity activity) {
481fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        BackgroundSupportFragment fragment = (BackgroundSupportFragment) activity
482fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu                .getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
483fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        if (fragment != null) {
484fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            BackgroundManager manager = fragment.getBackgroundManager();
485fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            if (manager != null) {
486fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu                return manager;
487fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            }
488fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            // manager is null: this is a fragment restored by FragmentManager,
489fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            // fall through to create a BackgroundManager attach to it.
490fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        }
491fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        return new BackgroundManager(activity, true);
4927f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu    }
4937f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu
494fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu    private BackgroundManager(Activity activity, boolean isSupportFragmentActivity) {
49517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mContext = activity;
49617993c442c26161f684d6c0c6867a746f3148548Craig Stout        mService = BackgroundContinuityService.getInstance();
49717993c442c26161f684d6c0c6867a746f3148548Craig Stout        mHeightPx = mContext.getResources().getDisplayMetrics().heightPixels;
49817993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWidthPx = mContext.getResources().getDisplayMetrics().widthPixels;
49917993c442c26161f684d6c0c6867a746f3148548Craig Stout        mHandler = new Handler();
50017993c442c26161f684d6c0c6867a746f3148548Craig Stout
5010f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        Interpolator defaultInterpolator = new FastOutLinearInInterpolator();
5020f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAccelerateInterpolator = AnimationUtils.loadInterpolator(mContext,
5030f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                android.R.anim.accelerate_interpolator);
5040f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mDecelerateInterpolator = AnimationUtils.loadInterpolator(mContext,
5050f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                android.R.anim.decelerate_interpolator);
5060f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
5070f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator = ValueAnimator.ofInt(0, FULL_ALPHA);
5080f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.addListener(mAnimationListener);
5090f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.addUpdateListener(mAnimationUpdateListener);
5100f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.setInterpolator(defaultInterpolator);
5110f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
5120f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mDimAnimator = new ValueAnimator();
5130f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mDimAnimator.addUpdateListener(mDimUpdateListener);
5140f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
51517993c442c26161f684d6c0c6867a746f3148548Craig Stout        TypedArray ta = activity.getTheme().obtainStyledAttributes(new int[] {
51617993c442c26161f684d6c0c6867a746f3148548Craig Stout                android.R.attr.windowBackground });
51717993c442c26161f684d6c0c6867a746f3148548Craig Stout        mThemeDrawableResourceId = ta.getResourceId(0, -1);
51817993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mThemeDrawableResourceId < 0) {
51917993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "BackgroundManager no window background resource!");
52017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
52117993c442c26161f684d6c0c6867a746f3148548Craig Stout        ta.recycle();
52217993c442c26161f684d6c0c6867a746f3148548Craig Stout
523fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        if (isSupportFragmentActivity) {
524fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            createSupportFragment((FragmentActivity) activity);
525fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        } else {
526fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            createFragment(activity);
527fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        }
52817993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
52917993c442c26161f684d6c0c6867a746f3148548Craig Stout
53017993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void createFragment(Activity activity) {
53117993c442c26161f684d6c0c6867a746f3148548Craig Stout        // Use a fragment to ensure the background manager gets detached properly.
532b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu        BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
5337f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                .findFragmentByTag(FRAGMENT_TAG);
534b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu        if (fragment == null) {
535b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu            fragment = new BackgroundFragment();
5367f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            activity.getFragmentManager().beginTransaction().add(fragment, FRAGMENT_TAG).commit();
5377f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        } else {
5387f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            if (fragment.getBackgroundManager() != null) {
5397f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                throw new IllegalStateException("Created duplicated BackgroundManager for same " +
5407f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                        "activity, please use getInstance() instead");
5417f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            }
542b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu        }
54317993c442c26161f684d6c0c6867a746f3148548Craig Stout        fragment.setBackgroundManager(this);
54417993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
54517993c442c26161f684d6c0c6867a746f3148548Craig Stout
546fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu    private void createSupportFragment(FragmentActivity activity) {
547fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        // Use a fragment to ensure the background manager gets detached properly.
548fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        BackgroundSupportFragment fragment = (BackgroundSupportFragment) activity
549fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu                .getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
550fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        if (fragment == null) {
551fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            fragment = new BackgroundSupportFragment();
552fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            activity.getSupportFragmentManager().beginTransaction().add(fragment, FRAGMENT_TAG)
553fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu                    .commit();
554fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        } else {
555fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            if (fragment.getBackgroundManager() != null) {
556fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu                throw new IllegalStateException("Created duplicated BackgroundManager for same " +
557fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu                    "activity, please use getInstance() instead");
558fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu            }
559fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        }
560fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu        fragment.setBackgroundManager(this);
561fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu    }
562fa9f41f8f5408b6e3931f1ab81f586a47cc2d975Dake Gu
5632590c39739945451f80dcf8667709b93293fc8bcCraig Stout    private DrawableWrapper getImageInWrapper() {
5642590c39739945451f80dcf8667709b93293fc8bcCraig Stout        return mLayerDrawable == null ? null :
5652590c39739945451f80dcf8667709b93293fc8bcCraig Stout                mLayerDrawable.findWrapperById(R.id.background_imagein);
5662590c39739945451f80dcf8667709b93293fc8bcCraig Stout    }
5672590c39739945451f80dcf8667709b93293fc8bcCraig Stout
5682590c39739945451f80dcf8667709b93293fc8bcCraig Stout    private DrawableWrapper getImageOutWrapper() {
5692590c39739945451f80dcf8667709b93293fc8bcCraig Stout        return mLayerDrawable == null ? null :
5702590c39739945451f80dcf8667709b93293fc8bcCraig Stout                mLayerDrawable.findWrapperById(R.id.background_imageout);
5712590c39739945451f80dcf8667709b93293fc8bcCraig Stout    }
5722590c39739945451f80dcf8667709b93293fc8bcCraig Stout
5732590c39739945451f80dcf8667709b93293fc8bcCraig Stout    private DrawableWrapper getDimWrapper() {
5742590c39739945451f80dcf8667709b93293fc8bcCraig Stout        return mLayerDrawable == null ? null :
5752590c39739945451f80dcf8667709b93293fc8bcCraig Stout                mLayerDrawable.findWrapperById(R.id.background_dim);
5762590c39739945451f80dcf8667709b93293fc8bcCraig Stout    }
5772590c39739945451f80dcf8667709b93293fc8bcCraig Stout
5782590c39739945451f80dcf8667709b93293fc8bcCraig Stout    private DrawableWrapper getColorWrapper() {
5792590c39739945451f80dcf8667709b93293fc8bcCraig Stout        return mLayerDrawable == null ? null :
5802590c39739945451f80dcf8667709b93293fc8bcCraig Stout                mLayerDrawable.findWrapperById(R.id.background_color);
5812590c39739945451f80dcf8667709b93293fc8bcCraig Stout    }
5822590c39739945451f80dcf8667709b93293fc8bcCraig Stout
58317993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
584146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Synchronizes state when the owning Activity is resumed.
58517993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
5862e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout    void onActivityResume() {
5872e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        if (mService == null) {
5882e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            return;
5892e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        }
5902e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        if (mLayerDrawable == null) {
5913d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (DEBUG) Log.v(TAG, "onActivityResume " + this +
5923d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                    " released state, syncing with service");
5932e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            syncWithService();
5942e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        } else {
5953d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (DEBUG) Log.v(TAG, "onActivityResume " + this + " updating service color "
5962e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                    + mBackgroundColor + " drawable " + mBackgroundDrawable);
5972e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mService.setColor(mBackgroundColor);
5982e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mService.setDrawable(mBackgroundDrawable);
5992e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        }
60017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
60117993c442c26161f684d6c0c6867a746f3148548Craig Stout
60217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void syncWithService() {
60317993c442c26161f684d6c0c6867a746f3148548Craig Stout        int color = mService.getColor();
60417993c442c26161f684d6c0c6867a746f3148548Craig Stout        Drawable drawable = mService.getDrawable();
60517993c442c26161f684d6c0c6867a746f3148548Craig Stout
60617993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "syncWithService color " + Integer.toHexString(color)
60717993c442c26161f684d6c0c6867a746f3148548Craig Stout                + " drawable " + drawable);
60817993c442c26161f684d6c0c6867a746f3148548Craig Stout
60917993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBackgroundColor = color;
6103d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        mBackgroundDrawable = drawable == null ? null :
6113d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            drawable.getConstantState().newDrawable().mutate();
6122e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
6132e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        updateImmediate();
61417993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
61517993c442c26161f684d6c0c6867a746f3148548Craig Stout
61617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void lazyInit() {
61717993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mLayerDrawable != null) {
61817993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
61917993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
62017993c442c26161f684d6c0c6867a746f3148548Craig Stout
621d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        LayerDrawable layerDrawable = (LayerDrawable)
622d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                ContextCompat.getDrawable(mContext, R.drawable.lb_background).mutate();
623d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        mLayerDrawable = TranslucentLayerDrawable.create(layerDrawable);
6242590c39739945451f80dcf8667709b93293fc8bcCraig Stout        BackgroundHelper.setBackgroundPreservingAlpha(mBgView, mLayerDrawable);
62517993c442c26161f684d6c0c6867a746f3148548Craig Stout
626d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
627d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        mLayerDrawable.updateDrawable(R.id.background_theme, getThemeDrawable());
628c149abce7f8a46f7c54211b5f97c5cd9ee729357Dake Gu
6290f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        updateDimWrapper();
6300f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
6310f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
6320f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private void updateDimWrapper() {
6330f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        if (mDimDrawable == null) {
6340f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mDimDrawable = getDefaultDimLayer();
6350f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        }
636d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        Drawable dimDrawable = mDimDrawable.getConstantState().newDrawable(
637d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                mContext.getResources()).mutate();
6382590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (mLayerDrawable != null) {
6392590c39739945451f80dcf8667709b93293fc8bcCraig Stout            mLayerDrawable.updateDrawable(R.id.background_dim, dimDrawable);
6402590c39739945451f80dcf8667709b93293fc8bcCraig Stout        }
64117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
64217993c442c26161f684d6c0c6867a746f3148548Craig Stout
64317993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
6440f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Make the background visible on the given Window.  The background manager must be attached
6450f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * when the background is set.
64617993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
64717993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void attach(Window window) {
64817993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (USE_SEPARATE_WINDOW) {
64917993c442c26161f684d6c0c6867a746f3148548Craig Stout            attachBehindWindow(window);
65017993c442c26161f684d6c0c6867a746f3148548Craig Stout        } else {
65117993c442c26161f684d6c0c6867a746f3148548Craig Stout            attachToView(window.getDecorView());
65217993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
65317993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
65417993c442c26161f684d6c0c6867a746f3148548Craig Stout
65517993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void attachBehindWindow(Window window) {
65617993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "attachBehindWindow " + window);
65717993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindow = window;
65817993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindowManager = window.getWindowManager();
65917993c442c26161f684d6c0c6867a746f3148548Craig Stout
66017993c442c26161f684d6c0c6867a746f3148548Craig Stout        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
66117993c442c26161f684d6c0c6867a746f3148548Craig Stout                // Media window sits behind the main application window
66217993c442c26161f684d6c0c6867a746f3148548Craig Stout                WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA,
66317993c442c26161f684d6c0c6867a746f3148548Craig Stout                // Avoid default to software format RGBA
66417993c442c26161f684d6c0c6867a746f3148548Craig Stout                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
66517993c442c26161f684d6c0c6867a746f3148548Craig Stout                android.graphics.PixelFormat.TRANSLUCENT);
66617993c442c26161f684d6c0c6867a746f3148548Craig Stout        params.setTitle(WINDOW_NAME);
66717993c442c26161f684d6c0c6867a746f3148548Craig Stout        params.width = ViewGroup.LayoutParams.MATCH_PARENT;
66817993c442c26161f684d6c0c6867a746f3148548Craig Stout        params.height = ViewGroup.LayoutParams.MATCH_PARENT;
66917993c442c26161f684d6c0c6867a746f3148548Craig Stout
67017993c442c26161f684d6c0c6867a746f3148548Craig Stout        View backgroundView = LayoutInflater.from(mContext).inflate(
67117993c442c26161f684d6c0c6867a746f3148548Craig Stout                R.layout.lb_background_window, null);
67217993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindowManager.addView(backgroundView, params);
67317993c442c26161f684d6c0c6867a746f3148548Craig Stout
67417993c442c26161f684d6c0c6867a746f3148548Craig Stout        attachToView(backgroundView);
67517993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
67617993c442c26161f684d6c0c6867a746f3148548Craig Stout
67717993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void attachToView(View sceneRoot) {
67817993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBgView = sceneRoot;
67917993c442c26161f684d6c0c6867a746f3148548Craig Stout        mAttached = true;
6802e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        syncWithService();
68117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
68217993c442c26161f684d6c0c6867a746f3148548Craig Stout
68317993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
6840f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Returns true if the background manager is currently attached; false otherwise.
6850f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     */
6860f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    public boolean isAttached() {
6870f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        return mAttached;
6880f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
6890f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
6900f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    /**
691146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Release references to Drawables and put the BackgroundManager into the
692146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * detached state. Called when the associated Activity is destroyed.
69317993c442c26161f684d6c0c6867a746f3148548Craig Stout     * @hide
69417993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
69517993c442c26161f684d6c0c6867a746f3148548Craig Stout    void detach() {
6963d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        if (DEBUG) Log.v(TAG, "detach " + this);
69717993c442c26161f684d6c0c6867a746f3148548Craig Stout        release();
69817993c442c26161f684d6c0c6867a746f3148548Craig Stout
69917993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mWindowManager != null && mBgView != null) {
70017993c442c26161f684d6c0c6867a746f3148548Craig Stout            mWindowManager.removeViewImmediate(mBgView);
70117993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
70217993c442c26161f684d6c0c6867a746f3148548Craig Stout
70317993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindowManager = null;
70417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindow = null;
70517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBgView = null;
70617993c442c26161f684d6c0c6867a746f3148548Craig Stout        mAttached = false;
70717993c442c26161f684d6c0c6867a746f3148548Craig Stout
70817993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mService != null) {
70917993c442c26161f684d6c0c6867a746f3148548Craig Stout            mService.unref();
71017993c442c26161f684d6c0c6867a746f3148548Craig Stout            mService = null;
71117993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
71217993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
71317993c442c26161f684d6c0c6867a746f3148548Craig Stout
71417993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
715146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Release references to Drawables. Typically called to reduce memory
716146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * overhead when not visible.
7172e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout     * <p>
718146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * When an Activity is resumed, if the BackgroundManager has not been
719146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * released, the continuity service is updated from the BackgroundManager
720146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * state. If the BackgroundManager was released, the BackgroundManager
721146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * inherits the current state from the continuity service.
72217993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
72317993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void release() {
7243d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        if (DEBUG) Log.v(TAG, "release " + this);
7252e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        if (mLayerDrawable != null) {
726d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mLayerDrawable.clearDrawable(R.id.background_imagein, mContext);
727d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
728d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mLayerDrawable.clearDrawable(R.id.background_theme, mContext);
7292e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mLayerDrawable = null;
7302e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        }
73117993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mChangeRunnable != null) {
7320f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mHandler.removeCallbacks(mChangeRunnable);
73317993c442c26161f684d6c0c6867a746f3148548Craig Stout            mChangeRunnable = null;
73417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
73517993c442c26161f684d6c0c6867a746f3148548Craig Stout        releaseBackgroundBitmap();
73617993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
73717993c442c26161f684d6c0c6867a746f3148548Craig Stout
73817993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void releaseBackgroundBitmap() {
73917993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBackgroundDrawable = null;
74017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
74117993c442c26161f684d6c0c6867a746f3148548Craig Stout
7420f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    /**
7430f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Sets the drawable used as a dim layer.
7440f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     */
7450f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    public void setDimLayer(Drawable drawable) {
7460f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mDimDrawable = drawable;
7470f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        updateDimWrapper();
7480f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
7490f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
7500f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    /**
7510f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Returns the drawable used as a dim layer.
7520f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     */
7530f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    public Drawable getDimLayer() {
7540f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        return mDimDrawable;
7550f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
7560f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
7570f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    /**
7580f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     * Returns the default drawable used as a dim layer.
7590f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout     */
7600f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    public Drawable getDefaultDimLayer() {
7610f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        return ContextCompat.getDrawable(mContext, R.color.lb_background_protection);
7620f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
7630f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
76417993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void updateImmediate() {
76517993c442c26161f684d6c0c6867a746f3148548Craig Stout        lazyInit();
76617993c442c26161f684d6c0c6867a746f3148548Craig Stout
7672590c39739945451f80dcf8667709b93293fc8bcCraig Stout        DrawableWrapper colorWrapper = getColorWrapper();
7682590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (colorWrapper != null) {
7692590c39739945451f80dcf8667709b93293fc8bcCraig Stout            colorWrapper.setColor(mBackgroundColor);
7702590c39739945451f80dcf8667709b93293fc8bcCraig Stout        }
7712590c39739945451f80dcf8667709b93293fc8bcCraig Stout        DrawableWrapper dimWrapper = getDimWrapper();
7722590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (dimWrapper != null) {
7732590c39739945451f80dcf8667709b93293fc8bcCraig Stout            dimWrapper.setAlpha(mBackgroundColor == Color.TRANSPARENT ? 0 : DIM_ALPHA_ON_SOLID);
77417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
77517993c442c26161f684d6c0c6867a746f3148548Craig Stout        showWallpaper(mBackgroundColor == Color.TRANSPARENT);
77617993c442c26161f684d6c0c6867a746f3148548Craig Stout
77717993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mBackgroundDrawable == null) {
778d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mLayerDrawable.clearDrawable(R.id.background_imagein, mContext);
77917993c442c26161f684d6c0c6867a746f3148548Craig Stout        } else {
78017993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "Background drawable is available");
7812590c39739945451f80dcf8667709b93293fc8bcCraig Stout            mLayerDrawable.updateDrawable(
782d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    R.id.background_imagein, mBackgroundDrawable);
7832590c39739945451f80dcf8667709b93293fc8bcCraig Stout            if (dimWrapper != null) {
7842590c39739945451f80dcf8667709b93293fc8bcCraig Stout                dimWrapper.setAlpha(FULL_ALPHA);
78517993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
78617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
78717993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
78817993c442c26161f684d6c0c6867a746f3148548Craig Stout
78917993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
790146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Set the background to the given color. The timing for when this becomes
791146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * visible in the app is undefined and may take place after a small delay.
79217993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
79317993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void setColor(int color) {
79417993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "setColor " + Integer.toHexString(color));
79517993c442c26161f684d6c0c6867a746f3148548Craig Stout
79617993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBackgroundColor = color;
79717993c442c26161f684d6c0c6867a746f3148548Craig Stout        mService.setColor(mBackgroundColor);
79817993c442c26161f684d6c0c6867a746f3148548Craig Stout
7992590c39739945451f80dcf8667709b93293fc8bcCraig Stout        DrawableWrapper colorWrapper = getColorWrapper();
8002590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (colorWrapper != null) {
8012590c39739945451f80dcf8667709b93293fc8bcCraig Stout            colorWrapper.setColor(mBackgroundColor);
80217993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
80317993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
80417993c442c26161f684d6c0c6867a746f3148548Craig Stout
80517993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
8065a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * Set the given drawable into the background. The provided Drawable will be
8075a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * used unmodified as the background, without any scaling or cropping
8085a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * applied to it. The timing for when this becomes visible in the app is
8095a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * undefined and may take place after a small delay.
81017993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
81117993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void setDrawable(Drawable drawable) {
81217993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "setBackgroundDrawable " + drawable);
81317993c442c26161f684d6c0c6867a746f3148548Craig Stout        setDrawableInternal(drawable);
81417993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
81517993c442c26161f684d6c0c6867a746f3148548Craig Stout
81617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void setDrawableInternal(Drawable drawable) {
8175a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        if (!mAttached) {
8185a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            throw new IllegalStateException("Must attach before setting background drawable");
8195a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        }
8200f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        long delayMs = getRunnableDelay();
8210f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mLastSetTime = System.currentTimeMillis();
82217993c442c26161f684d6c0c6867a746f3148548Craig Stout
82317993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mChangeRunnable != null) {
824d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout            if (sameDrawable(drawable, mChangeRunnable.mDrawable)) {
8250f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                if (DEBUG) Log.v(TAG, "new drawable same as pending");
826d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout                return;
827d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout            }
8280f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mHandler.removeCallbacks(mChangeRunnable);
82917993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
830d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
831d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        if (mLayerDrawable == null) {
832d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            if (DEBUG) Log.v(TAG, "setDrawableInternal while in released state");
833d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            mBackgroundDrawable = drawable;
834d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            updateImmediate();
835d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            return;
836d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        }
837d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout
83817993c442c26161f684d6c0c6867a746f3148548Craig Stout        mChangeRunnable = new ChangeBackgroundRunnable(drawable);
83917993c442c26161f684d6c0c6867a746f3148548Craig Stout
8400f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        if (mAnimator.isStarted()) {
8413d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (DEBUG) Log.v(TAG, "animation in progress");
8423d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        } else {
8430f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            if (DEBUG) Log.v(TAG, "posting runnable delayMs " + delayMs);
8440f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mHandler.postDelayed(mChangeRunnable, delayMs);
8453d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
84617993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
84717993c442c26161f684d6c0c6867a746f3148548Craig Stout
8480f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    private long getRunnableDelay() {
8490f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        return Math.max(0, mLastSetTime + CHANGE_BG_DELAY_MS - System.currentTimeMillis());
8500f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout    }
8510f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
85217993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
8535a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * Set the given bitmap into the background. When using setBitmap to set the
8545a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * background, the provided bitmap will be scaled and cropped to correctly
8555a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * fit within the dimensions of the view. The timing for when this becomes
856146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * visible in the app is undefined and may take place after a small delay.
85717993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
85817993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void setBitmap(Bitmap bitmap) {
8595a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        if (DEBUG) {
8605a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            Log.v(TAG, "setBitmap " + bitmap);
8615a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        }
8625a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
8635a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        if (bitmap == null) {
8645a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            setDrawableInternal(null);
8655a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            return;
8665a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        }
86717993c442c26161f684d6c0c6867a746f3148548Craig Stout
86817993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
8695a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            if (DEBUG) {
8705a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima                Log.v(TAG, "invalid bitmap width or height");
8715a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            }
87217993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
87317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
87417993c442c26161f684d6c0c6867a746f3148548Craig Stout
8757f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        Matrix matrix = null;
87617993c442c26161f684d6c0c6867a746f3148548Craig Stout
8777f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if ((bitmap.getWidth() != mWidthPx || bitmap.getHeight() != mHeightPx)) {
8785a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            int dwidth = bitmap.getWidth();
8795a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            int dheight = bitmap.getHeight();
8805a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            float scale;
8815a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
8827f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            // Scale proportionately to fit width and height.
8835a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            if (dwidth * mHeightPx > mWidthPx * dheight) {
8845a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima                scale = (float) mHeightPx / (float) dheight;
8855a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            } else {
8865a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima                scale = (float) mWidthPx / (float) dwidth;
8875a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            }
8885a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
8895a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            int subX = Math.min((int) (mWidthPx / scale), dwidth);
8907f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            int dx = Math.max(0, (dwidth - subX) / 2);
8915a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
8927f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            matrix = new Matrix();
8937f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            matrix.setScale(scale, scale);
8947f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            matrix.preTranslate(-dx, 0);
8957f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
8967f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            if (DEBUG) Log.v(TAG, "original image size " + bitmap.getWidth() + "x" + bitmap.getHeight() +
8977f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                    " scale " + scale + " dx " + dx);
89817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
89917993c442c26161f684d6c0c6867a746f3148548Craig Stout
9007f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap, matrix);
90117993c442c26161f684d6c0c6867a746f3148548Craig Stout
90217993c442c26161f684d6c0c6867a746f3148548Craig Stout        setDrawableInternal(bitmapDrawable);
90317993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
90417993c442c26161f684d6c0c6867a746f3148548Craig Stout
90517993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void applyBackgroundChanges() {
906d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        if (!mAttached) {
90717993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
90817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
90917993c442c26161f684d6c0c6867a746f3148548Craig Stout
91017993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "applyBackgroundChanges drawable " + mBackgroundDrawable);
91117993c442c26161f684d6c0c6867a746f3148548Craig Stout
9120f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        int dimAlpha = -1;
91317993c442c26161f684d6c0c6867a746f3148548Craig Stout
9142590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (getImageOutWrapper() != null) {
9150f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            dimAlpha = mBackgroundColor == Color.TRANSPARENT ? 0 : DIM_ALPHA_ON_SOLID;
91617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
91717993c442c26161f684d6c0c6867a746f3148548Craig Stout
9182590c39739945451f80dcf8667709b93293fc8bcCraig Stout        DrawableWrapper imageInWrapper = getImageInWrapper();
9192590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (imageInWrapper == null && mBackgroundDrawable != null) {
92017993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "creating new imagein drawable");
9212590c39739945451f80dcf8667709b93293fc8bcCraig Stout            imageInWrapper = mLayerDrawable.updateDrawable(
922d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                    R.id.background_imagein, mBackgroundDrawable);
9232590c39739945451f80dcf8667709b93293fc8bcCraig Stout            if (DEBUG) Log.v(TAG, "imageInWrapper animation starting");
9242590c39739945451f80dcf8667709b93293fc8bcCraig Stout            imageInWrapper.setAlpha(0);
9252e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            dimAlpha = FULL_ALPHA;
92617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
92717993c442c26161f684d6c0c6867a746f3148548Craig Stout
9280f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.setDuration(FADE_DURATION);
9290f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout        mAnimator.start();
9300f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout
9312590c39739945451f80dcf8667709b93293fc8bcCraig Stout        DrawableWrapper dimWrapper = getDimWrapper();
9322590c39739945451f80dcf8667709b93293fc8bcCraig Stout        if (dimWrapper != null && dimAlpha >= 0) {
93317993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "dimwrapper animation starting to " + dimAlpha);
9340f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mDimAnimator.cancel();
9352590c39739945451f80dcf8667709b93293fc8bcCraig Stout            mDimAnimator.setIntValues(dimWrapper.getAlpha(), dimAlpha);
9360f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mDimAnimator.setDuration(FADE_DURATION);
9370f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mDimAnimator.setInterpolator(
9380f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                    dimAlpha == FULL_ALPHA ? mDecelerateInterpolator : mAccelerateInterpolator);
9390f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mDimAnimator.start();
94017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
94117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
94217993c442c26161f684d6c0c6867a746f3148548Craig Stout
94317993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
944146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Returns the current background color.
94517993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
94617993c442c26161f684d6c0c6867a746f3148548Craig Stout    public final int getColor() {
94717993c442c26161f684d6c0c6867a746f3148548Craig Stout        return mBackgroundColor;
94817993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
94917993c442c26161f684d6c0c6867a746f3148548Craig Stout
95017993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
951146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Returns the current background {@link Drawable}.
95217993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
95317993c442c26161f684d6c0c6867a746f3148548Craig Stout    public Drawable getDrawable() {
95417993c442c26161f684d6c0c6867a746f3148548Craig Stout        return mBackgroundDrawable;
95517993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
95617993c442c26161f684d6c0c6867a746f3148548Craig Stout
9577f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    private boolean sameDrawable(Drawable first, Drawable second) {
9587f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if (first == null || second == null) {
9597f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            return false;
9607f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
9617f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if (first == second) {
9627f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            return true;
9637f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
9647f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if (first instanceof BitmapDrawable && second instanceof BitmapDrawable) {
9657f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            if (((BitmapDrawable) first).getBitmap().sameAs(((BitmapDrawable) second).getBitmap())) {
9667f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                return true;
9677f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            }
9687f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
9697f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        return false;
9707f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    }
9717f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
97217993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
97317993c442c26161f684d6c0c6867a746f3148548Craig Stout     * Task which changes the background.
97417993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
97517993c442c26161f684d6c0c6867a746f3148548Craig Stout    class ChangeBackgroundRunnable implements Runnable {
97617993c442c26161f684d6c0c6867a746f3148548Craig Stout        private Drawable mDrawable;
97717993c442c26161f684d6c0c6867a746f3148548Craig Stout
97817993c442c26161f684d6c0c6867a746f3148548Craig Stout        ChangeBackgroundRunnable(Drawable drawable) {
97917993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = drawable;
98017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
98117993c442c26161f684d6c0c6867a746f3148548Craig Stout
98217993c442c26161f684d6c0c6867a746f3148548Craig Stout        @Override
98317993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void run() {
9840f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            runTask();
9850f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout            mChangeRunnable = null;
98617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
98717993c442c26161f684d6c0c6867a746f3148548Craig Stout
98817993c442c26161f684d6c0c6867a746f3148548Craig Stout        private void runTask() {
989d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            if (mLayerDrawable == null) {
990d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                if (DEBUG) Log.v(TAG, "runTask while released - should not happen");
991d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                return;
992d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout            }
99317993c442c26161f684d6c0c6867a746f3148548Craig Stout
9947f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            if (sameDrawable(mDrawable, mBackgroundDrawable)) {
9950f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                if (DEBUG) Log.v(TAG, "new drawable same as current");
9962e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                return;
99717993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
99817993c442c26161f684d6c0c6867a746f3148548Craig Stout
9992e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            releaseBackgroundBitmap();
10002e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
10012590c39739945451f80dcf8667709b93293fc8bcCraig Stout            DrawableWrapper imageInWrapper = getImageInWrapper();
10022590c39739945451f80dcf8667709b93293fc8bcCraig Stout            if (imageInWrapper != null) {
10030f82bdd768ca56c4d14fa96afe8ff0355360148bCraig Stout                if (DEBUG) Log.v(TAG, "moving image in to image out");
10042e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                // Order is important! Setting a drawable "removes" the
10052e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                // previous one from the view
1006d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout                mLayerDrawable.clearDrawable(R.id.background_imagein, mContext);
10072590c39739945451f80dcf8667709b93293fc8bcCraig Stout                mLayerDrawable.updateDrawable(R.id.background_imageout,
10082590c39739945451f80dcf8667709b93293fc8bcCraig Stout                        imageInWrapper.getDrawable());
100917993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
10102e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
10112e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mBackgroundDrawable = mDrawable;
10122e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mService.setDrawable(mBackgroundDrawable);
10132e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
10142e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            applyBackgroundChanges();
101517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
101617993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
101717993c442c26161f684d6c0c6867a746f3148548Craig Stout
1018d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout    private static Drawable createEmptyDrawable(Context context) {
101917993c442c26161f684d6c0c6867a746f3148548Craig Stout        Bitmap bitmap = null;
1020d6c1bec6bd003158e79da4c945ee57f915336e12Craig Stout        return new BitmapDrawable(context.getResources(), bitmap);
102117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
102217993c442c26161f684d6c0c6867a746f3148548Craig Stout
102317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void showWallpaper(boolean show) {
102417993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mWindow == null) {
102517993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
102617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
102717993c442c26161f684d6c0c6867a746f3148548Craig Stout
102817993c442c26161f684d6c0c6867a746f3148548Craig Stout        WindowManager.LayoutParams layoutParams = mWindow.getAttributes();
102917993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (show) {
103017993c442c26161f684d6c0c6867a746f3148548Craig Stout            if ((layoutParams.flags & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
103117993c442c26161f684d6c0c6867a746f3148548Craig Stout                return;
103217993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
103317993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "showing wallpaper");
103417993c442c26161f684d6c0c6867a746f3148548Craig Stout            layoutParams.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
103517993c442c26161f684d6c0c6867a746f3148548Craig Stout        } else {
103617993c442c26161f684d6c0c6867a746f3148548Craig Stout            if ((layoutParams.flags & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) == 0) {
103717993c442c26161f684d6c0c6867a746f3148548Craig Stout                return;
103817993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
103917993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "hiding wallpaper");
104017993c442c26161f684d6c0c6867a746f3148548Craig Stout            layoutParams.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
104117993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
104217993c442c26161f684d6c0c6867a746f3148548Craig Stout
104317993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindow.setAttributes(layoutParams);
104417993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
104517993c442c26161f684d6c0c6867a746f3148548Craig Stout}
1046