diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 29fec416c656b..6d3f976a73e9e 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -26,7 +26,7 @@
android:fitsSystemWindows="true"
android:descendantFocusability="afterDescendants">
-
-
+
-
@@ -80,7 +80,7 @@
android:visibility="gone" />
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BackDropView.java b/packages/SystemUI/src/com/android/systemui/statusbar/BackDropView.java
new file mode 100644
index 0000000000000..f1eb9febfb334
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BackDropView.java
@@ -0,0 +1,65 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+/**
+ * A view who contains media artwork.
+ */
+public class BackDropView extends FrameLayout
+{
+ private Runnable mOnVisibilityChangedRunnable;
+
+ public BackDropView(Context context) {
+ super(context);
+ }
+
+ public BackDropView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public BackDropView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public BackDropView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ if (changedView == this && mOnVisibilityChangedRunnable != null) {
+ mOnVisibilityChangedRunnable.run();
+ }
+ }
+
+ public void setOnVisibilityChangedRunnable(Runnable runnable) {
+ mOnVisibilityChangedRunnable = runnable;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
new file mode 100644
index 0000000000000..23534255db116
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -0,0 +1,123 @@
+/*
+ * 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;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+/**
+ * A view which can draw a scrim
+ */
+public class ScrimView extends View
+{
+ private int mScrimColor;
+ private boolean mIsEmpty;
+ private boolean mDrawAsSrc;
+ private float mViewAlpha = 1.0f;
+ private ValueAnimator mAlphaAnimator;
+ private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener
+ = new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mViewAlpha = (float) animation.getAnimatedValue();
+ invalidate();
+ }
+ };
+ private AnimatorListenerAdapter mClearAnimatorListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAlphaAnimator = null;
+ }
+ };
+
+ public ScrimView(Context context) {
+ this(context, null);
+ }
+
+ public ScrimView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ScrimView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public ScrimView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mDrawAsSrc || !mIsEmpty) {
+ PorterDuff.Mode mode = mDrawAsSrc ? PorterDuff.Mode.SRC : PorterDuff.Mode.SRC_OVER;
+ int color = mScrimColor;
+ color = Color.argb((int) (Color.alpha(color) * mViewAlpha), Color.red(color),
+ Color.green(color), Color.blue(color));
+ canvas.drawColor(color, mode);
+ }
+ }
+
+ public void setDrawAsSrc(boolean asSrc) {
+ mDrawAsSrc = asSrc;
+ invalidate();
+ }
+
+ public void setScrimColor(int color) {
+ if (color != mScrimColor) {
+ mIsEmpty = Color.alpha(color) == 0;
+ mScrimColor = color;
+ invalidate();
+ }
+ }
+
+ public int getScrimColor() {
+ return mScrimColor;
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ public void setViewAlpha(float alpha) {
+ if (mAlphaAnimator != null) {
+ mAlphaAnimator.cancel();
+ }
+ mViewAlpha = alpha;
+ invalidate();
+ }
+
+ public void animateViewAlpha(float alpha, long durationOut, Interpolator interpolator) {
+ if (mAlphaAnimator != null) {
+ mAlphaAnimator.cancel();
+ }
+ mAlphaAnimator = ValueAnimator.ofFloat(mViewAlpha, alpha);
+ mAlphaAnimator.addUpdateListener(mAlphaUpdateListener);
+ mAlphaAnimator.addListener(mClearAnimatorListener);
+ mAlphaAnimator.setInterpolator(interpolator);
+ mAlphaAnimator.setDuration(durationOut);
+ mAlphaAnimator.start();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 624fea518cfad..5e9a64ccc6ca5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -51,7 +51,9 @@ import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.Xfermode;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.InputMethodService;
@@ -120,6 +122,7 @@ import com.android.systemui.doze.DozeService;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DismissView;
@@ -131,6 +134,7 @@ import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.NotificationOverflowContainer;
+import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.SpeedBumpView;
import com.android.systemui.statusbar.StatusBarIconView;
@@ -431,8 +435,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
- private FrameLayout mBackdrop;
+ private BackDropView mBackdrop;
private ImageView mBackdropFront, mBackdropBack;
+ private PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
+ private PorterDuffXfermode mSrcOverXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
private MediaSessionManager mMediaSessionManager;
private MediaController mMediaController;
@@ -723,8 +729,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mStackScroller.setDismissView(mDismissView);
mExpandedContents = mStackScroller;
- mScrimController = new ScrimController(mStatusBarWindow.findViewById(R.id.scrim_behind),
- mStatusBarWindow.findViewById(R.id.scrim_in_front));
+ mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
+ mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
+ mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);
+
+ ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
+ ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
+ mScrimController = new ScrimController(scrimBehind, scrimInFront);
+ mScrimController.setBackDropView(mBackdrop);
mStatusBarView.setScrimController(mScrimController);
mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
@@ -863,10 +875,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
});
}
- mBackdrop = (FrameLayout) mStatusBarWindow.findViewById(R.id.backdrop);
- mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
- mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);
-
// User info. Trigger first load.
mHeader.setUserInfoController(mUserInfoController);
mKeyguardStatusBar.setUserInfoController(mUserInfoController);
@@ -1852,7 +1860,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
if (metaDataChanged) {
if (mBackdropBack.getDrawable() != null) {
- mBackdropFront.setImageDrawable(mBackdropBack.getDrawable());
+ Drawable drawable = mBackdropBack.getDrawable();
+ mBackdropFront.setImageDrawable(drawable);
+ mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode);
mBackdropFront.setAlpha(1f);
mBackdropFront.setVisibility(View.VISIBLE);
} else {
@@ -1867,6 +1877,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
} else {
mBackdropBack.setImageBitmap(artworkBitmap);
}
+ mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode);
if (mBackdropFront.getVisibility() == View.VISIBLE) {
if (DEBUG_MEDIA) {
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 ddb03e7fac686..a502470480d5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -21,7 +21,6 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
@@ -31,6 +30,8 @@ import android.view.animation.Interpolator;
import com.android.systemui.R;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.statusbar.BackDropView;
+import com.android.systemui.statusbar.ScrimView;
/**
* Controls both the scrim behind the notifications and in front of the notifications (when a
@@ -48,8 +49,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
private static final float SCRIM_IN_FRONT_ALPHA = 0.75f;
private static final int TAG_KEY_ANIM = R.id.scrim;
- private final View mScrimBehind;
- private final View mScrimInFront;
+ private final ScrimView mScrimBehind;
+ private final ScrimView mScrimInFront;
private final UnlockMethodCache mUnlockMethodCache;
private final DozeParameters mDozeParameters;
@@ -70,8 +71,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
private long mPulseEndTime;
private final Interpolator mInterpolator = new DecelerateInterpolator();
private final Interpolator mLinearOutSlowInInterpolator;
+ private BackDropView mBackDropView;
- public ScrimController(View scrimBehind, View scrimInFront) {
+ public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront) {
mScrimBehind = scrimBehind;
mScrimInFront = scrimInFront;
final Context context = scrimBehind.getContext();
@@ -230,17 +232,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
}
}
- private void setScrimColor(View scrim, float alpha) {
+ private void setScrimColor(ScrimView scrim, float alpha) {
int color = Color.argb((int) (alpha * 255), 0, 0, 0);
if (mAnimateChange) {
startScrimAnimation(scrim, color);
} else {
- scrim.setBackgroundColor(color);
+ scrim.setScrimColor(color);
}
}
- private void startScrimAnimation(final View scrim, int targetColor) {
- int current = getBackgroundAlpha(scrim);
+ private void startScrimAnimation(final ScrimView scrim, int targetColor) {
+ int current = Color.alpha(scrim.getScrimColor());
int target = Color.alpha(targetColor);
if (current == targetColor) {
return;
@@ -254,7 +256,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
- scrim.setBackgroundColor(Color.argb(value, 0, 0, 0));
+ scrim.setScrimColor(Color.argb(value, 0, 0, 0));
}
});
anim.setInterpolator(mAnimateKeyguardFadingOut
@@ -278,15 +280,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
mAnimationStarted = true;
}
- private int getBackgroundAlpha(View scrim) {
- if (scrim.getBackground() instanceof ColorDrawable) {
- ColorDrawable drawable = (ColorDrawable) scrim.getBackground();
- return Color.alpha(drawable.getColor());
- } else {
- return 0;
- }
- }
-
@Override
public boolean onPreDraw() {
mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
@@ -349,4 +342,20 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
mPulseEndTime = 0;
}
};
+
+ public void setBackDropView(BackDropView backDropView) {
+ mBackDropView = backDropView;
+ mBackDropView.setOnVisibilityChangedRunnable(new Runnable() {
+ @Override
+ public void run() {
+ updateScrimBehindDrawingMode();
+ }
+ });
+ updateScrimBehindDrawingMode();
+ }
+
+ private void updateScrimBehindDrawingMode() {
+ boolean asSrc = mBackDropView.getVisibility() != View.VISIBLE;
+ mScrimBehind.setDrawAsSrc(asSrc);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 78554525e720c..89ce257cec08e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -20,12 +20,17 @@ import android.app.StatusBarManager;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.os.IBinder;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewRootImpl;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.widget.FrameLayout;
import com.android.systemui.R;
@@ -45,11 +50,14 @@ public class StatusBarWindowView extends FrameLayout {
private View mBrightnessMirror;
PhoneStatusBar mService;
+ private final Paint mTransparentSrcPaint = new Paint();
public StatusBarWindowView(Context context, AttributeSet attrs) {
super(context, attrs);
setMotionEventSplittingEnabled(false);
- setWillNotDraw(!DEBUG);
+ setWillNotDraw(false);
+ mTransparentSrcPaint.setColor(0);
+ mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
}
@Override
@@ -93,6 +101,15 @@ public class StatusBarWindowView extends FrameLayout {
if (root != null) {
root.setDrawDuringWindowsAnimating(true);
}
+
+ // We need to ensure that our window doesn't suffer from overdraw which would normally
+ // occur if our window is translucent. Since we are drawing the whole window anyway with
+ // the scrim, we don't need the window to be cleared in the beginning.
+ IBinder windowToken = getWindowToken();
+ WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
+ lp.token = windowToken;
+ setLayoutParams(lp);
+ WindowManagerGlobal.getInstance().changeCanvasOpacity(windowToken, true);
}
@Override
@@ -182,6 +199,24 @@ public class StatusBarWindowView extends FrameLayout {
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
+ // We need to ensure that our window is always drawn fully even when we have paddings,
+ // since we simulate it to be opaque.
+ int paddedBottom = getHeight() - getPaddingBottom();
+ int paddedRight = getWidth() - getPaddingRight();
+ if (getPaddingTop() != 0) {
+ canvas.drawRect(0, 0, getWidth(), getPaddingTop(), mTransparentSrcPaint);
+ }
+ if (getPaddingBottom() != 0) {
+ canvas.drawRect(0, paddedBottom, getWidth(), getHeight(), mTransparentSrcPaint);
+ }
+ if (getPaddingLeft() != 0) {
+ canvas.drawRect(0, getPaddingTop(), getPaddingLeft(), paddedBottom,
+ mTransparentSrcPaint);
+ }
+ if (getPaddingRight() != 0) {
+ canvas.drawRect(paddedRight, getPaddingTop(), getWidth(), paddedBottom,
+ mTransparentSrcPaint);
+ }
if (DEBUG) {
Paint pt = new Paint();
pt.setColor(0x80FFFF00);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 7bd2e5c6df043..895af628e1d29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -17,11 +17,11 @@
package com.android.systemui.statusbar.policy;
import com.android.systemui.R;
+import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.widget.FrameLayout;
@@ -33,26 +33,26 @@ public class BrightnessMirrorController {
public long TRANSITION_DURATION_OUT = 150;
public long TRANSITION_DURATION_IN = 200;
- private final View mScrimBehind;
+ private final ScrimView mScrimBehind;
private final View mBrightnessMirror;
private final View mPanelHolder;
private final int[] mInt2Cache = new int[2];
public BrightnessMirrorController(StatusBarWindowView statusBarWindow) {
- mScrimBehind = statusBarWindow.findViewById(R.id.scrim_behind);
+ mScrimBehind = (ScrimView) statusBarWindow.findViewById(R.id.scrim_behind);
mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror);
mPanelHolder = statusBarWindow.findViewById(R.id.panel_holder);
}
public void showMirror() {
mBrightnessMirror.setVisibility(View.VISIBLE);
- outAnimation(mScrimBehind.animate());
+ mScrimBehind.animateViewAlpha(0.0f, TRANSITION_DURATION_OUT, PhoneStatusBar.ALPHA_OUT);
outAnimation(mPanelHolder.animate())
.withLayer();
}
public void hideMirror() {
- inAnimation(mScrimBehind.animate());
+ mScrimBehind.animateViewAlpha(1.0f, TRANSITION_DURATION_IN, PhoneStatusBar.ALPHA_IN);
inAnimation(mPanelHolder.animate())
.withLayer()
.withEndAction(new Runnable() {