blob: 0f615aa9356f6ec1d8c58b41a0f7acbe2aeac199 [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.notification.row;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.View;
import com.android.internal.util.ArrayUtils;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
/**
* A view that can be used for both the dimmed and normal background of an notification.
*/
public class NotificationBackgroundView extends View {
private final boolean mDontModifyCorners;
private Drawable mBackground;
private int mClipTopAmount;
private int mActualHeight;
private int mClipBottomAmount;
private int mTintColor;
private final float[] mCornerRadii = new float[8];
private boolean mBottomIsRounded;
private int mBackgroundTop;
private boolean mBottomAmountClips = true;
private boolean mExpandAnimationRunning;
private float mActualWidth;
private int mDrawableAlpha = 255;
private boolean mIsPressedAllowed;
public NotificationBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
mDontModifyCorners = getResources().getBoolean(
R.bool.config_clipNotificationsToOutline);
}
@Override
protected void onDraw(Canvas canvas) {
if (mClipTopAmount + mClipBottomAmount < mActualHeight - mBackgroundTop
|| mExpandAnimationRunning) {
canvas.save();
if (!mExpandAnimationRunning) {
canvas.clipRect(0, mClipTopAmount, getWidth(), mActualHeight - mClipBottomAmount);
}
draw(canvas, mBackground);
canvas.restore();
}
}
private void draw(Canvas canvas, Drawable drawable) {
if (drawable != null) {
int top = mBackgroundTop;
int bottom = mActualHeight;
if (mBottomIsRounded
&& mBottomAmountClips
&& !mExpandAnimationRunning) {
bottom -= mClipBottomAmount;
}
int left = 0;
int right = getWidth();
if (mExpandAnimationRunning) {
left = (int) ((getWidth() - mActualWidth) / 2.0f);
right = (int) (left + mActualWidth);
}
drawable.setBounds(left, top, right, bottom);
drawable.draw(canvas);
}
}
@Override
protected boolean verifyDrawable(Drawable who) {
return super.verifyDrawable(who) || who == mBackground;
}
@Override
protected void drawableStateChanged() {
setState(getDrawableState());
}
@Override
public void drawableHotspotChanged(float x, float y) {
if (mBackground != null) {
mBackground.setHotspot(x, y);
}
}
/**
* Sets a background drawable. As we need to change our bounds independently of layout, we need
* the notion of a background independently of the regular View background..
*/
public void setCustomBackground(Drawable background) {
if (mBackground != null) {
mBackground.setCallback(null);
unscheduleDrawable(mBackground);
}
mBackground = background;
mBackground.mutate();
if (mBackground != null) {
mBackground.setCallback(this);
setTint(mTintColor);
}
if (mBackground instanceof RippleDrawable) {
((RippleDrawable) mBackground).setForceSoftware(true);
}
updateBackgroundRadii();
invalidate();
}
public void setCustomBackground(int drawableResId) {
final Drawable d = mContext.getDrawable(drawableResId);
setCustomBackground(d);
}
public void setTint(int tintColor) {
if (tintColor != 0) {
mBackground.setColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP);
} else {
mBackground.clearColorFilter();
}
mTintColor = tintColor;
invalidate();
}
public void setActualHeight(int actualHeight) {
if (mExpandAnimationRunning) {
return;
}
mActualHeight = actualHeight;
invalidate();
}
public int getActualHeight() {
return mActualHeight;
}
public void setClipTopAmount(int clipTopAmount) {
mClipTopAmount = clipTopAmount;
invalidate();
}
public void setClipBottomAmount(int clipBottomAmount) {
mClipBottomAmount = clipBottomAmount;
invalidate();
}
@Override
public boolean hasOverlappingRendering() {
// Prevents this view from creating a layer when alpha is animating.
return false;
}
public void setState(int[] drawableState) {
if (mBackground != null && mBackground.isStateful()) {
if (!mIsPressedAllowed) {
drawableState = ArrayUtils.removeInt(drawableState,
com.android.internal.R.attr.state_pressed);
}
mBackground.setState(drawableState);
}
}
public void setRippleColor(int color) {
if (mBackground instanceof RippleDrawable) {
RippleDrawable ripple = (RippleDrawable) mBackground;
ripple.setColor(ColorStateList.valueOf(color));
}
}
public void setDrawableAlpha(int drawableAlpha) {
mDrawableAlpha = drawableAlpha;
if (mExpandAnimationRunning) {
return;
}
mBackground.setAlpha(drawableAlpha);
}
/**
* Sets the current top and bottom radius for this background.
*/
public void setRadius(float topRoundness, float bottomRoundness) {
if (topRoundness == mCornerRadii[0] && bottomRoundness == mCornerRadii[4]) {
return;
}
mBottomIsRounded = bottomRoundness != 0.0f;
mCornerRadii[0] = topRoundness;
mCornerRadii[1] = topRoundness;
mCornerRadii[2] = topRoundness;
mCornerRadii[3] = topRoundness;
mCornerRadii[4] = bottomRoundness;
mCornerRadii[5] = bottomRoundness;
mCornerRadii[6] = bottomRoundness;
mCornerRadii[7] = bottomRoundness;
updateBackgroundRadii();
}
public void setBottomAmountClips(boolean clips) {
if (clips != mBottomAmountClips) {
mBottomAmountClips = clips;
invalidate();
}
}
private void updateBackgroundRadii() {
if (mDontModifyCorners) {
return;
}
if (mBackground instanceof LayerDrawable) {
GradientDrawable gradientDrawable =
(GradientDrawable) ((LayerDrawable) mBackground).getDrawable(0);
gradientDrawable.setCornerRadii(mCornerRadii);
}
}
public void setBackgroundTop(int backgroundTop) {
mBackgroundTop = backgroundTop;
invalidate();
}
/** Set the current expand animation size. */
public void setExpandAnimationSize(int actualWidth, int actualHeight) {
mActualHeight = actualHeight;
mActualWidth = actualWidth;
invalidate();
}
public void setExpandAnimationRunning(boolean running) {
mExpandAnimationRunning = running;
if (mBackground instanceof LayerDrawable) {
GradientDrawable gradientDrawable =
(GradientDrawable) ((LayerDrawable) mBackground).getDrawable(0);
// Speed optimization: disable AA if transfer mode is not SRC_OVER. AA is not easy to
// spot during animation anyways.
gradientDrawable.setAntiAlias(!running);
}
if (!mExpandAnimationRunning) {
setDrawableAlpha(mDrawableAlpha);
}
invalidate();
}
public void setPressedAllowed(boolean allowed) {
mIsPressedAllowed = allowed;
}
}