Color extraction on scrims
Consuming color extraction library to add wallpaper
colors to sysui scrims. Handles both lock screen and
notification shade.
Bug: 36856508
Bug: 37013527
Test: runtest --path frameworks/base/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
Change-Id: I8d964c978a766243d90bbfb3432d19eebf1a2056
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 5ee0c64..c7bae66 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -37,7 +37,8 @@
android-support-v7-mediarouter \
android-support-v7-palette \
android-support-v14-preference \
- android-support-v17-leanback
+ android-support-v17-leanback \
+ colorextraction
LOCAL_STATIC_JAVA_LIBRARIES := \
SystemUI-tags \
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index f9d0cd6..d9ac4d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -19,39 +19,52 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.NonNull;
import android.content.Context;
-import android.content.res.TypedArray;
+import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.Paint;
+import android.graphics.Point;
import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Display;
import android.view.View;
+import android.view.WindowManager;
import android.view.animation.Interpolator;
-import com.android.systemui.R;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+
+import com.google.android.colorextraction.ColorExtractor;
+import com.google.android.colorextraction.drawable.GradientDrawable;
/**
* A view which can draw a scrim
*/
-public class ScrimView extends View
-{
- private final Paint mPaint = new Paint();
- private int mScrimColor;
- private boolean mIsEmpty = true;
+public class ScrimView extends View implements ConfigurationController.ConfigurationListener {
+ private static final String TAG = "ScrimView";
+ private final ColorExtractor.GradientColors mColors;
private boolean mDrawAsSrc;
private float mViewAlpha = 1.0f;
private ValueAnimator mAlphaAnimator;
private Rect mExcludedRect = new Rect();
private boolean mHasExcludedArea;
- private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener
- = new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mViewAlpha = (float) animation.getAnimatedValue();
- invalidate();
+ private Drawable mDrawable;
+ private PorterDuffColorFilter mColorFilter;
+ private int mTintColor;
+ private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener = animation -> {
+ if (mDrawable == null) {
+ Log.w(TAG, "Trying to animate null drawable");
+ return;
}
+ mDrawable.setAlpha((int) (255 * (float) animation.getAnimatedValue()));
};
private AnimatorListenerAdapter mClearAnimatorListener = new AnimatorListenerAdapter() {
@Override
@@ -76,72 +89,134 @@
public ScrimView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ScrimView);
+ mDrawable = new GradientDrawable(context);
+ mDrawable.setCallback(this);
+ mColors = new ColorExtractor.GradientColors();
+ updateScreenSize();
- try {
- mScrimColor = ta.getColor(R.styleable.ScrimView_scrimColor, Color.BLACK);
- } finally {
- ta.recycle();
- }
+ // We need to know about configuration changes to update the gradient size
+ // since it's independent from view bounds.
+ ConfigurationController config = Dependency.get(ConfigurationController.class);
+ config.addCallback(this);
}
@Override
protected void onDraw(Canvas canvas) {
- if (mDrawAsSrc || (!mIsEmpty && mViewAlpha > 0f)) {
- PorterDuff.Mode mode = mDrawAsSrc ? PorterDuff.Mode.SRC : PorterDuff.Mode.SRC_OVER;
- int color = getScrimColorWithAlpha();
+ if (mDrawAsSrc || mDrawable.getAlpha() > 0) {
if (!mHasExcludedArea) {
- canvas.drawColor(color, mode);
+ mDrawable.draw(canvas);
} else {
- mPaint.setColor(color);
if (mExcludedRect.top > 0) {
- canvas.drawRect(0, 0, getWidth(), mExcludedRect.top, mPaint);
+ canvas.save();
+ canvas.clipRect(0, 0, getWidth(), mExcludedRect.top);
+ mDrawable.draw(canvas);
+ canvas.restore();
}
if (mExcludedRect.left > 0) {
- canvas.drawRect(0, mExcludedRect.top, mExcludedRect.left, mExcludedRect.bottom,
- mPaint);
+ canvas.save();
+ canvas.clipRect(0, mExcludedRect.top, mExcludedRect.left,
+ mExcludedRect.bottom);
+ mDrawable.draw(canvas);
+ canvas.restore();
}
if (mExcludedRect.right < getWidth()) {
- canvas.drawRect(mExcludedRect.right,
- mExcludedRect.top,
- getWidth(),
- mExcludedRect.bottom,
- mPaint);
+ canvas.save();
+ canvas.clipRect(mExcludedRect.right, mExcludedRect.top, getWidth(),
+ mExcludedRect.bottom);
+ mDrawable.draw(canvas);
+ canvas.restore();
}
if (mExcludedRect.bottom < getHeight()) {
- canvas.drawRect(0, mExcludedRect.bottom, getWidth(), getHeight(), mPaint);
+ canvas.save();
+ canvas.clipRect(0, mExcludedRect.bottom, getWidth(), getHeight());
+ mDrawable.draw(canvas);
+ canvas.restore();
}
}
}
}
- public int getScrimColorWithAlpha() {
- int color = mScrimColor;
- color = Color.argb((int) (Color.alpha(color) * mViewAlpha), Color.red(color),
- Color.green(color), Color.blue(color));
- return color;
+ public void setDrawable(Drawable drawable) {
+ mDrawable = drawable;
+ mDrawable.setCallback(this);
+ mDrawable.setBounds(getLeft(), getTop(), getRight(), getBottom());
+ invalidate();
+ }
+
+ @Override
+ public void invalidateDrawable(@NonNull Drawable drawable) {
+ super.invalidateDrawable(drawable);
+ if (drawable == mDrawable) {
+ invalidate();
+ }
}
public void setDrawAsSrc(boolean asSrc) {
mDrawAsSrc = asSrc;
- mPaint.setXfermode(new PorterDuffXfermode(mDrawAsSrc ? PorterDuff.Mode.SRC
- : PorterDuff.Mode.SRC_OVER));
- invalidate();
+ PorterDuff.Mode mode = asSrc ? PorterDuff.Mode.SRC : PorterDuff.Mode.SRC_OVER;
+ mDrawable.setXfermode(new PorterDuffXfermode(mode));
}
- public void setScrimColor(int color) {
- if (color != mScrimColor) {
- mIsEmpty = Color.alpha(color) == 0;
- mScrimColor = color;
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (changed) {
+ mDrawable.setBounds(left, top, right, bottom);
invalidate();
- if (mChangeRunnable != null) {
- mChangeRunnable.run();
- }
}
}
- public int getScrimColor() {
- return mScrimColor;
+ public void setColors(@NonNull ColorExtractor.GradientColors colors) {
+ if (colors == null) {
+ throw new IllegalArgumentException("Colors cannot be null");
+ }
+ if (mColors.equals(colors)) {
+ return;
+ }
+ mColors.set(colors);
+ updateColorWithTint();
+ }
+
+ @VisibleForTesting
+ Drawable getDrawable() {
+ return mDrawable;
+ }
+
+ public void setTint(int color) {
+ if (mTintColor == color) {
+ return;
+ }
+ mTintColor = color;
+ updateColorWithTint();
+ }
+
+ private void updateColorWithTint() {
+ if (mDrawable instanceof GradientDrawable) {
+ // Optimization to blend colors and avoid a color filter
+ GradientDrawable drawable = (GradientDrawable) mDrawable;
+ float tintAmount = Color.alpha(mTintColor) / 255f;
+ int mainTinted = ColorUtils.blendARGB(mColors.getMainColor(), mTintColor,
+ tintAmount);
+ int secondaryTinted = ColorUtils.blendARGB(mColors.getSecondaryColor(), mTintColor,
+ tintAmount);
+ drawable.setColors(mainTinted, secondaryTinted, false);
+ } else {
+ if (mColorFilter == null) {
+ mColorFilter = new PorterDuffColorFilter(mTintColor, PorterDuff.Mode.SRC_OVER);
+ } else {
+ mColorFilter.setColor(mTintColor);
+ }
+ mDrawable.setColorFilter(Color.alpha(mTintColor) == 0 ? null : mColorFilter);
+ mDrawable.invalidateSelf();
+ }
+
+ if (mChangeRunnable != null) {
+ mChangeRunnable.run();
+ }
+ }
+
+ public int getTint() {
+ return mTintColor;
}
@Override
@@ -150,23 +225,30 @@
}
public void setViewAlpha(float alpha) {
- if (mAlphaAnimator != null) {
- mAlphaAnimator.cancel();
- }
if (alpha != mViewAlpha) {
mViewAlpha = alpha;
- invalidate();
+
+ if (mAlphaAnimator != null) {
+ mAlphaAnimator.cancel();
+ }
+
+ mDrawable.setAlpha((int) (255 * alpha));
if (mChangeRunnable != null) {
mChangeRunnable.run();
}
}
}
+ @VisibleForTesting
+ float getViewAlpha() {
+ return mViewAlpha;
+ }
+
public void animateViewAlpha(float alpha, long durationOut, Interpolator interpolator) {
if (mAlphaAnimator != null) {
mAlphaAnimator.cancel();
}
- mAlphaAnimator = ValueAnimator.ofFloat(mViewAlpha, alpha);
+ mAlphaAnimator = ValueAnimator.ofFloat(getViewAlpha(), alpha);
mAlphaAnimator.addUpdateListener(mAlphaUpdateListener);
mAlphaAnimator.addListener(mClearAnimatorListener);
mAlphaAnimator.setInterpolator(interpolator);
@@ -193,4 +275,25 @@
public void setChangeRunnable(Runnable changeRunnable) {
mChangeRunnable = changeRunnable;
}
+
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ updateScreenSize();
+ }
+
+ private void updateScreenSize() {
+ if (mDrawable instanceof GradientDrawable) {
+ WindowManager wm = mContext.getSystemService(WindowManager.class);
+ if (wm == null) {
+ Log.w(TAG, "Can't resize gradient drawable to fit the screen");
+ return;
+ }
+ Display display = wm.getDefaultDisplay();
+ if (display != null) {
+ Point size = new Point();
+ display.getRealSize(size);
+ ((GradientDrawable) mDrawable).setScreenSize(size.x, size.y);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 67d5b6a..2be5b83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -20,9 +20,12 @@
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.support.v4.graphics.ColorUtils;
+import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
@@ -30,6 +33,7 @@
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -38,12 +42,14 @@
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.stack.ViewState;
+import com.google.android.colorextraction.ColorExtractor;
+
/**
* 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 {
+ OnHeadsUpChangedListener, ColorExtractor.OnColorsChangedListener {
public static final long ANIMATION_DURATION = 220;
public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR
= new PathInterpolator(0f, 0, 0.7f, 1f);
@@ -61,11 +67,16 @@
private final LightBarController mLightBarController;
protected final ScrimView mScrimBehind;
- private final ScrimView mScrimInFront;
+ protected final ScrimView mScrimInFront;
private final UnlockMethodCache mUnlockMethodCache;
private final View mHeadsUpScrim;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final ColorExtractor mColorExtractor;
+ private ColorExtractor.GradientColors mLockColors;
+ private ColorExtractor.GradientColors mSystemColors;
+ private boolean mNeedsDrawableColorUpdate;
+
protected float mScrimBehindAlpha;
protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
protected float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
@@ -98,6 +109,7 @@
private boolean mSkipFirstFrame;
private boolean mDontAnimateBouncerChanges;
private boolean mKeyguardFadingOutInProgress;
+ private boolean mAnimatingDozeUnlock;
private ValueAnimator mKeyguardFadeoutAnimation;
public ScrimController(LightBarController lightBarController, ScrimView scrimBehind,
@@ -111,12 +123,22 @@
mLightBarController = lightBarController;
mScrimBehindAlpha = context.getResources().getFloat(R.dimen.scrim_behind_alpha);
+ mColorExtractor = new ColorExtractor(context);
+ mColorExtractor.setListener(this);
+ mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK);
+ mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM);
+ mNeedsDrawableColorUpdate = true;
+
updateHeadsUpScrim(false);
updateScrims();
}
public void setKeyguardShowing(boolean showing) {
mKeyguardShowing = showing;
+
+ // Showing/hiding the keyguard means that scrim colors
+ // will probably have to be switched
+ mNeedsDrawableColorUpdate = true;
scheduleUpdate();
}
@@ -157,6 +179,7 @@
public void setWakeAndUnlocking() {
mWakeAndUnlocking = true;
+ mAnimatingDozeUnlock = true;
scheduleUpdate();
}
@@ -192,7 +215,7 @@
public void animateKeyguardUnoccluding(long duration) {
mAnimateChange = false;
- setScrimBehindColor(0f);
+ setScrimBehindAlpha(0f);
mAnimateChange = true;
scheduleUpdate();
mDurationOverride = duration;
@@ -246,23 +269,35 @@
}
protected void updateScrims() {
- if (mAnimateKeyguardFadingOut || mForceHideScrims) {
- setScrimInFrontColor(0f);
- setScrimBehindColor(0f);
- } else if (mWakeAndUnlocking) {
+ // Make sure we have the right gradients
+ if (mNeedsDrawableColorUpdate) {
+ mNeedsDrawableColorUpdate = false;
+ if (mKeyguardShowing) {
+ mScrimInFront.setColors(mLockColors);
+ mScrimBehind.setColors(mLockColors);
+ } else {
+ mScrimInFront.setColors(mSystemColors);
+ mScrimBehind.setColors(mSystemColors);
+ }
+ }
+
+ 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.
if (mDozing) {
- setScrimInFrontColor(0f);
- setScrimBehindColor(1f);
+ setScrimInFrontAlpha(0f);
+ setScrimBehindAlpha(1f);
} else {
- setScrimInFrontColor(1f);
- setScrimBehindColor(0f);
+ setScrimInFrontAlpha(1f);
+ setScrimBehindAlpha(0f);
}
} else if (!mKeyguardShowing && !mBouncerShowing) {
updateScrimNormal();
- setScrimInFrontColor(0);
+ setScrimInFrontAlpha(0);
} else {
updateScrimKeyguard();
}
@@ -275,18 +310,18 @@
float fraction = 1 - behindFraction;
fraction = (float) Math.pow(fraction, 0.8f);
behindFraction = (float) Math.pow(behindFraction, 0.8f);
- setScrimInFrontColor(fraction * getScrimInFrontAlpha());
- setScrimBehindColor(behindFraction * mScrimBehindAlphaKeyguard);
+ setScrimInFrontAlpha(fraction * getScrimInFrontAlpha());
+ setScrimBehindAlpha(behindFraction * mScrimBehindAlphaKeyguard);
} else if (mBouncerShowing && !mBouncerIsKeyguard) {
- setScrimInFrontColor(getScrimInFrontAlpha());
+ setScrimInFrontAlpha(getScrimInFrontAlpha());
updateScrimNormal();
} else if (mBouncerShowing) {
- setScrimInFrontColor(0f);
- setScrimBehindColor(mScrimBehindAlpha);
+ setScrimInFrontAlpha(0f);
+ setScrimBehindAlpha(mScrimBehindAlpha);
} else {
float fraction = Math.max(0, Math.min(mFraction, 1));
- setScrimInFrontColor(0f);
- setScrimBehindColor(fraction
+ setScrimInFrontAlpha(0f);
+ setScrimBehindAlpha(fraction
* (mScrimBehindAlphaKeyguard - mScrimBehindAlphaUnlocking)
+ mScrimBehindAlphaUnlocking);
}
@@ -297,30 +332,29 @@
// let's start this 20% of the way down the screen
frac = frac * 1.2f - 0.2f;
if (frac <= 0) {
- setScrimBehindColor(0);
+ setScrimBehindAlpha(0);
} else {
// woo, special effects
final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
- setScrimBehindColor(k * mScrimBehindAlpha);
+ setScrimBehindAlpha(k * mScrimBehindAlpha);
}
}
- private void setScrimBehindColor(float alpha) {
- setScrimColor(mScrimBehind, alpha);
+ private void setScrimBehindAlpha(float alpha) {
+ setScrimAlpha(mScrimBehind, alpha);
}
- private void setScrimInFrontColor(float alpha) {
- setScrimColor(mScrimInFront, 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 setScrimColor(View scrim, float alpha) {
+ private void setScrimAlpha(View scrim, float alpha) {
updateScrim(mAnimateChange, scrim, alpha, getCurrentScrimAlpha(scrim));
}
@@ -346,15 +380,20 @@
}
}
- protected void updateScrimColor(View scrim) {
+ private void updateScrimColor(View scrim) {
float alpha1 = getCurrentScrimAlpha(scrim);
if (scrim instanceof ScrimView) {
- float alpha2 = getDozeAlpha(scrim);
- float alpha = 1 - (1 - alpha1) * (1 - alpha2);
+ ScrimView scrimView = (ScrimView) scrim;
+ float dozeAlpha = getDozeAlpha(scrim);
+ float alpha = 1 - (1 - alpha1) * (1 - dozeAlpha);
alpha = Math.max(0, Math.min(1.0f, alpha));
- int baseColor = ((ScrimView) scrim).getScrimColor();
- ((ScrimView) scrim).setScrimColor(
- ColorUtils.setAlphaComponent(baseColor, (int) (alpha * 255)));
+ scrimView.setViewAlpha(alpha);
+
+ int dozeTint = Color.TRANSPARENT;
+ if (mAnimatingDozeUnlock || mDozing) {
+ dozeTint = Color.BLACK;
+ }
+ scrimView.setTint(dozeTint);
} else {
scrim.setAlpha(alpha1);
}
@@ -363,13 +402,10 @@
private void startScrimAnimation(final View scrim, float target) {
float current = getCurrentScrimAlpha(scrim);
ValueAnimator anim = ValueAnimator.ofFloat(current, target);
- anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float alpha = (float) animation.getAnimatedValue();
- setCurrentScrimAlpha(scrim, alpha);
- updateScrimColor(scrim);
- }
+ anim.addUpdateListener(animation -> {
+ float alpha = (float) animation.getAnimatedValue();
+ setCurrentScrimAlpha(scrim, alpha);
+ updateScrimColor(scrim);
});
anim.setInterpolator(getInterpolator());
anim.setStartDelay(mAnimationDelay);
@@ -384,6 +420,7 @@
if (mKeyguardFadingOutInProgress) {
mKeyguardFadeoutAnimation = null;
mKeyguardFadingOutInProgress = false;
+ mAnimatingDozeUnlock = false;
}
scrim.setTag(TAG_KEY_ANIM, null);
scrim.setTag(TAG_KEY_ANIM_TARGET, null);
@@ -436,6 +473,8 @@
mOnAnimationFinished = null;
}
mKeyguardFadingOutInProgress = false;
+ if (!mWakeAndUnlocking || force)
+ mAnimatingDozeUnlock = false;
}
}
@@ -559,8 +598,10 @@
mScrimBehind.setExcludedArea(area);
}
- public int getScrimBehindColor() {
- return mScrimBehind.getScrimColorWithAlpha();
+ 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) {
@@ -577,4 +618,18 @@
public void setCurrentUser(int currentUser) {
// Don't care in the base class.
}
+
+ @Override
+ public void onColorsChanged(ColorExtractor.GradientColors colors, int which) {
+ if ((which & WallpaperManager.FLAG_LOCK) != 0) {
+ mLockColors = colors;
+ mNeedsDrawableColorUpdate = true;
+ scheduleUpdate();
+ }
+ if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
+ mSystemColors = colors;
+ mNeedsDrawableColorUpdate = true;
+ scheduleUpdate();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 859c435..63bb4da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -58,6 +58,7 @@
import android.view.animation.Interpolator;
import android.widget.OverScroller;
import android.widget.ScrollView;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.ExpandHelper;
@@ -87,6 +88,8 @@
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ScrollAdapter;
+import android.support.v4.graphics.ColorUtils;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -485,16 +488,8 @@
float alpha = BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount);
alpha *= mBackgroundFadeAmount;
// We need to manually blend in the background color
- int scrimColor = mScrimController.getScrimBehindColor();
- // SRC_OVER blending Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc
- float alphaInv = 1 - alpha;
- int color = Color.argb((int) (alpha * 255 + alphaInv * Color.alpha(scrimColor)),
- (int) (mBackgroundFadeAmount * Color.red(mBgColor)
- + alphaInv * Color.red(scrimColor)),
- (int) (mBackgroundFadeAmount * Color.green(mBgColor)
- + alphaInv * Color.green(scrimColor)),
- (int) (mBackgroundFadeAmount * Color.blue(mBgColor)
- + alphaInv * Color.blue(scrimColor)));
+ int scrimColor = mScrimController.getBackgroundColor();
+ int color = ColorUtils.blendARGB(scrimColor, mBgColor, alpha);
if (mCachedBackgroundColor != color) {
mCachedBackgroundColor = color;
mBackgroundPaint.setColor(color);
@@ -4074,12 +4069,7 @@
public void setScrimController(ScrimController scrimController) {
mScrimController = scrimController;
- mScrimController.setScrimBehindChangeRunnable(new Runnable() {
- @Override
- public void run() {
- updateBackgroundDimming();
- }
- });
+ mScrimController.setScrimBehindChangeRunnable(this::updateBackgroundDimming);
}
public void forceNoOverlappingRendering(boolean force) {
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 8eedf31..fa2d3b5 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -43,7 +43,8 @@
android-support-v7-appcompat \
android-support-v7-mediarouter \
android-support-v14-preference \
- android-support-v17-leanback
+ android-support-v17-leanback \
+ colorextraction
LOCAL_STATIC_JAVA_LIBRARIES := \
metrics-helper-lib \
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
new file mode 100644
index 0000000..ea14681
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 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;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+
+import android.graphics.drawable.VectorDrawable;
+import android.testing.AndroidTestingRunner;
+import android.view.View;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.ScrimView;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import static junit.framework.Assert.assertEquals;
+
+@RunWith(AndroidTestingRunner.class)
+public class ScrimViewTest extends SysuiTestCase {
+
+ ScrimView mView;
+
+ @Before
+ public void setUp() {
+ mView = new ScrimView(getContext());
+ mView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ mView.layout(0, 0, 1920, 1080);
+ }
+
+ @Test
+ public void testSetDrawable_UpdateDrawable() {
+ Drawable drawable = new ColorDrawable(Color.GREEN);
+ mView.setDrawable(drawable);
+ assertEquals(drawable, mView.getDrawable());
+ }
+
+ @Test
+ public void testSetViewAlpha_propagatesToDrawable() {
+ float alpha = 0.5f;
+ mView.setViewAlpha(alpha);
+ assertEquals(mView.getViewAlpha(), alpha);
+ }
+
+ @Test
+ public void testOnDraw_ExcludeRectDrawable() {
+ mView.setExcludedArea(new Rect(10, 10, 20, 20));
+ Canvas canvas = mock(Canvas.class);
+ mView.onDraw(canvas);
+ // One time for each rect side
+ verify(canvas, times(4)).clipRect(anyInt(), anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void setTint_set() {
+ int tint = Color.BLUE;
+ mView.setTint(tint);
+ assertEquals(mView.getTint(), tint);
+ }
+}