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