/* * Copyright (C) 2014 AChep@xda <artemchep@gmail.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package com.achep.acdisplay.ui; import android.animation.Animator; import android.animation.AnimatorInflater; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.TransitionDrawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.View; import android.widget.ImageView; import com.achep.acdisplay.Config; import com.achep.acdisplay.R; import com.achep.acdisplay.ui.fragments.AcDisplayFragment; import com.achep.base.ui.animations.AnimatorListenerAdapter; import com.achep.base.utils.Operator; /** * Created by Artem Chepurnoy on 22.11.2014. */ public abstract class DynamicBackground { protected static final String TAG = "DynamicBackground"; @NonNull public static DynamicBackground newInstance( @NonNull AcDisplayFragment fragment, @Nullable ImageView imageView) { return new DynamicBackgroundCompat(fragment, imageView); } protected final AcDisplayFragment mFragment; protected final ImageView mImageView; protected DynamicBackground(@NonNull AcDisplayFragment fragment, @Nullable ImageView imageView) { mFragment = fragment; mImageView = imageView; if (mImageView == null) { return; } initBackground(); } protected abstract void initBackground(); protected abstract void dispatchSetBackgroundInternal(@Nullable Bitmap bitmap); /** * Clears background. * * @see #dispatchSetBackground(android.graphics.Bitmap, int) */ public void dispatchClearBackground() { dispatchSetBackground(null); } /** * Smoothly sets the background. This feature is known as "Dynamic background". * * @param bitmap the bitmap to display, or {@code null} to hide previous background. * @param mask one of the following: * {@link Config#DYNAMIC_BG_ARTWORK_MASK}, * {@link Config#DYNAMIC_BG_NOTIFICATION_MASK} or * {@code 0} to bypass mask checking. * @see #dispatchClearBackground() */ public void dispatchSetBackground(@Nullable Bitmap bitmap, int mask) { Config config = mFragment.getConfig(); if (mask == 0 || Operator.bitAnd(config.getDynamicBackgroundMode(), mask)) { dispatchSetBackground(bitmap); } } /** * Smoothly sets the background. */ private void dispatchSetBackground(@Nullable Bitmap bitmap) { if (mImageView == null) return; if (mFragment.isPowerSaveMode()) { // No animations and no background. mImageView.setImageBitmap(null); } else { dispatchSetBackgroundInternal(bitmap); } } /** * {@inheritDoc} */ private static class DynamicBackgroundCompat extends DynamicBackground { private Animator mEnterAnimation; private Animator mExitAnimation; /** * {@inheritDoc} */ DynamicBackgroundCompat( @NonNull AcDisplayFragment fragment, @Nullable ImageView imageView) { super(fragment, imageView); } @Override protected void initBackground() { assert mImageView != null; Context context = mFragment.getActivity(); // Setup enter animation. mEnterAnimation = AnimatorInflater.loadAnimator(context, R.animator.background_enter); mEnterAnimation.setTarget(mImageView); mEnterAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mImageView.setVisibility(View.VISIBLE); } }); // Setup exit animation. mExitAnimation = AnimatorInflater.loadAnimator(context, R.animator.background_exit); mExitAnimation.setTarget(mImageView); mExitAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (isCanceled()) return; mImageView.setVisibility(View.GONE); mImageView.setImageDrawable(null); } }); } @Override protected void dispatchSetBackgroundInternal(@Nullable Bitmap bitmap) { assert mImageView != null; if (bitmap == null) { // Clear background. if (mImageView.getDrawable() != null) { mEnterAnimation.cancel(); mExitAnimation.start(); } } else { // Set background. BitmapDrawable drawable = new BitmapDrawable(getResources(), bitmap); Drawable drawablePrev = mImageView.getDrawable(); if (mExitAnimation.isRunning()) { mExitAnimation.cancel(); mEnterAnimation.setupEndValues(); } if (drawablePrev == null || !mFragment.isAnimatableAuto()) { mImageView.setImageDrawable(drawable); mEnterAnimation.start(); } else { if (drawablePrev instanceof TransitionDrawable) { TransitionDrawable d = (TransitionDrawable) drawablePrev; drawablePrev = d.getDrawable(1); d.resetTransition(); } Drawable[] arrayDrawable = new Drawable[]{drawablePrev, drawable}; TransitionDrawable transitionDrawable = new TransitionDrawable(arrayDrawable); transitionDrawable.setCrossFadeEnabled(true); mImageView.setImageDrawable(transitionDrawable); // Start cross-fade animation. int duration = getResources().getInteger(android.R.integer.config_shortAnimTime); transitionDrawable.startTransition(duration); } } } @NonNull private Resources getResources() { return mFragment.getResources(); } } }