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..ae7006ba8fab3ef4832ff09c66ca17d38c95ba49 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,72 @@ 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) { |
+ // mAnimatedLogoDrawable doesn't actually know its bounds, so super.invalidateDrawable() |
+ // doesn't 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()); |
} |
} |
} |