blob: 702afa3a38b190e66c6e29e7b3e65e7fa6f1a3b4 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.statusbar.phone;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Trace;
import android.util.MathUtils;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
import com.android.internal.graphics.ColorUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.stack.ViewState;
import java.io.PrintWriter;
import java.util.function.Consumer;
/**
* Controls both the scrim behind the notifications and in front of the notifications (when a
* security method gets shown).
*/
public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
OnHeadsUpChangedListener, OnColorsChangedListener {
public static final long ANIMATION_DURATION = 220;
public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR
= new PathInterpolator(0f, 0, 0.7f, 1f);
public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED
= new PathInterpolator(0.3f, 0f, 0.8f, 1f);
// Default alpha value for most scrims, if unsure use this constant
public static final float GRADIENT_SCRIM_ALPHA = 0.45f;
// A scrim varies its opacity based on a busyness factor, for example
// how many notifications are currently visible.
public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.70f;
protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = GRADIENT_SCRIM_ALPHA;
protected static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
private static final float SCRIM_IN_FRONT_ALPHA = GRADIENT_SCRIM_ALPHA_BUSY;
private static final float SCRIM_IN_FRONT_ALPHA_LOCKED = GRADIENT_SCRIM_ALPHA_BUSY;
private static final int TAG_KEY_ANIM = R.id.scrim;
private static final int TAG_KEY_ANIM_TARGET = R.id.scrim_target;
private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
private static final float NOT_INITIALIZED = -1;
private final LightBarController mLightBarController;
protected final ScrimView mScrimBehind;
protected final ScrimView mScrimInFront;
private final UnlockMethodCache mUnlockMethodCache;
private final View mHeadsUpScrim;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final SysuiColorExtractor mColorExtractor;
private GradientColors mLockColors;
private GradientColors mSystemColors;
private boolean mNeedsDrawableColorUpdate;
protected float mScrimBehindAlpha;
protected float mScrimBehindAlphaResValue;
protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
protected float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
protected boolean mKeyguardShowing;
private float mFraction;
private boolean mDarkenWhileDragging;
protected boolean mBouncerShowing;
protected boolean mBouncerIsKeyguard = false;
private boolean mWakeAndUnlocking;
protected boolean mAnimateChange;
private boolean mUpdatePending;
private boolean mTracking;
private boolean mAnimateKeyguardFadingOut;
protected long mDurationOverride = -1;
private long mAnimationDelay;
private Runnable mOnAnimationFinished;
private boolean mDeferFinishedListener;
private final Interpolator mInterpolator = new DecelerateInterpolator();
private boolean mDozing;
private float mDozeInFrontAlpha;
private float mDozeBehindAlpha;
private float mCurrentInFrontAlpha = NOT_INITIALIZED;
private float mCurrentBehindAlpha = NOT_INITIALIZED;
private float mCurrentHeadsUpAlpha = NOT_INITIALIZED;
private int mPinnedHeadsUpCount;
private float mTopHeadsUpDragAmount;
private View mDraggedHeadsUpView;
private boolean mForceHideScrims;
private boolean mSkipFirstFrame;
private boolean mDontAnimateBouncerChanges;
private boolean mKeyguardFadingOutInProgress;
private boolean mAnimatingDozeUnlock;
private ValueAnimator mKeyguardFadeoutAnimation;
/** Wake up from AOD transition is starting; need fully opaque front scrim */
private boolean mWakingUpFromAodStarting;
/** Wake up from AOD transition is in progress; need black tint */
private boolean mWakingUpFromAodInProgress;
/** Wake up from AOD transition is animating; need to reset when animation finishes */
private boolean mWakingUpFromAodAnimationRunning;
private boolean mScrimsVisble;
private final Consumer<Boolean> mScrimVisibleListener;
public ScrimController(LightBarController lightBarController, ScrimView scrimBehind,
ScrimView scrimInFront, View headsUpScrim,
Consumer<Boolean> scrimVisibleListener) {
mScrimBehind = scrimBehind;
mScrimInFront = scrimInFront;
mHeadsUpScrim = headsUpScrim;
mScrimVisibleListener = scrimVisibleListener;
final Context context = scrimBehind.getContext();
mUnlockMethodCache = UnlockMethodCache.getInstance(context);
mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
mLightBarController = lightBarController;
mScrimBehindAlphaResValue = context.getResources().getFloat(R.dimen.scrim_behind_alpha);
// Scrim alpha is initially set to the value on the resource but might be changed
// to make sure that text on top of it is legible.
mScrimBehindAlpha = mScrimBehindAlphaResValue;
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
mColorExtractor.addOnColorsChangedListener(this);
mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
mNeedsDrawableColorUpdate = true;
updateHeadsUpScrim(false);
updateScrims();
}
public void setKeyguardShowing(boolean showing) {
mKeyguardShowing = showing;
// Showing/hiding the keyguard means that scrim colors have to be switched
mNeedsDrawableColorUpdate = true;
scheduleUpdate();
}
protected void setScrimBehindValues(float scrimBehindAlphaKeyguard,
float scrimBehindAlphaUnlocking) {
mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
mScrimBehindAlphaUnlocking = scrimBehindAlphaUnlocking;
scheduleUpdate();
}
public void onTrackingStarted() {
mTracking = true;
mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
}
public void onExpandingFinished() {
mTracking = false;
}
public void setPanelExpansion(float fraction) {
if (mFraction != fraction) {
mFraction = fraction;
scheduleUpdate();
if (mPinnedHeadsUpCount != 0) {
updateHeadsUpScrim(false);
}
if (mKeyguardFadeoutAnimation != null && mTracking) {
mKeyguardFadeoutAnimation.cancel();
}
}
}
public void setBouncerShowing(boolean showing) {
mBouncerShowing = showing;
mAnimateChange = !mTracking && !mDontAnimateBouncerChanges && !mKeyguardFadingOutInProgress;
scheduleUpdate();
}
/** Prepares the wakeUpFromAod animation (while turning on screen); Forces black scrims. */
public void prepareWakeUpFromAod() {
if (mWakingUpFromAodInProgress) {
return;
}
mWakingUpFromAodInProgress = true;
mWakingUpFromAodStarting = true;
mAnimateChange = false;
scheduleUpdate();
onPreDraw();
}
/** Starts the wakeUpFromAod animation (once screen is on); animate to transparent scrims. */
public void wakeUpFromAod() {
if (mWakeAndUnlocking || mAnimateKeyguardFadingOut) {
// Wake and unlocking has a separate transition that must not be interfered with.
mWakingUpFromAodStarting = false;
mWakingUpFromAodInProgress = false;
return;
}
if (mWakingUpFromAodStarting) {
mWakingUpFromAodInProgress = true;
mWakingUpFromAodStarting = false;
mAnimateChange = true;
scheduleUpdate();
}
}
public void setWakeAndUnlocking() {
mWakeAndUnlocking = true;
mAnimatingDozeUnlock = true;
mWakingUpFromAodStarting = false;
mWakingUpFromAodInProgress = false;
scheduleUpdate();
}
public void animateKeyguardFadingOut(long delay, long duration, Runnable onAnimationFinished,
boolean skipFirstFrame) {
mWakeAndUnlocking = false;
mAnimateKeyguardFadingOut = true;
mDurationOverride = duration;
mAnimationDelay = delay;
mAnimateChange = true;
mSkipFirstFrame = skipFirstFrame;
mOnAnimationFinished = onAnimationFinished;
if (!mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
scheduleUpdate();
// No need to wait for the next frame to be drawn for this case - onPreDraw will execute
// the changes we just scheduled.
onPreDraw();
} else {
// In case the user isn't unlocked, make sure to delay a bit because the system is hosed
// with too many things in this case, in order to not skip the initial frames.
mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16);
}
}
public void abortKeyguardFadingOut() {
if (mAnimateKeyguardFadingOut) {
endAnimateKeyguardFadingOut(true /* force */);
}
}
public void animateKeyguardUnoccluding(long duration) {
mAnimateChange = false;
setScrimBehindAlpha(0f);
mAnimateChange = true;
scheduleUpdate();
mDurationOverride = duration;
}
public void animateGoingToFullShade(long delay, long duration) {
mDurationOverride = duration;
mAnimationDelay = delay;
mAnimateChange = true;
scheduleUpdate();
}
public void setDozing(boolean dozing) {
if (mDozing != dozing) {
mDozing = dozing;
scheduleUpdate();
}
}
public void setDozeInFrontAlpha(float alpha) {
mDozeInFrontAlpha = alpha;
updateScrimColor(mScrimInFront);
}
public void setDozeBehindAlpha(float alpha) {
mDozeBehindAlpha = alpha;
updateScrimColor(mScrimBehind);
}
public float getDozeBehindAlpha() {
return mDozeBehindAlpha;
}
public float getDozeInFrontAlpha() {
return mDozeInFrontAlpha;
}
public void setNotificationCount(int notificationCount) {
final float maxNotificationDensity = 3;
float notificationDensity = Math.min(notificationCount / maxNotificationDensity, 1f);
float newAlpha = MathUtils.map(0, 1,
GRADIENT_SCRIM_ALPHA, GRADIENT_SCRIM_ALPHA_BUSY,
notificationDensity);
if (mScrimBehindAlphaKeyguard != newAlpha) {
mScrimBehindAlphaKeyguard = newAlpha;
mAnimateChange = true;
scheduleUpdate();
}
}
private float getScrimInFrontAlpha() {
return mKeyguardUpdateMonitor.needsSlowUnlockTransition()
? SCRIM_IN_FRONT_ALPHA_LOCKED
: SCRIM_IN_FRONT_ALPHA;
}
/**
* Sets the given drawable as the background of the scrim that shows up behind the
* notifications.
*/
public void setScrimBehindDrawable(Drawable drawable) {
mScrimBehind.setDrawable(drawable);
}
protected void scheduleUpdate() {
if (mUpdatePending) return;
// Make sure that a frame gets scheduled.
mScrimBehind.invalidate();
mScrimBehind.getViewTreeObserver().addOnPreDrawListener(this);
mUpdatePending = true;
}
protected void updateScrims() {
// Make sure we have the right gradients and their opacities will satisfy GAR.
if (mNeedsDrawableColorUpdate) {
mNeedsDrawableColorUpdate = false;
final GradientColors currentScrimColors;
if (mKeyguardShowing) {
// Always animate color changes if we're seeing the keyguard
mScrimInFront.setColors(mLockColors, true /* animated */);
mScrimBehind.setColors(mLockColors, true /* animated */);
currentScrimColors = mLockColors;
} else {
// Only animate scrim color if the scrim view is actually visible
boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0;
boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0;
mScrimInFront.setColors(mSystemColors, animateScrimInFront);
mScrimBehind.setColors(mSystemColors, animateScrimBehind);
currentScrimColors = mSystemColors;
}
// Calculate minimum scrim opacity for white or black text.
int textColor = currentScrimColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
int mainColor = currentScrimColors.getMainColor();
float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
4.5f /* minimumContrast */) / 255f;
mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity);
mLightBarController.setScrimColor(mScrimInFront.getColors());
}
if (mAnimateKeyguardFadingOut || mForceHideScrims) {
setScrimInFrontAlpha(0f);
setScrimBehindAlpha(0f);
} else if (mWakeAndUnlocking) {
// During wake and unlock, we first hide everything behind a black scrim, which then
// gets faded out from animateKeyguardFadingOut. This must never be animated.
mAnimateChange = false;
if (mDozing) {
setScrimInFrontAlpha(0f);
setScrimBehindAlpha(1f);
} else {
setScrimInFrontAlpha(1f);
setScrimBehindAlpha(0f);
}
} else if (!mKeyguardShowing && !mBouncerShowing && !mWakingUpFromAodStarting) {
updateScrimNormal();
setScrimInFrontAlpha(0);
} else {
updateScrimKeyguard();
}
mAnimateChange = false;
dispatchScrimsVisible();
}
private void dispatchScrimsVisible() {
boolean scrimsVisible = mScrimBehind.getViewAlpha() > 0 || mScrimInFront.getViewAlpha() > 0;
if (mScrimsVisble != scrimsVisible) {
mScrimsVisble = scrimsVisible;
mScrimVisibleListener.accept(scrimsVisible);
}
}
private void updateScrimKeyguard() {
if (mTracking && mDarkenWhileDragging) {
float behindFraction = Math.max(0, Math.min(mFraction, 1));
float fraction = 1 - behindFraction;
fraction = (float) Math.pow(fraction, 0.8f);
behindFraction = (float) Math.pow(behindFraction, 0.8f);
setScrimInFrontAlpha(fraction * getScrimInFrontAlpha());
setScrimBehindAlpha(behindFraction * mScrimBehindAlphaKeyguard);
} else if (mBouncerShowing && !mBouncerIsKeyguard) {
setScrimInFrontAlpha(getScrimInFrontAlpha());
updateScrimNormal();
} else if (mBouncerShowing) {
setScrimInFrontAlpha(0f);
setScrimBehindAlpha(mScrimBehindAlpha);
} else {
float fraction = Math.max(0, Math.min(mFraction, 1));
if (mWakingUpFromAodStarting) {
setScrimInFrontAlpha(1f);
} else {
setScrimInFrontAlpha(0f);
}
setScrimBehindAlpha(fraction
* (mScrimBehindAlphaKeyguard - mScrimBehindAlphaUnlocking)
+ mScrimBehindAlphaUnlocking);
}
}
private void updateScrimNormal() {
float frac = mFraction;
// let's start this 20% of the way down the screen
frac = frac * 1.2f - 0.2f;
if (frac <= 0) {
setScrimBehindAlpha(0);
} else {
// woo, special effects
final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
setScrimBehindAlpha(k * mScrimBehindAlpha);
}
}
private void setScrimBehindAlpha(float alpha) {
setScrimAlpha(mScrimBehind, alpha);
}
private void setScrimInFrontAlpha(float alpha) {
setScrimAlpha(mScrimInFront, alpha);
if (alpha == 0f) {
mScrimInFront.setClickable(false);
} else {
// Eat touch events (unless dozing).
mScrimInFront.setClickable(!mDozing);
}
}
private void setScrimAlpha(View scrim, float alpha) {
updateScrim(mAnimateChange, scrim, alpha, getCurrentScrimAlpha(scrim));
}
protected float getDozeAlpha(View scrim) {
return scrim == mScrimBehind ? mDozeBehindAlpha : mDozeInFrontAlpha;
}
protected float getCurrentScrimAlpha(View scrim) {
return scrim == mScrimBehind ? mCurrentBehindAlpha
: scrim == mScrimInFront ? mCurrentInFrontAlpha
: mCurrentHeadsUpAlpha;
}
private void setCurrentScrimAlpha(View scrim, float alpha) {
if (scrim == mScrimBehind) {
mCurrentBehindAlpha = alpha;
mLightBarController.setScrimAlpha(mCurrentBehindAlpha);
} else if (scrim == mScrimInFront) {
mCurrentInFrontAlpha = alpha;
} else {
alpha = Math.max(0.0f, Math.min(1.0f, alpha));
mCurrentHeadsUpAlpha = alpha;
}
}
private void updateScrimColor(View scrim) {
float alpha1 = getCurrentScrimAlpha(scrim);
if (scrim instanceof ScrimView) {
ScrimView scrimView = (ScrimView) scrim;
float dozeAlpha = getDozeAlpha(scrim);
float alpha = 1 - (1 - alpha1) * (1 - dozeAlpha);
alpha = Math.max(0, Math.min(1.0f, alpha));
scrimView.setViewAlpha(alpha);
Trace.traceCounter(Trace.TRACE_TAG_APP,
scrim == mScrimInFront ? "front_scrim_alpha" : "back_scrim_alpha",
(int) (alpha * 255));
int dozeTint = Color.TRANSPARENT;
boolean dozing = mAnimatingDozeUnlock || mDozing;
boolean frontScrimDozing = mWakingUpFromAodInProgress;
if (dozing || frontScrimDozing && scrim == mScrimInFront) {
dozeTint = Color.BLACK;
}
Trace.traceCounter(Trace.TRACE_TAG_APP,
scrim == mScrimInFront ? "front_scrim_tint" : "back_scrim_tint",
dozeTint == Color.BLACK ? 1 : 0);
scrimView.setTint(dozeTint);
} else {
scrim.setAlpha(alpha1);
}
dispatchScrimsVisible();
}
private void startScrimAnimation(final View scrim, float target) {
float current = getCurrentScrimAlpha(scrim);
ValueAnimator anim = ValueAnimator.ofFloat(current, target);
anim.addUpdateListener(animation -> {
float alpha = (float) animation.getAnimatedValue();
setCurrentScrimAlpha(scrim, alpha);
updateScrimColor(scrim);
dispatchScrimsVisible();
});
anim.setInterpolator(getInterpolator());
anim.setStartDelay(mAnimationDelay);
anim.setDuration(mDurationOverride != -1 ? mDurationOverride : ANIMATION_DURATION);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (!mDeferFinishedListener && mOnAnimationFinished != null) {
mOnAnimationFinished.run();
mOnAnimationFinished = null;
}
if (mKeyguardFadingOutInProgress) {
mKeyguardFadeoutAnimation = null;
mKeyguardFadingOutInProgress = false;
mAnimatingDozeUnlock = false;
}
if (mWakingUpFromAodAnimationRunning && !mDeferFinishedListener) {
mWakingUpFromAodAnimationRunning = false;
mWakingUpFromAodInProgress = false;
}
scrim.setTag(TAG_KEY_ANIM, null);
scrim.setTag(TAG_KEY_ANIM_TARGET, null);
dispatchScrimsVisible();
}
});
anim.start();
if (mAnimateKeyguardFadingOut) {
mKeyguardFadingOutInProgress = true;
mKeyguardFadeoutAnimation = anim;
}
if (mWakingUpFromAodInProgress) {
mWakingUpFromAodAnimationRunning = true;
}
if (mSkipFirstFrame) {
anim.setCurrentPlayTime(16);
}
scrim.setTag(TAG_KEY_ANIM, anim);
scrim.setTag(TAG_KEY_ANIM_TARGET, target);
}
protected Interpolator getInterpolator() {
if (mAnimateKeyguardFadingOut && mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
return KEYGUARD_FADE_OUT_INTERPOLATOR_LOCKED;
} else if (mAnimateKeyguardFadingOut) {
return KEYGUARD_FADE_OUT_INTERPOLATOR;
} else {
return mInterpolator;
}
}
@Override
public boolean onPreDraw() {
mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
mUpdatePending = false;
if (mDontAnimateBouncerChanges) {
mDontAnimateBouncerChanges = false;
}
updateScrims();
mDurationOverride = -1;
mAnimationDelay = 0;
mSkipFirstFrame = false;
// Make sure that we always call the listener even if we didn't start an animation.
endAnimateKeyguardFadingOut(false /* force */);
return true;
}
private void endAnimateKeyguardFadingOut(boolean force) {
mAnimateKeyguardFadingOut = false;
if (force || (!isAnimating(mScrimInFront) && !isAnimating(mScrimBehind))) {
if (mOnAnimationFinished != null) {
mOnAnimationFinished.run();
mOnAnimationFinished = null;
}
mKeyguardFadingOutInProgress = false;
if (!mWakeAndUnlocking || force)
mAnimatingDozeUnlock = false;
}
}
private boolean isAnimating(View scrim) {
return scrim.getTag(TAG_KEY_ANIM) != null;
}
public void setDrawBehindAsSrc(boolean asSrc) {
mScrimBehind.setDrawAsSrc(asSrc);
}
@Override
public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
}
@Override
public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
mPinnedHeadsUpCount++;
updateHeadsUpScrim(true);
}
@Override
public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
mPinnedHeadsUpCount--;
if (headsUp == mDraggedHeadsUpView) {
mDraggedHeadsUpView = null;
mTopHeadsUpDragAmount = 0.0f;
}
updateHeadsUpScrim(true);
}
@Override
public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
}
private void updateHeadsUpScrim(boolean animate) {
updateScrim(animate, mHeadsUpScrim, calculateHeadsUpAlpha(), mCurrentHeadsUpAlpha);
}
private void updateScrim(boolean animate, View scrim, float alpha, float currentAlpha) {
if (mKeyguardFadingOutInProgress && mKeyguardFadeoutAnimation.getCurrentPlayTime() != 0) {
return;
}
ValueAnimator previousAnimator = ViewState.getChildTag(scrim,
TAG_KEY_ANIM);
float animEndValue = -1;
if (previousAnimator != null) {
if (animate || alpha == currentAlpha) {
// We are not done yet! Defer calling the finished listener.
if (animate) {
mDeferFinishedListener = true;
}
previousAnimator.cancel();
mDeferFinishedListener = false;
} else {
animEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA);
}
}
if (alpha != currentAlpha && alpha != animEndValue) {
if (animate) {
startScrimAnimation(scrim, alpha);
scrim.setTag(TAG_START_ALPHA, currentAlpha);
scrim.setTag(TAG_END_ALPHA, alpha);
} else {
if (previousAnimator != null) {
float previousStartValue = ViewState.getChildTag(scrim, TAG_START_ALPHA);
float previousEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA);
// we need to increase all animation keyframes of the previous animator by the
// relative change to the end value
PropertyValuesHolder[] values = previousAnimator.getValues();
float relativeDiff = alpha - previousEndValue;
float newStartValue = previousStartValue + relativeDiff;
newStartValue = Math.max(0, Math.min(1.0f, newStartValue));
values[0].setFloatValues(newStartValue, alpha);
scrim.setTag(TAG_START_ALPHA, newStartValue);
scrim.setTag(TAG_END_ALPHA, alpha);
previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
} else {
// update the alpha directly
setCurrentScrimAlpha(scrim, alpha);
updateScrimColor(scrim);
}
}
}
}
/**
* Set the amount the current top heads up view is dragged. The range is from 0 to 1 and 0 means
* the heads up is in its resting space and 1 means it's fully dragged out.
*
* @param draggedHeadsUpView the dragged view
* @param topHeadsUpDragAmount how far is it dragged
*/
public void setTopHeadsUpDragAmount(View draggedHeadsUpView, float topHeadsUpDragAmount) {
mTopHeadsUpDragAmount = topHeadsUpDragAmount;
mDraggedHeadsUpView = draggedHeadsUpView;
updateHeadsUpScrim(false);
}
private float calculateHeadsUpAlpha() {
float alpha;
if (mPinnedHeadsUpCount >= 2) {
alpha = 1.0f;
} else if (mPinnedHeadsUpCount == 0) {
alpha = 0.0f;
} else {
alpha = 1.0f - mTopHeadsUpDragAmount;
}
float expandFactor = (1.0f - mFraction);
expandFactor = Math.max(expandFactor, 0.0f);
return alpha * expandFactor;
}
public void forceHideScrims(boolean hide, boolean animated) {
mForceHideScrims = hide;
mAnimateChange = animated;
scheduleUpdate();
}
public void dontAnimateBouncerChangesUntilNextFrame() {
mDontAnimateBouncerChanges = true;
}
public void setExcludedBackgroundArea(Rect area) {
mScrimBehind.setExcludedArea(area);
}
public int getBackgroundColor() {
int color = mLockColors.getMainColor();
return Color.argb((int) (mScrimBehind.getAlpha() * Color.alpha(color)),
Color.red(color), Color.green(color), Color.blue(color));
}
public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
mScrimBehind.setChangeRunnable(changeRunnable);
}
public void onDensityOrFontScaleChanged() {
ViewGroup.LayoutParams layoutParams = mHeadsUpScrim.getLayoutParams();
layoutParams.height = mHeadsUpScrim.getResources().getDimensionPixelSize(
R.dimen.heads_up_scrim_height);
mHeadsUpScrim.setLayoutParams(layoutParams);
}
public void setCurrentUser(int currentUser) {
// Don't care in the base class.
}
@Override
public void onColorsChanged(ColorExtractor colorExtractor, int which) {
if ((which & WallpaperManager.FLAG_LOCK) != 0) {
mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
mNeedsDrawableColorUpdate = true;
scheduleUpdate();
}
if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
ColorExtractor.TYPE_DARK, mKeyguardShowing);
mNeedsDrawableColorUpdate = true;
scheduleUpdate();
}
}
public void dump(PrintWriter pw) {
pw.println(" ScrimController:");
pw.print(" frontScrim:"); pw.print(" viewAlpha="); pw.print(mScrimInFront.getViewAlpha());
pw.print(" alpha="); pw.print(mCurrentInFrontAlpha);
pw.print(" dozeAlpha="); pw.print(mDozeInFrontAlpha);
pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimInFront.getTint()));
pw.print(" backScrim:"); pw.print(" viewAlpha="); pw.print(mScrimBehind.getViewAlpha());
pw.print(" alpha="); pw.print(mCurrentBehindAlpha);
pw.print(" dozeAlpha="); pw.print(mDozeBehindAlpha);
pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimBehind.getTint()));
pw.print(" mBouncerShowing="); pw.println(mBouncerShowing);
pw.print(" mTracking="); pw.println(mTracking);
pw.print(" mForceHideScrims="); pw.println(mForceHideScrims);
}
}