Fields Summary |
---|
private static final long | DOUBLETAP_TIMEOUT_MS |
private static final int | BACKGROUND_ANIMATION_LENGTH_MS |
private static final int | ACTIVATE_ANIMATION_LENGTH |
private static final int | DARK_ANIMATION_LENGTH |
private static final float | HORIZONTAL_COLLAPSED_REST_PARTIALThe amount of width, which is kept in the end when performing a disappear animation (also
the amount from which the horizontal appearing begins) |
private static final float | HORIZONTAL_ANIMATION_ENDAt which point from [0,1] does the horizontal collapse animation end (or start when
expanding)? 1.0 meaning that it ends immediately and 0.0 that it is continuously animated. |
private static final float | ALPHA_ANIMATION_ENDAt which point from [0,1] does the alpha animation end (or start when
expanding)? 1.0 meaning that it ends immediately and 0.0 that it is continuously animated. |
private static final float | HORIZONTAL_ANIMATION_STARTAt which point from [0,1] does the horizontal collapse animation start (or start when
expanding)? 1.0 meaning that it starts immediately and 0.0 that it is animated at all. |
private static final float | VERTICAL_ANIMATION_STARTAt which point from [0,1] does the vertical collapse animation start (or end when
expanding) 1.0 meaning that it starts immediately and 0.0 that it is animated at all. |
private static final float | DARK_EXIT_SCALE_STARTScale for the background to animate from when exiting dark mode. |
private static final android.view.animation.Interpolator | ACTIVATE_INVERSE_INTERPOLATOR |
private static final android.view.animation.Interpolator | ACTIVATE_INVERSE_ALPHA_INTERPOLATOR |
private final int | mTintedRippleColor |
private final int | mLowPriorityRippleColor |
private final int | mNormalRippleColor |
private boolean | mDimmed |
private boolean | mDark |
private int | mBgTint |
private final int | mRoundedRectCornerRadius |
private boolean | mActivatedFlag to indicate that the notification has been touched once and the second touch will
click it. |
private float | mDownX |
private float | mDownY |
private final float | mTouchSlop |
private OnActivatedListener | mOnActivatedListener |
private final android.view.animation.Interpolator | mLinearOutSlowInInterpolator |
private final android.view.animation.Interpolator | mFastOutSlowInInterpolator |
private final android.view.animation.Interpolator | mSlowOutFastInInterpolator |
private final android.view.animation.Interpolator | mSlowOutLinearInInterpolator |
private final android.view.animation.Interpolator | mLinearInterpolator |
private android.view.animation.Interpolator | mCurrentAppearInterpolator |
private android.view.animation.Interpolator | mCurrentAlphaInterpolator |
private NotificationBackgroundView | mBackgroundNormal |
private NotificationBackgroundView | mBackgroundDimmed |
private android.animation.ObjectAnimator | mBackgroundAnimator |
private android.graphics.RectF | mAppearAnimationRect |
private android.graphics.PorterDuffColorFilter | mAppearAnimationFilter |
private float | mAnimationTranslationY |
private boolean | mDrawingAppearAnimation |
private android.graphics.Paint | mAppearPaint |
private android.animation.ValueAnimator | mAppearAnimator |
private float | mAppearAnimationFraction |
private float | mAppearAnimationTranslation |
private boolean | mShowingLegacyBackground |
private final int | mLegacyColor |
private final int | mNormalColor |
private final int | mLowPriorityColor |
private boolean | mIsBelowSpeedBump |
private final Runnable | mTapTimeoutRunnable |
Methods Summary |
---|
private void | cancelFadeAnimations()
if (mBackgroundAnimator != null) {
mBackgroundAnimator.cancel();
}
mBackgroundDimmed.animate().cancel();
mBackgroundNormal.animate().cancel();
|
protected void | dispatchDraw(android.graphics.Canvas canvas)
if (!mDrawingAppearAnimation) {
super.dispatchDraw(canvas);
} else {
drawAppearRect(canvas);
}
|
private void | drawAppearRect(android.graphics.Canvas canvas)
canvas.save();
canvas.translate(0, mAppearAnimationTranslation);
canvas.drawRoundRect(mAppearAnimationRect, mRoundedRectCornerRadius,
mRoundedRectCornerRadius, mAppearPaint);
canvas.restore();
|
public void | drawableHotspotChanged(float x, float y)
if (!mDimmed){
mBackgroundNormal.drawableHotspotChanged(x, y);
}
|
protected void | drawableStateChanged()
super.drawableStateChanged();
if (mDimmed) {
mBackgroundDimmed.setState(getDrawableState());
} else {
mBackgroundNormal.setState(getDrawableState());
}
|
private void | enableAppearDrawing(boolean enable)When we draw the appear animation, we render the view in a bitmap and render this bitmap
as a shader of a rect. This call creates the Bitmap and switches the drawing mode,
such that the normal drawing of the views does not happen anymore.
if (enable != mDrawingAppearAnimation) {
if (enable) {
if (getWidth() == 0 || getActualHeight() == 0) {
// TODO: This should not happen, but it can during expansion. Needs
// investigation
return;
}
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getActualHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
draw(canvas);
mAppearPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP));
} else {
mAppearPaint.setShader(null);
}
mDrawingAppearAnimation = enable;
invalidate();
}
|
private void | fadeDimmedBackground()Fades the background when the dimmed state changes.
mBackgroundDimmed.animate().cancel();
mBackgroundNormal.animate().cancel();
if (mDimmed) {
mBackgroundDimmed.setVisibility(View.VISIBLE);
} else {
mBackgroundNormal.setVisibility(View.VISIBLE);
}
float startAlpha = mDimmed ? 1f : 0;
float endAlpha = mDimmed ? 0 : 1f;
int duration = BACKGROUND_ANIMATION_LENGTH_MS;
// Check whether there is already a background animation running.
if (mBackgroundAnimator != null) {
startAlpha = (Float) mBackgroundAnimator.getAnimatedValue();
duration = (int) mBackgroundAnimator.getCurrentPlayTime();
mBackgroundAnimator.removeAllListeners();
mBackgroundAnimator.cancel();
if (duration <= 0) {
updateBackground();
return;
}
}
mBackgroundNormal.setAlpha(startAlpha);
mBackgroundAnimator =
ObjectAnimator.ofFloat(mBackgroundNormal, View.ALPHA, startAlpha, endAlpha);
mBackgroundAnimator.setInterpolator(mFastOutSlowInInterpolator);
mBackgroundAnimator.setDuration(duration);
mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mDimmed) {
mBackgroundNormal.setVisibility(View.INVISIBLE);
} else {
mBackgroundDimmed.setVisibility(View.INVISIBLE);
}
mBackgroundAnimator = null;
}
});
mBackgroundAnimator.start();
|
private void | fadeInFromDark(long delay)Fades in the background when exiting dark mode.
final View background = mDimmed ? mBackgroundDimmed : mBackgroundNormal;
background.setAlpha(0f);
background.setPivotX(mBackgroundDimmed.getWidth() / 2f);
background.setPivotY(getActualHeight() / 2f);
background.setScaleX(DARK_EXIT_SCALE_START);
background.setScaleY(DARK_EXIT_SCALE_START);
background.animate()
.alpha(1f)
.scaleX(1f)
.scaleY(1f)
.setDuration(DARK_ANIMATION_LENGTH)
.setStartDelay(delay)
.setInterpolator(mLinearOutSlowInInterpolator)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
// Jump state if we are cancelled
background.setScaleX(1f);
background.setScaleY(1f);
background.setAlpha(1f);
}
})
.start();
|
private int | getBackgroundColor()
if (mBgTint != 0) {
return mBgTint;
} else if (mShowingLegacyBackground) {
return mLegacyColor;
} else if (mIsBelowSpeedBump) {
return mLowPriorityColor;
} else {
return mNormalColor;
}
|
private int | getRippleColor()
if (mBgTint != 0) {
return mTintedRippleColor;
} else if (mShowingLegacyBackground) {
return mTintedRippleColor;
} else if (mIsBelowSpeedBump) {
return mLowPriorityRippleColor;
} else {
return mNormalRippleColor;
}
|
private boolean | handleTouchEventDimmed(android.view.MotionEvent event)
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
mDownX = event.getX();
mDownY = event.getY();
if (mDownY > getActualHeight()) {
return false;
}
break;
case MotionEvent.ACTION_MOVE:
if (!isWithinTouchSlop(event)) {
makeInactive(true /* animate */);
return false;
}
break;
case MotionEvent.ACTION_UP:
if (isWithinTouchSlop(event)) {
if (!mActivated) {
makeActive();
postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
} else {
boolean performed = performClick();
if (performed) {
removeCallbacks(mTapTimeoutRunnable);
}
}
} else {
makeInactive(true /* animate */);
}
break;
case MotionEvent.ACTION_CANCEL:
makeInactive(true /* animate */);
break;
default:
break;
}
return true;
|
private boolean | isWithinTouchSlop(android.view.MotionEvent event)
return Math.abs(event.getX() - mDownX) < mTouchSlop
&& Math.abs(event.getY() - mDownY) < mTouchSlop;
|
private void | makeActive()
startActivateAnimation(false /* reverse */);
mActivated = true;
if (mOnActivatedListener != null) {
mOnActivatedListener.onActivated(this);
}
|
public void | makeInactive(boolean animate)Cancels the hotspot and makes the notification inactive.
if (mActivated) {
if (mDimmed) {
if (animate) {
startActivateAnimation(true /* reverse */);
} else {
mBackgroundNormal.setVisibility(View.INVISIBLE);
}
}
mActivated = false;
}
if (mOnActivatedListener != null) {
mOnActivatedListener.onActivationReset(this);
}
removeCallbacks(mTapTimeoutRunnable);
|
protected void | onFinishInflate()
super.onFinishInflate();
mBackgroundNormal = (NotificationBackgroundView) findViewById(R.id.backgroundNormal);
mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg);
mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
updateBackground();
updateBackgroundTint();
|
protected void | onLayout(boolean changed, int left, int top, int right, int bottom)
super.onLayout(changed, left, top, right, bottom);
setPivotX(getWidth() / 2);
|
public boolean | onTouchEvent(android.view.MotionEvent event)
if (mDimmed) {
return handleTouchEventDimmed(event);
} else {
return super.onTouchEvent(event);
}
|
public void | performAddAnimation(long delay, long duration)
enableAppearDrawing(true);
if (mDrawingAppearAnimation) {
startAppearAnimation(true /* isAppearing */, -1.0f, delay, duration, null);
}
|
public void | performRemoveAnimation(long duration, float translationDirection, java.lang.Runnable onFinishedRunnable)
enableAppearDrawing(true);
if (mDrawingAppearAnimation) {
startAppearAnimation(false /* isAppearing */, translationDirection,
0, duration, onFinishedRunnable);
} else if (onFinishedRunnable != null) {
onFinishedRunnable.run();
}
|
public void | reset()
setTintColor(0);
setShowingLegacyBackground(false);
setBelowSpeedBump(false);
|
public void | setActualHeight(int actualHeight, boolean notifyListeners)
super.setActualHeight(actualHeight, notifyListeners);
setPivotY(actualHeight / 2);
mBackgroundNormal.setActualHeight(actualHeight);
mBackgroundDimmed.setActualHeight(actualHeight);
|
public void | setBelowSpeedBump(boolean below)
super.setBelowSpeedBump(below);
if (below != mIsBelowSpeedBump) {
mIsBelowSpeedBump = below;
updateBackgroundTint();
}
|
public void | setClipTopAmount(int clipTopAmount)
super.setClipTopAmount(clipTopAmount);
mBackgroundNormal.setClipTopAmount(clipTopAmount);
mBackgroundDimmed.setClipTopAmount(clipTopAmount);
|
public void | setDark(boolean dark, boolean fade, long delay)
super.setDark(dark, fade, delay);
if (mDark == dark) {
return;
}
mDark = dark;
if (!dark && fade) {
if (mActivated) {
mBackgroundDimmed.setVisibility(View.VISIBLE);
mBackgroundNormal.setVisibility(View.VISIBLE);
} else if (mDimmed) {
mBackgroundDimmed.setVisibility(View.VISIBLE);
mBackgroundNormal.setVisibility(View.INVISIBLE);
} else {
mBackgroundDimmed.setVisibility(View.INVISIBLE);
mBackgroundNormal.setVisibility(View.VISIBLE);
}
fadeInFromDark(delay);
} else {
updateBackground();
}
|
public void | setDimmed(boolean dimmed, boolean fade)
if (mDimmed != dimmed) {
mDimmed = dimmed;
if (fade) {
fadeDimmedBackground();
} else {
updateBackground();
}
}
|
public void | setOnActivatedListener(com.android.systemui.statusbar.ActivatableNotificationView$OnActivatedListener onActivatedListener)
mOnActivatedListener = onActivatedListener;
|
public void | setShowingLegacyBackground(boolean showing)
mShowingLegacyBackground = showing;
updateBackgroundTint();
|
public void | setTintColor(int color)Sets the tint color of the background
mBgTint = color;
updateBackgroundTint();
|
private void | startActivateAnimation(boolean reverse)
if (!isAttachedToWindow()) {
return;
}
int widthHalf = mBackgroundNormal.getWidth()/2;
int heightHalf = mBackgroundNormal.getActualHeight()/2;
float radius = (float) Math.sqrt(widthHalf*widthHalf + heightHalf*heightHalf);
Animator animator;
if (reverse) {
animator = ViewAnimationUtils.createCircularReveal(mBackgroundNormal,
widthHalf, heightHalf, radius, 0);
} else {
animator = ViewAnimationUtils.createCircularReveal(mBackgroundNormal,
widthHalf, heightHalf, 0, radius);
}
mBackgroundNormal.setVisibility(View.VISIBLE);
Interpolator interpolator;
Interpolator alphaInterpolator;
if (!reverse) {
interpolator = mLinearOutSlowInInterpolator;
alphaInterpolator = mLinearOutSlowInInterpolator;
} else {
interpolator = ACTIVATE_INVERSE_INTERPOLATOR;
alphaInterpolator = ACTIVATE_INVERSE_ALPHA_INTERPOLATOR;
}
animator.setInterpolator(interpolator);
animator.setDuration(ACTIVATE_ANIMATION_LENGTH);
if (reverse) {
mBackgroundNormal.setAlpha(1f);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mDimmed) {
mBackgroundNormal.setVisibility(View.INVISIBLE);
}
}
});
animator.start();
} else {
mBackgroundNormal.setAlpha(0.4f);
animator.start();
}
mBackgroundNormal.animate()
.alpha(reverse ? 0f : 1f)
.setInterpolator(alphaInterpolator)
.setDuration(ACTIVATE_ANIMATION_LENGTH);
|
private void | startAppearAnimation(boolean isAppearing, float translationDirection, long delay, long duration, java.lang.Runnable onFinishedRunnable)
if (mAppearAnimator != null) {
mAppearAnimator.cancel();
}
mAnimationTranslationY = translationDirection * getActualHeight();
if (mAppearAnimationFraction == -1.0f) {
// not initialized yet, we start anew
if (isAppearing) {
mAppearAnimationFraction = 0.0f;
mAppearAnimationTranslation = mAnimationTranslationY;
} else {
mAppearAnimationFraction = 1.0f;
mAppearAnimationTranslation = 0;
}
}
float targetValue;
if (isAppearing) {
mCurrentAppearInterpolator = mSlowOutFastInInterpolator;
mCurrentAlphaInterpolator = mLinearOutSlowInInterpolator;
targetValue = 1.0f;
} else {
mCurrentAppearInterpolator = mFastOutSlowInInterpolator;
mCurrentAlphaInterpolator = mSlowOutLinearInInterpolator;
targetValue = 0.0f;
}
mAppearAnimator = ValueAnimator.ofFloat(mAppearAnimationFraction,
targetValue);
mAppearAnimator.setInterpolator(mLinearInterpolator);
mAppearAnimator.setDuration(
(long) (duration * Math.abs(mAppearAnimationFraction - targetValue)));
mAppearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mAppearAnimationFraction = (float) animation.getAnimatedValue();
updateAppearAnimationAlpha();
updateAppearRect();
invalidate();
}
});
if (delay > 0) {
// we need to apply the initial state already to avoid drawn frames in the wrong state
updateAppearAnimationAlpha();
updateAppearRect();
mAppearAnimator.setStartDelay(delay);
}
mAppearAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mWasCancelled;
@Override
public void onAnimationEnd(Animator animation) {
if (onFinishedRunnable != null) {
onFinishedRunnable.run();
}
if (!mWasCancelled) {
mAppearAnimationFraction = -1;
setOutlineRect(null);
enableAppearDrawing(false);
}
}
@Override
public void onAnimationStart(Animator animation) {
mWasCancelled = false;
}
@Override
public void onAnimationCancel(Animator animation) {
mWasCancelled = true;
}
});
mAppearAnimator.start();
|
private void | updateAppearAnimationAlpha()
int backgroundColor = getBackgroundColor();
if (backgroundColor != -1) {
float contentAlphaProgress = mAppearAnimationFraction;
contentAlphaProgress = contentAlphaProgress / (1.0f - ALPHA_ANIMATION_END);
contentAlphaProgress = Math.min(1.0f, contentAlphaProgress);
contentAlphaProgress = mCurrentAlphaInterpolator.getInterpolation(contentAlphaProgress);
int sourceColor = Color.argb((int) (255 * (1.0f - contentAlphaProgress)),
Color.red(backgroundColor), Color.green(backgroundColor),
Color.blue(backgroundColor));
mAppearAnimationFilter.setColor(sourceColor);
mAppearPaint.setColorFilter(mAppearAnimationFilter);
}
|
private void | updateAppearRect()
float inverseFraction = (1.0f - mAppearAnimationFraction);
float translationFraction = mCurrentAppearInterpolator.getInterpolation(inverseFraction);
float translateYTotalAmount = translationFraction * mAnimationTranslationY;
mAppearAnimationTranslation = translateYTotalAmount;
// handle width animation
float widthFraction = (inverseFraction - (1.0f - HORIZONTAL_ANIMATION_START))
/ (HORIZONTAL_ANIMATION_START - HORIZONTAL_ANIMATION_END);
widthFraction = Math.min(1.0f, Math.max(0.0f, widthFraction));
widthFraction = mCurrentAppearInterpolator.getInterpolation(widthFraction);
float left = (getWidth() * (0.5f - HORIZONTAL_COLLAPSED_REST_PARTIAL / 2.0f) *
widthFraction);
float right = getWidth() - left;
// handle top animation
float heightFraction = (inverseFraction - (1.0f - VERTICAL_ANIMATION_START)) /
VERTICAL_ANIMATION_START;
heightFraction = Math.max(0.0f, heightFraction);
heightFraction = mCurrentAppearInterpolator.getInterpolation(heightFraction);
float top;
float bottom;
final int actualHeight = getActualHeight();
if (mAnimationTranslationY > 0.0f) {
bottom = actualHeight - heightFraction * mAnimationTranslationY * 0.1f
- translateYTotalAmount;
top = bottom * heightFraction;
} else {
top = heightFraction * (actualHeight + mAnimationTranslationY) * 0.1f -
translateYTotalAmount;
bottom = actualHeight * (1 - heightFraction) + top * heightFraction;
}
mAppearAnimationRect.set(left, top, right, bottom);
setOutlineRect(left, top + mAppearAnimationTranslation, right,
bottom + mAppearAnimationTranslation);
|
private void | updateBackground()
cancelFadeAnimations();
if (mDark) {
mBackgroundDimmed.setVisibility(View.INVISIBLE);
mBackgroundNormal.setVisibility(View.INVISIBLE);
} else if (mDimmed) {
mBackgroundDimmed.setVisibility(View.VISIBLE);
mBackgroundNormal.setVisibility(View.INVISIBLE);
} else {
mBackgroundDimmed.setVisibility(View.INVISIBLE);
mBackgroundNormal.setVisibility(View.VISIBLE);
mBackgroundNormal.setAlpha(1f);
removeCallbacks(mTapTimeoutRunnable);
}
|
private void | updateBackgroundTint()
int color = getBackgroundColor();
int rippleColor = getRippleColor();
if (color == mNormalColor) {
// We don't need to tint a normal notification
color = 0;
}
mBackgroundDimmed.setTint(color);
mBackgroundNormal.setTint(color);
mBackgroundDimmed.setRippleColor(rippleColor);
mBackgroundNormal.setRippleColor(rippleColor);
|