BackgroundManager.java revision 60c3b420827d0520509387f1abe3e3d8168e2279
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
1817993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.support.v17.leanback.R;
193d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stoutimport android.animation.Animator;
207e22f555da71f49a32420965817c760522b95963Craig Stoutimport android.animation.ValueAnimator;
2117993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.app.Activity;
2217993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.content.Context;
237f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.content.res.Resources;
2417993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.content.res.TypedArray;
2517993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.Bitmap;
267f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.graphics.Canvas;
2717993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.Color;
287f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.graphics.ColorFilter;
2917993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.Matrix;
307f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stoutimport android.graphics.Paint;
3117993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.drawable.ColorDrawable;
3217993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.drawable.Drawable;
3317993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.graphics.drawable.LayerDrawable;
3417993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.os.Handler;
3517993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.util.Log;
3617993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.LayoutInflater;
3717993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.View;
3817993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.ViewGroup;
3917993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.Window;
4017993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.WindowManager;
417e22f555da71f49a32420965817c760522b95963Craig Stoutimport android.view.animation.Interpolator;
4217993c442c26161f684d6c0c6867a746f3148548Craig Stoutimport android.view.animation.LinearInterpolator;
4360c3b420827d0520509387f1abe3e3d8168e2279Dake Guimport android.support.v4.content.ContextCompat;
4417993c442c26161f684d6c0c6867a746f3148548Craig Stout
4517993c442c26161f684d6c0c6867a746f3148548Craig Stout/**
46146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * Supports background image continuity between multiple Activities.
4717993c442c26161f684d6c0c6867a746f3148548Craig Stout *
48146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>An Activity should instantiate a BackgroundManager and {@link #attach}
49146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * to the Activity's window.  When the Activity is started, the background is
5017993c442c26161f684d6c0c6867a746f3148548Craig Stout * initialized to the current background values stored in a continuity service.
5117993c442c26161f684d6c0c6867a746f3148548Craig Stout * The background continuity service is updated as the background is updated.
5217993c442c26161f684d6c0c6867a746f3148548Craig Stout *
53146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>At some point, for example when it is stopped, the Activity may release
54146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * its background state.
552e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout *
56146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>When an Activity is resumed, if the BackgroundManager has not been
57146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * released, the continuity service is updated from the BackgroundManager state.
58146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * If the BackgroundManager was released, the BackgroundManager inherits the
59146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * current state from the continuity service.
6017993c442c26161f684d6c0c6867a746f3148548Craig Stout *
61146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>When the last Activity is destroyed, the background state is reset.
6217993c442c26161f684d6c0c6867a746f3148548Craig Stout *
63146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>Backgrounds consist of several layers, from back to front:
64146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <ul>
65146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   <li>the background Drawable of the theme</li>
66146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   <li>a solid color (set via {@link #setColor})</li>
67146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   <li>two Drawables, previous and current (set via {@link #setBitmap} or
68146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn *   {@link #setDrawable}), which may be in transition</li>
69146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * </ul>
7017993c442c26161f684d6c0c6867a746f3148548Craig Stout *
71146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * <p>BackgroundManager holds references to potentially large bitmap Drawables.
72146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn * Call {@link #release} to release these references when the Activity is not
7317993c442c26161f684d6c0c6867a746f3148548Craig Stout * visible.
7417993c442c26161f684d6c0c6867a746f3148548Craig Stout */
75146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn// TODO: support for multiple app processes requires a proper android service
76146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn// instead of the shared memory "service" implemented here. Such a service could
77146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn// support continuity between fragments of different applications if desired.
7817993c442c26161f684d6c0c6867a746f3148548Craig Stoutpublic final class BackgroundManager {
7917993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final String TAG = "BackgroundManager";
8017993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final boolean DEBUG = false;
8117993c442c26161f684d6c0c6867a746f3148548Craig Stout
8217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final int FULL_ALPHA = 255;
8317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final int DIM_ALPHA_ON_SOLID = (int) (0.8f * FULL_ALPHA);
8417993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final int CHANGE_BG_DELAY_MS = 500;
853d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout    private static final int FADE_DURATION = 500;
8617993c442c26161f684d6c0c6867a746f3148548Craig Stout
8717993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
8817993c442c26161f684d6c0c6867a746f3148548Craig Stout     * Using a separate window for backgrounds can improve graphics performance by
8917993c442c26161f684d6c0c6867a746f3148548Craig Stout     * leveraging hardware display layers.
9017993c442c26161f684d6c0c6867a746f3148548Craig Stout     * TODO: support a leanback configuration option.
9117993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
9217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final boolean USE_SEPARATE_WINDOW = false;
9317993c442c26161f684d6c0c6867a746f3148548Craig Stout
9417993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static final String WINDOW_NAME = "BackgroundManager";
957f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu    private static final String FRAGMENT_TAG = BackgroundManager.class.getCanonicalName();
9617993c442c26161f684d6c0c6867a746f3148548Craig Stout
9717993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Context mContext;
9817993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Handler mHandler;
9917993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Window mWindow;
10017993c442c26161f684d6c0c6867a746f3148548Craig Stout    private WindowManager mWindowManager;
10117993c442c26161f684d6c0c6867a746f3148548Craig Stout    private View mBgView;
10217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private BackgroundContinuityService mService;
10317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mThemeDrawableResourceId;
10417993c442c26161f684d6c0c6867a746f3148548Craig Stout
10517993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mHeightPx;
10617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mWidthPx;
10717993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Drawable mBackgroundDrawable;
10817993c442c26161f684d6c0c6867a746f3148548Craig Stout    private int mBackgroundColor;
10917993c442c26161f684d6c0c6867a746f3148548Craig Stout    private boolean mAttached;
11017993c442c26161f684d6c0c6867a746f3148548Craig Stout
1117f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    private static class BitmapDrawable extends Drawable {
1127f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1133d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        static class ConstantState extends Drawable.ConstantState {
1143d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            Bitmap mBitmap;
1153d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            Matrix mMatrix;
1163d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            Paint mPaint;
1173d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1183d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            @Override
1193d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            public Drawable newDrawable() {
1203d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                return new BitmapDrawable(null, mBitmap, mMatrix);
1213d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            }
1223d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1233d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            @Override
1243d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            public int getChangingConfigurations() {
1253d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                return 0;
1263d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            }
1273d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
1283d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1293d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        private ConstantState mState = new ConstantState();
1307f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1317f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        BitmapDrawable(Resources resources, Bitmap bitmap) {
1327f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            this(resources, bitmap, null);
1337f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1347f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1357f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        BitmapDrawable(Resources resources, Bitmap bitmap, Matrix matrix) {
1363d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mState.mBitmap = bitmap;
1373d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mState.mMatrix = matrix != null ? matrix : new Matrix();
1383d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mState.mPaint = new Paint();
1393d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mState.mPaint.setFilterBitmap(true);
1407f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1417f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1427f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        Bitmap getBitmap() {
1433d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            return mState.mBitmap;
1447f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1457f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1467f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1477f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public void draw(Canvas canvas) {
1483d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (mState.mBitmap == null) {
1497f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                return;
1507f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            }
1513d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            canvas.drawBitmap(mState.mBitmap, mState.mMatrix, mState.mPaint);
1527f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1537f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1547f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1557f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public int getOpacity() {
1567f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            return android.graphics.PixelFormat.OPAQUE;
1577f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1587f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1597f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1607f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public void setAlpha(int alpha) {
1613d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (mState.mPaint.getAlpha() != alpha) {
1623d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                mState.mPaint.setAlpha(alpha);
1637f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                invalidateSelf();
1647f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            }
1657f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1667f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1677f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        @Override
1687f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        public void setColorFilter(ColorFilter cf) {
1697f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            // Abstract in Drawable, not implemented
1707f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
1713d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
1723d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        @Override
1733d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        public ConstantState getConstantState() {
1743d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            return mState;
1753d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
1767f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    }
1777f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
1787f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    private static class DrawableWrapper {
17917993c442c26161f684d6c0c6867a746f3148548Craig Stout        protected int mAlpha;
18017993c442c26161f684d6c0c6867a746f3148548Craig Stout        protected Drawable mDrawable;
1817e22f555da71f49a32420965817c760522b95963Craig Stout        protected ValueAnimator mAnimator;
18217993c442c26161f684d6c0c6867a746f3148548Craig Stout        protected boolean mAnimationPending;
18317993c442c26161f684d6c0c6867a746f3148548Craig Stout
1847e22f555da71f49a32420965817c760522b95963Craig Stout        private final Interpolator mInterpolator = new LinearInterpolator();
1857e22f555da71f49a32420965817c760522b95963Craig Stout        private final ValueAnimator.AnimatorUpdateListener mAnimationUpdateListener =
1867e22f555da71f49a32420965817c760522b95963Craig Stout                new ValueAnimator.AnimatorUpdateListener() {
1877e22f555da71f49a32420965817c760522b95963Craig Stout            @Override
1887e22f555da71f49a32420965817c760522b95963Craig Stout            public void onAnimationUpdate(ValueAnimator animation) {
1897e22f555da71f49a32420965817c760522b95963Craig Stout                setAlpha((Integer) animation.getAnimatedValue());
1907e22f555da71f49a32420965817c760522b95963Craig Stout            }
1917e22f555da71f49a32420965817c760522b95963Craig Stout        };
1927e22f555da71f49a32420965817c760522b95963Craig Stout
19317993c442c26161f684d6c0c6867a746f3148548Craig Stout        public DrawableWrapper(Drawable drawable) {
19417993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = drawable;
19517993c442c26161f684d6c0c6867a746f3148548Craig Stout            setAlpha(FULL_ALPHA);
19617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
19717993c442c26161f684d6c0c6867a746f3148548Craig Stout
19817993c442c26161f684d6c0c6867a746f3148548Craig Stout        public Drawable getDrawable() {
19917993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mDrawable;
20017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
20117993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setAlpha(int alpha) {
20217993c442c26161f684d6c0c6867a746f3148548Craig Stout            mAlpha = alpha;
20317993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable.setAlpha(alpha);
20417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
20517993c442c26161f684d6c0c6867a746f3148548Craig Stout        public int getAlpha() {
20617993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mAlpha;
20717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
20817993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setColor(int color) {
20917993c442c26161f684d6c0c6867a746f3148548Craig Stout            ((ColorDrawable) mDrawable).setColor(color);
21017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
21117993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void fadeIn(int durationMs, int delayMs) {
21217993c442c26161f684d6c0c6867a746f3148548Craig Stout            fade(durationMs, delayMs, FULL_ALPHA);
21317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
21417993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void fadeOut(int durationMs) {
21517993c442c26161f684d6c0c6867a746f3148548Craig Stout            fade(durationMs, 0, 0);
21617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
21717993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void fade(int durationMs, int delayMs, int alpha) {
21817993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (mAnimator != null && mAnimator.isStarted()) {
21917993c442c26161f684d6c0c6867a746f3148548Craig Stout                mAnimator.cancel();
22017993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
2217e22f555da71f49a32420965817c760522b95963Craig Stout            mAnimator = ValueAnimator.ofInt(getAlpha(), alpha);
2227e22f555da71f49a32420965817c760522b95963Craig Stout            mAnimator.addUpdateListener(mAnimationUpdateListener);
2237e22f555da71f49a32420965817c760522b95963Craig Stout            mAnimator.setInterpolator(mInterpolator);
22417993c442c26161f684d6c0c6867a746f3148548Craig Stout            mAnimator.setDuration(durationMs);
22517993c442c26161f684d6c0c6867a746f3148548Craig Stout            mAnimator.setStartDelay(delayMs);
22617993c442c26161f684d6c0c6867a746f3148548Craig Stout            mAnimationPending = true;
22717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
22817993c442c26161f684d6c0c6867a746f3148548Craig Stout        public boolean isAnimationPending() {
22917993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mAnimationPending;
23017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
23117993c442c26161f684d6c0c6867a746f3148548Craig Stout        public boolean isAnimationStarted() {
23217993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mAnimator != null && mAnimator.isStarted();
23317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
23417993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void startAnimation() {
2353d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            startAnimation(null);
2363d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
2373d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        public void startAnimation(Animator.AnimatorListener listener) {
2383d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (listener != null) {
2393d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                mAnimator.addListener(listener);
2403d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            }
24117993c442c26161f684d6c0c6867a746f3148548Craig Stout            mAnimator.start();
24217993c442c26161f684d6c0c6867a746f3148548Craig Stout            mAnimationPending = false;
24317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
24417993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
24517993c442c26161f684d6c0c6867a746f3148548Craig Stout
24617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private LayerDrawable mLayerDrawable;
24717993c442c26161f684d6c0c6867a746f3148548Craig Stout    private DrawableWrapper mLayerWrapper;
24817993c442c26161f684d6c0c6867a746f3148548Craig Stout    private DrawableWrapper mImageInWrapper;
24917993c442c26161f684d6c0c6867a746f3148548Craig Stout    private DrawableWrapper mImageOutWrapper;
25017993c442c26161f684d6c0c6867a746f3148548Craig Stout    private DrawableWrapper mColorWrapper;
25117993c442c26161f684d6c0c6867a746f3148548Craig Stout    private DrawableWrapper mDimWrapper;
25217993c442c26161f684d6c0c6867a746f3148548Craig Stout
25317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Drawable mThemeDrawable;
25417993c442c26161f684d6c0c6867a746f3148548Craig Stout    private ChangeBackgroundRunnable mChangeRunnable;
25517993c442c26161f684d6c0c6867a746f3148548Craig Stout
25617993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
25717993c442c26161f684d6c0c6867a746f3148548Craig Stout     * Shared memory continuity service.
25817993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
25917993c442c26161f684d6c0c6867a746f3148548Craig Stout    private static class BackgroundContinuityService {
26017993c442c26161f684d6c0c6867a746f3148548Craig Stout        private static final String TAG = "BackgroundContinuityService";
26117993c442c26161f684d6c0c6867a746f3148548Craig Stout        private static boolean DEBUG = BackgroundManager.DEBUG;
26217993c442c26161f684d6c0c6867a746f3148548Craig Stout
26317993c442c26161f684d6c0c6867a746f3148548Craig Stout        private static BackgroundContinuityService sService = new BackgroundContinuityService();
26417993c442c26161f684d6c0c6867a746f3148548Craig Stout
26517993c442c26161f684d6c0c6867a746f3148548Craig Stout        private int mColor;
26617993c442c26161f684d6c0c6867a746f3148548Craig Stout        private Drawable mDrawable;
26717993c442c26161f684d6c0c6867a746f3148548Craig Stout        private int mCount;
26817993c442c26161f684d6c0c6867a746f3148548Craig Stout
26960c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        /** Single cache of theme drawable */
27060c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        private int mLastThemeDrawableId;
27160c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        private WeakReference<Drawable> mLastThemeDrawable;
27260c3b420827d0520509387f1abe3e3d8168e2279Dake Gu
27317993c442c26161f684d6c0c6867a746f3148548Craig Stout        private BackgroundContinuityService() {
27417993c442c26161f684d6c0c6867a746f3148548Craig Stout            reset();
27517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
27617993c442c26161f684d6c0c6867a746f3148548Craig Stout
27717993c442c26161f684d6c0c6867a746f3148548Craig Stout        private void reset() {
27817993c442c26161f684d6c0c6867a746f3148548Craig Stout            mColor = Color.TRANSPARENT;
27917993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = null;
28017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
28117993c442c26161f684d6c0c6867a746f3148548Craig Stout
28217993c442c26161f684d6c0c6867a746f3148548Craig Stout        public static BackgroundContinuityService getInstance() {
28317993c442c26161f684d6c0c6867a746f3148548Craig Stout            final int count = sService.mCount++;
28417993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "Returning instance with new count " + count);
28517993c442c26161f684d6c0c6867a746f3148548Craig Stout            return sService;
28617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
28717993c442c26161f684d6c0c6867a746f3148548Craig Stout
28817993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void unref() {
28917993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (mCount <= 0) throw new IllegalStateException("Can't unref, count " + mCount);
29017993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (--mCount == 0) {
29117993c442c26161f684d6c0c6867a746f3148548Craig Stout                if (DEBUG) Log.v(TAG, "mCount is zero, resetting");
29217993c442c26161f684d6c0c6867a746f3148548Craig Stout                reset();
29317993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
29417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
29517993c442c26161f684d6c0c6867a746f3148548Craig Stout        public int getColor() {
29617993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mColor;
29717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
29817993c442c26161f684d6c0c6867a746f3148548Craig Stout        public Drawable getDrawable() {
29917993c442c26161f684d6c0c6867a746f3148548Craig Stout            return mDrawable;
30017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
30117993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setColor(int color) {
30217993c442c26161f684d6c0c6867a746f3148548Craig Stout            mColor = color;
30317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
30417993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void setDrawable(Drawable drawable) {
30517993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = drawable;
30617993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
30760c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        public Drawable getThemeDrawable(Context context, int themeDrawableId) {
30860c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            Drawable drawable = null;
30960c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            if (mLastThemeDrawable != null && mLastThemeDrawableId == themeDrawableId) {
31060c3b420827d0520509387f1abe3e3d8168e2279Dake Gu                drawable = mLastThemeDrawable.get();
31160c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            }
31260c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            if (drawable == null) {
31360c3b420827d0520509387f1abe3e3d8168e2279Dake Gu                drawable = ContextCompat.getDrawable(context, themeDrawableId);
31460c3b420827d0520509387f1abe3e3d8168e2279Dake Gu                mLastThemeDrawable = new WeakReference<Drawable>(drawable);
31560c3b420827d0520509387f1abe3e3d8168e2279Dake Gu                mLastThemeDrawableId = themeDrawableId;
31660c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            }
31760c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            return drawable.getConstantState().newDrawable(context.getResources()).mutate();
31860c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        }
31917993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
32017993c442c26161f684d6c0c6867a746f3148548Craig Stout
32117993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Drawable getThemeDrawable() {
32217993c442c26161f684d6c0c6867a746f3148548Craig Stout        Drawable drawable = null;
32317993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mThemeDrawableResourceId != -1) {
32460c3b420827d0520509387f1abe3e3d8168e2279Dake Gu            drawable = mService.getThemeDrawable(mContext, mThemeDrawableResourceId);
32517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
32617993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (drawable == null) {
32717993c442c26161f684d6c0c6867a746f3148548Craig Stout            drawable = createEmptyDrawable();
32817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
32917993c442c26161f684d6c0c6867a746f3148548Craig Stout        return drawable;
33017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
33117993c442c26161f684d6c0c6867a746f3148548Craig Stout
33217993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
333146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Get the BackgroundManager associated with the Activity.
3347f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu     * <p>
335146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * The BackgroundManager will be created on-demand for each individual
336146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Activity. Subsequent calls will return the same BackgroundManager created
337146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * for this Activity.
3387f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu     */
3397f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu    public static BackgroundManager getInstance(Activity activity) {
3407f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
3417f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                .findFragmentByTag(FRAGMENT_TAG);
3427f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        if (fragment != null) {
3437f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            BackgroundManager manager = fragment.getBackgroundManager();
3447f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            if (manager != null) {
3457f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                return manager;
3467f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            }
3477f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            // manager is null: this is a fragment restored by FragmentManager,
3487f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            // fall through to create a BackgroundManager attach to it.
3497f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        }
3507f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        return new BackgroundManager(activity);
3517f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu    }
3527f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu
353497a47f2ab7fdc8490191b02caa9a68f884d9ac0Tim Kilbourn    private BackgroundManager(Activity activity) {
35417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mContext = activity;
35517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mService = BackgroundContinuityService.getInstance();
35617993c442c26161f684d6c0c6867a746f3148548Craig Stout        mHeightPx = mContext.getResources().getDisplayMetrics().heightPixels;
35717993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWidthPx = mContext.getResources().getDisplayMetrics().widthPixels;
35817993c442c26161f684d6c0c6867a746f3148548Craig Stout        mHandler = new Handler();
35917993c442c26161f684d6c0c6867a746f3148548Craig Stout
36017993c442c26161f684d6c0c6867a746f3148548Craig Stout        TypedArray ta = activity.getTheme().obtainStyledAttributes(new int[] {
36117993c442c26161f684d6c0c6867a746f3148548Craig Stout                android.R.attr.windowBackground });
36217993c442c26161f684d6c0c6867a746f3148548Craig Stout        mThemeDrawableResourceId = ta.getResourceId(0, -1);
36317993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mThemeDrawableResourceId < 0) {
36417993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "BackgroundManager no window background resource!");
36517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
36617993c442c26161f684d6c0c6867a746f3148548Craig Stout        ta.recycle();
36717993c442c26161f684d6c0c6867a746f3148548Craig Stout
36817993c442c26161f684d6c0c6867a746f3148548Craig Stout        createFragment(activity);
36917993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
37017993c442c26161f684d6c0c6867a746f3148548Craig Stout
37117993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void createFragment(Activity activity) {
37217993c442c26161f684d6c0c6867a746f3148548Craig Stout        // Use a fragment to ensure the background manager gets detached properly.
373b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu        BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
3747f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                .findFragmentByTag(FRAGMENT_TAG);
375b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu        if (fragment == null) {
376b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu            fragment = new BackgroundFragment();
3777f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            activity.getFragmentManager().beginTransaction().add(fragment, FRAGMENT_TAG).commit();
3787f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu        } else {
3797f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            if (fragment.getBackgroundManager() != null) {
3807f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                throw new IllegalStateException("Created duplicated BackgroundManager for same " +
3817f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu                        "activity, please use getInstance() instead");
3827f0ed3452a3378c851217cd300950ba2e03f2649Dake Gu            }
383b70539172cdeb5672ed7128f69383d1fc1458ccbDake Gu        }
38417993c442c26161f684d6c0c6867a746f3148548Craig Stout        fragment.setBackgroundManager(this);
38517993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
38617993c442c26161f684d6c0c6867a746f3148548Craig Stout
38717993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
388146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Synchronizes state when the owning Activity is resumed.
38917993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
3902e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout    void onActivityResume() {
3912e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        if (mService == null) {
3922e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            return;
3932e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        }
3942e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        if (mLayerDrawable == null) {
3953d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (DEBUG) Log.v(TAG, "onActivityResume " + this +
3963d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                    " released state, syncing with service");
3972e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            syncWithService();
3982e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        } else {
3993d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (DEBUG) Log.v(TAG, "onActivityResume " + this + " updating service color "
4002e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                    + mBackgroundColor + " drawable " + mBackgroundDrawable);
4012e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mService.setColor(mBackgroundColor);
4022e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mService.setDrawable(mBackgroundDrawable);
4032e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        }
40417993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
40517993c442c26161f684d6c0c6867a746f3148548Craig Stout
40617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void syncWithService() {
40717993c442c26161f684d6c0c6867a746f3148548Craig Stout        int color = mService.getColor();
40817993c442c26161f684d6c0c6867a746f3148548Craig Stout        Drawable drawable = mService.getDrawable();
40917993c442c26161f684d6c0c6867a746f3148548Craig Stout
41017993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "syncWithService color " + Integer.toHexString(color)
41117993c442c26161f684d6c0c6867a746f3148548Craig Stout                + " drawable " + drawable);
41217993c442c26161f684d6c0c6867a746f3148548Craig Stout
41317993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBackgroundColor = color;
4143d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        mBackgroundDrawable = drawable == null ? null :
4153d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            drawable.getConstantState().newDrawable().mutate();
4162e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
4172e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        updateImmediate();
41817993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
41917993c442c26161f684d6c0c6867a746f3148548Craig Stout
42017993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void lazyInit() {
42117993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mLayerDrawable != null) {
42217993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
42317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
42417993c442c26161f684d6c0c6867a746f3148548Craig Stout
42560c3b420827d0520509387f1abe3e3d8168e2279Dake Gu        mLayerDrawable = (LayerDrawable) ContextCompat.getDrawable(mContext,
4260eb4595e6a4d6e9ebc9f5b8065e0c787d45a0f70David Saxton                R.drawable.lb_background).mutate();
42717993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBgView.setBackground(mLayerDrawable);
42817993c442c26161f684d6c0c6867a746f3148548Craig Stout
42917993c442c26161f684d6c0c6867a746f3148548Craig Stout        mLayerDrawable.setDrawableByLayerId(R.id.background_imageout, createEmptyDrawable());
43017993c442c26161f684d6c0c6867a746f3148548Craig Stout
43117993c442c26161f684d6c0c6867a746f3148548Craig Stout        mDimWrapper = new DrawableWrapper(
43217993c442c26161f684d6c0c6867a746f3148548Craig Stout                mLayerDrawable.findDrawableByLayerId(R.id.background_dim));
43317993c442c26161f684d6c0c6867a746f3148548Craig Stout
43417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mLayerWrapper = new DrawableWrapper(mLayerDrawable);
43517993c442c26161f684d6c0c6867a746f3148548Craig Stout
43617993c442c26161f684d6c0c6867a746f3148548Craig Stout        mColorWrapper = new DrawableWrapper(
43717993c442c26161f684d6c0c6867a746f3148548Craig Stout                mLayerDrawable.findDrawableByLayerId(R.id.background_color));
43817993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
43917993c442c26161f684d6c0c6867a746f3148548Craig Stout
44017993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
441146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Make the background visible on the given Window.
44217993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
44317993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void attach(Window window) {
44417993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (USE_SEPARATE_WINDOW) {
44517993c442c26161f684d6c0c6867a746f3148548Craig Stout            attachBehindWindow(window);
44617993c442c26161f684d6c0c6867a746f3148548Craig Stout        } else {
44717993c442c26161f684d6c0c6867a746f3148548Craig Stout            attachToView(window.getDecorView());
44817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
44917993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
45017993c442c26161f684d6c0c6867a746f3148548Craig Stout
45117993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void attachBehindWindow(Window window) {
45217993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "attachBehindWindow " + window);
45317993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindow = window;
45417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindowManager = window.getWindowManager();
45517993c442c26161f684d6c0c6867a746f3148548Craig Stout
45617993c442c26161f684d6c0c6867a746f3148548Craig Stout        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
45717993c442c26161f684d6c0c6867a746f3148548Craig Stout                // Media window sits behind the main application window
45817993c442c26161f684d6c0c6867a746f3148548Craig Stout                WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA,
45917993c442c26161f684d6c0c6867a746f3148548Craig Stout                // Avoid default to software format RGBA
46017993c442c26161f684d6c0c6867a746f3148548Craig Stout                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
46117993c442c26161f684d6c0c6867a746f3148548Craig Stout                android.graphics.PixelFormat.TRANSLUCENT);
46217993c442c26161f684d6c0c6867a746f3148548Craig Stout        params.setTitle(WINDOW_NAME);
46317993c442c26161f684d6c0c6867a746f3148548Craig Stout        params.width = ViewGroup.LayoutParams.MATCH_PARENT;
46417993c442c26161f684d6c0c6867a746f3148548Craig Stout        params.height = ViewGroup.LayoutParams.MATCH_PARENT;
46517993c442c26161f684d6c0c6867a746f3148548Craig Stout
46617993c442c26161f684d6c0c6867a746f3148548Craig Stout        View backgroundView = LayoutInflater.from(mContext).inflate(
46717993c442c26161f684d6c0c6867a746f3148548Craig Stout                R.layout.lb_background_window, null);
46817993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindowManager.addView(backgroundView, params);
46917993c442c26161f684d6c0c6867a746f3148548Craig Stout
47017993c442c26161f684d6c0c6867a746f3148548Craig Stout        attachToView(backgroundView);
47117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
47217993c442c26161f684d6c0c6867a746f3148548Craig Stout
47317993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void attachToView(View sceneRoot) {
47417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBgView = sceneRoot;
47517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mAttached = true;
4762e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        syncWithService();
47717993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
47817993c442c26161f684d6c0c6867a746f3148548Craig Stout
47917993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
480146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Release references to Drawables and put the BackgroundManager into the
481146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * detached state. Called when the associated Activity is destroyed.
48217993c442c26161f684d6c0c6867a746f3148548Craig Stout     * @hide
48317993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
48417993c442c26161f684d6c0c6867a746f3148548Craig Stout    void detach() {
4853d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        if (DEBUG) Log.v(TAG, "detach " + this);
48617993c442c26161f684d6c0c6867a746f3148548Craig Stout        release();
48717993c442c26161f684d6c0c6867a746f3148548Craig Stout
48817993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mWindowManager != null && mBgView != null) {
48917993c442c26161f684d6c0c6867a746f3148548Craig Stout            mWindowManager.removeViewImmediate(mBgView);
49017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
49117993c442c26161f684d6c0c6867a746f3148548Craig Stout
49217993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindowManager = null;
49317993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindow = null;
49417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBgView = null;
49517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mAttached = false;
49617993c442c26161f684d6c0c6867a746f3148548Craig Stout
49717993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mService != null) {
49817993c442c26161f684d6c0c6867a746f3148548Craig Stout            mService.unref();
49917993c442c26161f684d6c0c6867a746f3148548Craig Stout            mService = null;
50017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
50117993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
50217993c442c26161f684d6c0c6867a746f3148548Craig Stout
50317993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
504146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Release references to Drawables. Typically called to reduce memory
505146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * overhead when not visible.
5062e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout     * <p>
507146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * When an Activity is resumed, if the BackgroundManager has not been
508146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * released, the continuity service is updated from the BackgroundManager
509146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * state. If the BackgroundManager was released, the BackgroundManager
510146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * inherits the current state from the continuity service.
51117993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
51217993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void release() {
5133d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        if (DEBUG) Log.v(TAG, "release " + this);
5142e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        if (mLayerDrawable != null) {
5152e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mLayerDrawable.setDrawableByLayerId(R.id.background_imagein, createEmptyDrawable());
5162e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mLayerDrawable.setDrawableByLayerId(R.id.background_imageout, createEmptyDrawable());
5172e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mLayerDrawable = null;
5182e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout        }
51917993c442c26161f684d6c0c6867a746f3148548Craig Stout        mLayerWrapper = null;
52017993c442c26161f684d6c0c6867a746f3148548Craig Stout        mImageInWrapper = null;
52117993c442c26161f684d6c0c6867a746f3148548Craig Stout        mImageOutWrapper = null;
52217993c442c26161f684d6c0c6867a746f3148548Craig Stout        mColorWrapper = null;
52317993c442c26161f684d6c0c6867a746f3148548Craig Stout        mDimWrapper = null;
52417993c442c26161f684d6c0c6867a746f3148548Craig Stout        mThemeDrawable = null;
52517993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mChangeRunnable != null) {
52617993c442c26161f684d6c0c6867a746f3148548Craig Stout            mChangeRunnable.cancel();
52717993c442c26161f684d6c0c6867a746f3148548Craig Stout            mChangeRunnable = null;
52817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
52917993c442c26161f684d6c0c6867a746f3148548Craig Stout        releaseBackgroundBitmap();
53017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
53117993c442c26161f684d6c0c6867a746f3148548Craig Stout
53217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void releaseBackgroundBitmap() {
53317993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBackgroundDrawable = null;
53417993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
53517993c442c26161f684d6c0c6867a746f3148548Craig Stout
53617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void updateImmediate() {
53717993c442c26161f684d6c0c6867a746f3148548Craig Stout        lazyInit();
53817993c442c26161f684d6c0c6867a746f3148548Craig Stout
53917993c442c26161f684d6c0c6867a746f3148548Craig Stout        mColorWrapper.setColor(mBackgroundColor);
54017993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mDimWrapper != null) {
54117993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDimWrapper.setAlpha(mBackgroundColor == Color.TRANSPARENT ? 0 : DIM_ALPHA_ON_SOLID);
54217993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
54317993c442c26161f684d6c0c6867a746f3148548Craig Stout        showWallpaper(mBackgroundColor == Color.TRANSPARENT);
54417993c442c26161f684d6c0c6867a746f3148548Craig Stout
54517993c442c26161f684d6c0c6867a746f3148548Craig Stout        mThemeDrawable = getThemeDrawable();
54617993c442c26161f684d6c0c6867a746f3148548Craig Stout        mLayerDrawable.setDrawableByLayerId(R.id.background_theme, mThemeDrawable);
54717993c442c26161f684d6c0c6867a746f3148548Craig Stout
54817993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mBackgroundDrawable == null) {
54917993c442c26161f684d6c0c6867a746f3148548Craig Stout            mLayerDrawable.setDrawableByLayerId(R.id.background_imagein, createEmptyDrawable());
55017993c442c26161f684d6c0c6867a746f3148548Craig Stout        } else {
55117993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "Background drawable is available");
55217993c442c26161f684d6c0c6867a746f3148548Craig Stout            mImageInWrapper = new DrawableWrapper(mBackgroundDrawable);
55317993c442c26161f684d6c0c6867a746f3148548Craig Stout            mLayerDrawable.setDrawableByLayerId(R.id.background_imagein, mBackgroundDrawable);
55417993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (mDimWrapper != null) {
55517993c442c26161f684d6c0c6867a746f3148548Craig Stout                mDimWrapper.setAlpha(FULL_ALPHA);
55617993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
55717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
55817993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
55917993c442c26161f684d6c0c6867a746f3148548Craig Stout
56017993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
561146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Set the background to the given color. The timing for when this becomes
562146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * visible in the app is undefined and may take place after a small delay.
56317993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
56417993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void setColor(int color) {
56517993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "setColor " + Integer.toHexString(color));
56617993c442c26161f684d6c0c6867a746f3148548Craig Stout
56717993c442c26161f684d6c0c6867a746f3148548Craig Stout        mBackgroundColor = color;
56817993c442c26161f684d6c0c6867a746f3148548Craig Stout        mService.setColor(mBackgroundColor);
56917993c442c26161f684d6c0c6867a746f3148548Craig Stout
57017993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mColorWrapper != null) {
57117993c442c26161f684d6c0c6867a746f3148548Craig Stout            mColorWrapper.setColor(mBackgroundColor);
57217993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
57317993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
57417993c442c26161f684d6c0c6867a746f3148548Craig Stout
57517993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
5765a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * Set the given drawable into the background. The provided Drawable will be
5775a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * used unmodified as the background, without any scaling or cropping
5785a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * applied to it. The timing for when this becomes visible in the app is
5795a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * undefined and may take place after a small delay.
58017993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
58117993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void setDrawable(Drawable drawable) {
58217993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "setBackgroundDrawable " + drawable);
58317993c442c26161f684d6c0c6867a746f3148548Craig Stout        setDrawableInternal(drawable);
58417993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
58517993c442c26161f684d6c0c6867a746f3148548Craig Stout
58617993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void setDrawableInternal(Drawable drawable) {
5875a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        if (!mAttached) {
5885a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            throw new IllegalStateException("Must attach before setting background drawable");
5895a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        }
59017993c442c26161f684d6c0c6867a746f3148548Craig Stout
59117993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mChangeRunnable != null) {
592d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout            if (sameDrawable(drawable, mChangeRunnable.mDrawable)) {
593d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout                if (DEBUG) Log.v(TAG, "setting same drawable");
594d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout                return;
595d6019d141130ae4811b78e37286faf93d5944fd9Craig Stout            }
59617993c442c26161f684d6c0c6867a746f3148548Craig Stout            mChangeRunnable.cancel();
59717993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
59817993c442c26161f684d6c0c6867a746f3148548Craig Stout        mChangeRunnable = new ChangeBackgroundRunnable(drawable);
59917993c442c26161f684d6c0c6867a746f3148548Craig Stout
6003d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        if (mImageInWrapper != null && mImageInWrapper.isAnimationStarted()) {
6013d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (DEBUG) Log.v(TAG, "animation in progress");
6023d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        } else {
6033d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mHandler.postDelayed(mChangeRunnable, CHANGE_BG_DELAY_MS);
6043d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
60517993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
60617993c442c26161f684d6c0c6867a746f3148548Craig Stout
60717993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
6085a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * Set the given bitmap into the background. When using setBitmap to set the
6095a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * background, the provided bitmap will be scaled and cropped to correctly
6105a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima     * fit within the dimensions of the view. The timing for when this becomes
611146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * visible in the app is undefined and may take place after a small delay.
61217993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
61317993c442c26161f684d6c0c6867a746f3148548Craig Stout    public void setBitmap(Bitmap bitmap) {
6145a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        if (DEBUG) {
6155a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            Log.v(TAG, "setBitmap " + bitmap);
6165a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        }
6175a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
6185a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        if (bitmap == null) {
6195a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            setDrawableInternal(null);
6205a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            return;
6215a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima        }
62217993c442c26161f684d6c0c6867a746f3148548Craig Stout
62317993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
6245a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            if (DEBUG) {
6255a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima                Log.v(TAG, "invalid bitmap width or height");
6265a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            }
62717993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
62817993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
62917993c442c26161f684d6c0c6867a746f3148548Craig Stout
6307f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        Matrix matrix = null;
63117993c442c26161f684d6c0c6867a746f3148548Craig Stout
6327f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if ((bitmap.getWidth() != mWidthPx || bitmap.getHeight() != mHeightPx)) {
6335a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            int dwidth = bitmap.getWidth();
6345a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            int dheight = bitmap.getHeight();
6355a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            float scale;
6365a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
6377f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            // Scale proportionately to fit width and height.
6385a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            if (dwidth * mHeightPx > mWidthPx * dheight) {
6395a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima                scale = (float) mHeightPx / (float) dheight;
6405a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            } else {
6415a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima                scale = (float) mWidthPx / (float) dwidth;
6425a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            }
6435a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
6445a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima            int subX = Math.min((int) (mWidthPx / scale), dwidth);
6457f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            int dx = Math.max(0, (dwidth - subX) / 2);
6465a8a7c929e07e3a3d17b2e5466785d271eee7657Jose Lima
6477f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            matrix = new Matrix();
6487f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            matrix.setScale(scale, scale);
6497f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            matrix.preTranslate(-dx, 0);
6507f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
6517f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            if (DEBUG) Log.v(TAG, "original image size " + bitmap.getWidth() + "x" + bitmap.getHeight() +
6527f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                    " scale " + scale + " dx " + dx);
65317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
65417993c442c26161f684d6c0c6867a746f3148548Craig Stout
6557f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap, matrix);
65617993c442c26161f684d6c0c6867a746f3148548Craig Stout
65717993c442c26161f684d6c0c6867a746f3148548Craig Stout        setDrawableInternal(bitmapDrawable);
65817993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
65917993c442c26161f684d6c0c6867a746f3148548Craig Stout
66017993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void applyBackgroundChanges() {
66117993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (!mAttached || mLayerWrapper == null) {
66217993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
66317993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
66417993c442c26161f684d6c0c6867a746f3148548Craig Stout
66517993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (DEBUG) Log.v(TAG, "applyBackgroundChanges drawable " + mBackgroundDrawable);
66617993c442c26161f684d6c0c6867a746f3148548Craig Stout
66717993c442c26161f684d6c0c6867a746f3148548Craig Stout        int dimAlpha = 0;
66817993c442c26161f684d6c0c6867a746f3148548Craig Stout
66917993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mImageOutWrapper != null && mImageOutWrapper.isAnimationPending()) {
67017993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "mImageOutWrapper animation starting");
67117993c442c26161f684d6c0c6867a746f3148548Craig Stout            mImageOutWrapper.startAnimation();
67217993c442c26161f684d6c0c6867a746f3148548Craig Stout            mImageOutWrapper = null;
67317993c442c26161f684d6c0c6867a746f3148548Craig Stout            dimAlpha = DIM_ALPHA_ON_SOLID;
67417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
67517993c442c26161f684d6c0c6867a746f3148548Craig Stout
67617993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mImageInWrapper == null && mBackgroundDrawable != null) {
67717993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "creating new imagein drawable");
67817993c442c26161f684d6c0c6867a746f3148548Craig Stout            mImageInWrapper = new DrawableWrapper(mBackgroundDrawable);
67917993c442c26161f684d6c0c6867a746f3148548Craig Stout            mLayerDrawable.setDrawableByLayerId(R.id.background_imagein, mBackgroundDrawable);
6802e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            if (DEBUG) Log.v(TAG, "mImageInWrapper animation starting");
6812e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mImageInWrapper.setAlpha(0);
6823d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mImageInWrapper.fadeIn(FADE_DURATION, 0);
6833d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mImageInWrapper.startAnimation(mImageInListener);
6842e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            dimAlpha = FULL_ALPHA;
68517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
68617993c442c26161f684d6c0c6867a746f3148548Craig Stout
68717993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mDimWrapper != null && dimAlpha != 0) {
68817993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "dimwrapper animation starting to " + dimAlpha);
6893d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mDimWrapper.fade(FADE_DURATION, 0, dimAlpha);
69017993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDimWrapper.startAnimation();
69117993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
69217993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
69317993c442c26161f684d6c0c6867a746f3148548Craig Stout
6943d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout    private final Animator.AnimatorListener mImageInListener = new Animator.AnimatorListener() {
6953d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        @Override
6963d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        public void onAnimationStart(Animator animation) {
6973d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
6983d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        @Override
6993d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        public void onAnimationRepeat(Animator animation) {
7003d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
7013d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        @Override
7023d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        public void onAnimationEnd(Animator animation) {
7033d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            if (mChangeRunnable != null) {
7043d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                if (DEBUG) Log.v(TAG, "animation ended, found change runnable");
7053d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                mChangeRunnable.run();
7063d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            }
7073d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
7083d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        @Override
7093d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        public void onAnimationCancel(Animator animation) {
7103d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout        }
7113d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout    };
7123d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
71317993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
714146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Returns the current background color.
71517993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
71617993c442c26161f684d6c0c6867a746f3148548Craig Stout    public final int getColor() {
71717993c442c26161f684d6c0c6867a746f3148548Craig Stout        return mBackgroundColor;
71817993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
71917993c442c26161f684d6c0c6867a746f3148548Craig Stout
72017993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
721146a2a07c0e9750c2bdd5bd434197c2f46fea662Tim Kilbourn     * Returns the current background {@link Drawable}.
72217993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
72317993c442c26161f684d6c0c6867a746f3148548Craig Stout    public Drawable getDrawable() {
72417993c442c26161f684d6c0c6867a746f3148548Craig Stout        return mBackgroundDrawable;
72517993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
72617993c442c26161f684d6c0c6867a746f3148548Craig Stout
7277f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    private boolean sameDrawable(Drawable first, Drawable second) {
7287f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if (first == null || second == null) {
7297f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            return false;
7307f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
7317f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if (first == second) {
7327f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            return true;
7337f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
7347f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        if (first instanceof BitmapDrawable && second instanceof BitmapDrawable) {
7357f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            if (((BitmapDrawable) first).getBitmap().sameAs(((BitmapDrawable) second).getBitmap())) {
7367f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                return true;
7377f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            }
7387f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        }
7397f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout        return false;
7407f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout    }
7417f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout
74217993c442c26161f684d6c0c6867a746f3148548Craig Stout    /**
74317993c442c26161f684d6c0c6867a746f3148548Craig Stout     * Task which changes the background.
74417993c442c26161f684d6c0c6867a746f3148548Craig Stout     */
74517993c442c26161f684d6c0c6867a746f3148548Craig Stout    class ChangeBackgroundRunnable implements Runnable {
74617993c442c26161f684d6c0c6867a746f3148548Craig Stout        private Drawable mDrawable;
74717993c442c26161f684d6c0c6867a746f3148548Craig Stout        private boolean mCancel;
74817993c442c26161f684d6c0c6867a746f3148548Craig Stout
74917993c442c26161f684d6c0c6867a746f3148548Craig Stout        ChangeBackgroundRunnable(Drawable drawable) {
75017993c442c26161f684d6c0c6867a746f3148548Craig Stout            mDrawable = drawable;
75117993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
75217993c442c26161f684d6c0c6867a746f3148548Craig Stout
75317993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void cancel() {
75417993c442c26161f684d6c0c6867a746f3148548Craig Stout            mCancel = true;
75517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
75617993c442c26161f684d6c0c6867a746f3148548Craig Stout
75717993c442c26161f684d6c0c6867a746f3148548Craig Stout        @Override
75817993c442c26161f684d6c0c6867a746f3148548Craig Stout        public void run() {
75917993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (!mCancel) {
76017993c442c26161f684d6c0c6867a746f3148548Craig Stout                runTask();
76117993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
76217993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
76317993c442c26161f684d6c0c6867a746f3148548Craig Stout
76417993c442c26161f684d6c0c6867a746f3148548Craig Stout        private void runTask() {
76517993c442c26161f684d6c0c6867a746f3148548Craig Stout            lazyInit();
76617993c442c26161f684d6c0c6867a746f3148548Craig Stout
7677f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout            if (sameDrawable(mDrawable, mBackgroundDrawable)) {
7687f85292289f235c50740c3180fdbcb4bb2bf9703Craig Stout                if (DEBUG) Log.v(TAG, "same bitmap detected");
7692e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                return;
77017993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
77117993c442c26161f684d6c0c6867a746f3148548Craig Stout
7722e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            releaseBackgroundBitmap();
7732e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
7742e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            if (mImageInWrapper != null) {
7752e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                mImageOutWrapper = new DrawableWrapper(mImageInWrapper.getDrawable());
7762e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                mImageOutWrapper.setAlpha(mImageInWrapper.getAlpha());
7773d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout                mImageOutWrapper.fadeOut(FADE_DURATION);
7782e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
7792e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                // Order is important! Setting a drawable "removes" the
7802e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                // previous one from the view
7812e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                mLayerDrawable.setDrawableByLayerId(R.id.background_imagein, createEmptyDrawable());
7822e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                mLayerDrawable.setDrawableByLayerId(R.id.background_imageout,
7832e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                        mImageOutWrapper.getDrawable());
7842e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                mImageInWrapper.setAlpha(0);
7852e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout                mImageInWrapper = null;
78617993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
7872e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
7882e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mBackgroundDrawable = mDrawable;
7892e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            mService.setDrawable(mBackgroundDrawable);
7902e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout
7912e2e91a93f6d03108a73e7b4a05d289589957a0eCraig Stout            applyBackgroundChanges();
7923d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout
7933d9d8cbaa9086f3ca2f486233fa3051e614a99edCraig Stout            mChangeRunnable = null;
79417993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
79517993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
79617993c442c26161f684d6c0c6867a746f3148548Craig Stout
79717993c442c26161f684d6c0c6867a746f3148548Craig Stout    private Drawable createEmptyDrawable() {
79817993c442c26161f684d6c0c6867a746f3148548Craig Stout        Bitmap bitmap = null;
79917993c442c26161f684d6c0c6867a746f3148548Craig Stout        return new BitmapDrawable(mContext.getResources(), bitmap);
80017993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
80117993c442c26161f684d6c0c6867a746f3148548Craig Stout
80217993c442c26161f684d6c0c6867a746f3148548Craig Stout    private void showWallpaper(boolean show) {
80317993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (mWindow == null) {
80417993c442c26161f684d6c0c6867a746f3148548Craig Stout            return;
80517993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
80617993c442c26161f684d6c0c6867a746f3148548Craig Stout
80717993c442c26161f684d6c0c6867a746f3148548Craig Stout        WindowManager.LayoutParams layoutParams = mWindow.getAttributes();
80817993c442c26161f684d6c0c6867a746f3148548Craig Stout        if (show) {
80917993c442c26161f684d6c0c6867a746f3148548Craig Stout            if ((layoutParams.flags & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
81017993c442c26161f684d6c0c6867a746f3148548Craig Stout                return;
81117993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
81217993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "showing wallpaper");
81317993c442c26161f684d6c0c6867a746f3148548Craig Stout            layoutParams.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
81417993c442c26161f684d6c0c6867a746f3148548Craig Stout        } else {
81517993c442c26161f684d6c0c6867a746f3148548Craig Stout            if ((layoutParams.flags & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) == 0) {
81617993c442c26161f684d6c0c6867a746f3148548Craig Stout                return;
81717993c442c26161f684d6c0c6867a746f3148548Craig Stout            }
81817993c442c26161f684d6c0c6867a746f3148548Craig Stout            if (DEBUG) Log.v(TAG, "hiding wallpaper");
81917993c442c26161f684d6c0c6867a746f3148548Craig Stout            layoutParams.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
82017993c442c26161f684d6c0c6867a746f3148548Craig Stout        }
82117993c442c26161f684d6c0c6867a746f3148548Craig Stout
82217993c442c26161f684d6c0c6867a746f3148548Craig Stout        mWindow.setAttributes(layoutParams);
82317993c442c26161f684d6c0c6867a746f3148548Craig Stout    }
82417993c442c26161f684d6c0c6867a746f3148548Craig Stout}
825