Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java |
| index 94a7f3df7f0e7521d7ddb30dcf304a1a0a6a6cda..9262ddfb478df76d9b0163d79aa911cd099249a0 100644 |
| --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/LogoView.java |
| @@ -8,10 +8,12 @@ import android.animation.Animator; |
| import android.animation.ObjectAnimator; |
| import android.content.Context; |
| import android.graphics.Bitmap; |
| +import android.graphics.Bitmap.Config; |
| import android.graphics.BitmapFactory; |
| import android.graphics.Canvas; |
| import android.graphics.Matrix; |
| import android.graphics.Paint; |
| +import android.graphics.drawable.Drawable; |
| import android.text.TextUtils; |
| import android.util.AttributeSet; |
| import android.util.Property; |
| @@ -24,9 +26,13 @@ import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; |
| import java.lang.ref.WeakReference; |
| +import jp.tomorrowkey.android.gifplayer.BaseGifDrawable; |
| +import jp.tomorrowkey.android.gifplayer.BaseGifImage; |
| + |
| /** |
| * This view shows the default search provider's logo and fades in a new logo if one becomes |
| - * available. |
| + * available. It also maintains a {@link BaseGifDrawable} that will be played when the user clicks |
| + * this view and we have an animated GIF logo ready. |
| */ |
| public class LogoView extends View implements OnClickListener { |
| @@ -36,14 +42,18 @@ public class LogoView extends View implements OnClickListener { |
| // The default logo is shared across all NTPs. |
| private static WeakReference<Bitmap> sDefaultLogo; |
| - private Paint mPaint; |
| + // mLogo and mNewLogo are remembered for cross fading animation. |
| private Bitmap mLogo; |
| private Bitmap mNewLogo; |
| + private BaseGifDrawable mAnimatedLogoDrawable; |
| + |
| + private ObjectAnimator mFadeAnimation; |
| + private Paint mPaint; |
| private Matrix mLogoMatrix; |
| private Matrix mNewLogoMatrix; |
| + private Matrix mAnimatedLogoMatrix; |
| private boolean mLogoIsDefault; |
| private boolean mNewLogoIsDefault; |
| - private ObjectAnimator mAnimation; |
| /** |
| * A measure from 0 to 1 of how much the new logo has faded in. 0 shows the old logo, 1 shows |
| @@ -99,16 +109,37 @@ public class LogoView extends View implements OnClickListener { |
| } |
| /** |
| - * Jumps to the end of the current logo animation, if any. |
| + * Jumps to the end of the logo cross-fading animation, if any. |
| */ |
| - public void endAnimation() { |
| - if (mAnimation != null) { |
| - mAnimation.end(); |
| - mAnimation = null; |
| + public void endFadeAnimation() { |
| + if (mFadeAnimation != null) { |
| + mFadeAnimation.end(); |
| + mFadeAnimation = null; |
| } |
| } |
| /** |
| + * @return True after the animated GIF logo starts playing. False otherwise. |
| + */ |
| + public boolean isAnimatedLogoShowing() { |
| + return mAnimatedLogoDrawable != null && mAnimatedLogoDrawable.isRunning() |
| + && mAnimatedLogoDrawable.isValid(); |
| + } |
| + |
| + /** |
| + * Starts playing the given animated GIF logo. |
| + */ |
| + public void playAnimatedLogo(BaseGifImage gifImage) { |
| + mAnimatedLogoDrawable = new BaseGifDrawable(gifImage, Config.ARGB_8888); |
| + mAnimatedLogoMatrix = new Matrix(); |
| + setMatrix(mAnimatedLogoDrawable.getIntrinsicWidth(), |
| + mAnimatedLogoDrawable.getIntrinsicHeight(), mAnimatedLogoMatrix, false); |
| + // Set callback here to ensure #invalidateDrawable() is called. |
| + mAnimatedLogoDrawable.setCallback(this); |
| + mAnimatedLogoDrawable.start(); |
| + } |
| + |
| + /** |
| * Fades in a new logo over the current logo. |
| * |
| * @param logo The new logo to fade in. May be null to reset to the default logo. |
| @@ -124,16 +155,16 @@ public class LogoView extends View implements OnClickListener { |
| } |
| private void updateLogo(Bitmap logo, final String contentDescription, boolean isDefaultLogo) { |
| - if (mAnimation != null) mAnimation.end(); |
| + if (mFadeAnimation != null) mFadeAnimation.end(); |
| mNewLogo = logo; |
| mNewLogoMatrix = new Matrix(); |
| mNewLogoIsDefault = isDefaultLogo; |
| - setMatrix(mNewLogo, mNewLogoMatrix, mNewLogoIsDefault); |
| + setMatrix(mNewLogo.getWidth(), mNewLogo.getHeight(), mNewLogoMatrix, mNewLogoIsDefault); |
| - mAnimation = ObjectAnimator.ofFloat(this, mTransitionProperty, 0f, 1f); |
| - mAnimation.setDuration(LOGO_TRANSITION_TIME_MS); |
| - mAnimation.addListener(new Animator.AnimatorListener() { |
| + mFadeAnimation = ObjectAnimator.ofFloat(this, mTransitionProperty, 0f, 1f); |
| + mFadeAnimation.setDuration(LOGO_TRANSITION_TIME_MS); |
| + mFadeAnimation.addListener(new Animator.AnimatorListener() { |
| @Override |
| public void onAnimationStart(Animator animation) { |
| } |
| @@ -150,7 +181,7 @@ public class LogoView extends View implements OnClickListener { |
| mNewLogo = null; |
| mNewLogoMatrix = null; |
| mTransitionAmount = 0f; |
| - mAnimation = null; |
| + mFadeAnimation = null; |
| setContentDescription(contentDescription); |
| setClickable(!mNewLogoIsDefault); |
| } |
| @@ -161,7 +192,7 @@ public class LogoView extends View implements OnClickListener { |
| invalidate(); |
| } |
| }); |
| - mAnimation.start(); |
| + mFadeAnimation.start(); |
| } |
| /** |
| @@ -178,11 +209,10 @@ public class LogoView extends View implements OnClickListener { |
| * @param preventUpscaling Whether the image should not be scaled up. If true, the image might |
| * not fill the entire view but will still be centered. |
| */ |
| - private void setMatrix(Bitmap image, Matrix matrix, boolean preventUpscaling) { |
| + private void setMatrix(int imageWidth, int imageHeight, Matrix matrix, |
| + boolean preventUpscaling) { |
| int width = getWidth(); |
| int height = getHeight(); |
| - int imageWidth = image.getWidth(); |
| - int imageHeight = image.getHeight(); |
| float scale = Math.min((float) width / imageWidth, (float) height / imageHeight); |
| if (preventUpscaling) scale = Math.min(1.0f, scale); |
| @@ -207,36 +237,71 @@ public class LogoView extends View implements OnClickListener { |
| } |
| @Override |
| + protected boolean verifyDrawable(Drawable who) { |
| + return (who == mAnimatedLogoDrawable) || super.verifyDrawable(who); |
| + } |
| + |
| + @Override |
| + public void invalidateDrawable(Drawable drawable) { |
| + // mGifDrawable doesn't actually know its bounds, so super.invalidateDrawable() doesn't |
|
newt (away)
2015/09/23 22:18:02
"mAnimatedLogoDrawable"
|
| + // invalidate the right area. Instead invalidate the entire view; the drawable takes up most |
| + // of the view anyway so this is just as efficient. @see ImageView#invalidateDrawable(). |
| + if (drawable == mAnimatedLogoDrawable) invalidate(); |
| + else super.invalidateDrawable(drawable); |
| + } |
| + |
| + @Override |
| protected void onDraw(Canvas canvas) { |
| - if (mLogo != null && mTransitionAmount < 0.5f) { |
| - mPaint.setAlpha((int) (255 * 2 * (0.5f - mTransitionAmount))); |
| - canvas.save(); |
| - canvas.concat(mLogoMatrix); |
| - canvas.drawBitmap(mLogo, 0, 0, mPaint); |
| - canvas.restore(); |
| - } |
| + if (isAnimatedLogoShowing()) { |
| + if (mFadeAnimation != null) mFadeAnimation.cancel(); |
| + // Free the old bitmaps to allow them to be GC'd. |
| + mLogo = null; |
| + mNewLogo = null; |
| - if (mNewLogo != null && mTransitionAmount > 0.5f) { |
| - mPaint.setAlpha((int) (255 * 2 * (mTransitionAmount - 0.5f))); |
| canvas.save(); |
| - canvas.concat(mNewLogoMatrix); |
| - canvas.drawBitmap(mNewLogo, 0, 0, mPaint); |
| + canvas.concat(mAnimatedLogoMatrix); |
| + mAnimatedLogoDrawable.draw(canvas); |
| canvas.restore(); |
| + } else { |
| + if (mLogo != null && mTransitionAmount < 0.5f) { |
| + mPaint.setAlpha((int) (255 * 2 * (0.5f - mTransitionAmount))); |
| + canvas.save(); |
| + canvas.concat(mLogoMatrix); |
| + canvas.drawBitmap(mLogo, 0, 0, mPaint); |
| + canvas.restore(); |
| + } |
| + |
| + if (mNewLogo != null && mTransitionAmount > 0.5f) { |
| + mPaint.setAlpha((int) (255 * 2 * (mTransitionAmount - 0.5f))); |
| + canvas.save(); |
| + canvas.concat(mNewLogoMatrix); |
| + canvas.drawBitmap(mNewLogo, 0, 0, mPaint); |
| + canvas.restore(); |
| + } |
| } |
| } |
| @Override |
| protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
| if (w != oldw || h != oldh) { |
| - if (mLogo != null) setMatrix(mLogo, mLogoMatrix, mLogoIsDefault); |
| - if (mNewLogo != null) setMatrix(mNewLogo, mNewLogoMatrix, mNewLogoIsDefault); |
| + if (mAnimatedLogoDrawable != null) { |
| + setMatrix(mAnimatedLogoDrawable.getIntrinsicWidth(), |
| + mAnimatedLogoDrawable.getIntrinsicHeight(), mAnimatedLogoMatrix, false); |
| + } |
| + if (mLogo != null) { |
| + setMatrix(mLogo.getWidth(), mLogo.getHeight(), mLogoMatrix, mLogoIsDefault); |
| + } |
| + if (mNewLogo != null) { |
| + setMatrix(mNewLogo.getWidth(), mNewLogo.getHeight(), mNewLogoMatrix, |
| + mNewLogoIsDefault); |
| + } |
| } |
| } |
| @Override |
| public void onClick(View view) { |
| if (view == this && mManager != null && !isTransitioning()) { |
| - mManager.openLogoLink(); |
| + mManager.onLogoClicked(isAnimatedLogoShowing()); |
| } |
| } |
| } |