blob: ab89a5287cdbf5e23dee549ed5bdcb94453ba9d7 [file] [log] [blame]
Jorim Jaggia8b48e12014-05-19 20:26:46 +02001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.systemui.statusbar;
18
19import android.content.Context;
Selim Cinek697178b2014-07-02 19:40:30 +020020import android.content.res.ColorStateList;
Jorim Jaggia8b48e12014-05-19 20:26:46 +020021import android.graphics.Canvas;
22import android.graphics.PorterDuff;
Selim Cinek2627d722018-01-19 12:16:49 -080023import android.graphics.PorterDuffXfermode;
Jorim Jaggia8b48e12014-05-19 20:26:46 +020024import android.graphics.drawable.Drawable;
Selim Cinek0fe07392017-11-09 13:26:34 -080025import android.graphics.drawable.GradientDrawable;
26import android.graphics.drawable.LayerDrawable;
Selim Cinek697178b2014-07-02 19:40:30 +020027import android.graphics.drawable.RippleDrawable;
Jorim Jaggia8b48e12014-05-19 20:26:46 +020028import android.util.AttributeSet;
29import android.view.View;
30
Selim Cinek2627d722018-01-19 12:16:49 -080031import com.android.systemui.Interpolators;
Selim Cinek0fe07392017-11-09 13:26:34 -080032import com.android.systemui.R;
Selim Cinek2627d722018-01-19 12:16:49 -080033import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
Selim Cinek0fe07392017-11-09 13:26:34 -080034
Jorim Jaggia8b48e12014-05-19 20:26:46 +020035/**
36 * A view that can be used for both the dimmed and normal background of an notification.
37 */
38public class NotificationBackgroundView extends View {
39
Selim Cinek0fe07392017-11-09 13:26:34 -080040 private final boolean mDontModifyCorners;
Jorim Jaggia8b48e12014-05-19 20:26:46 +020041 private Drawable mBackground;
42 private int mClipTopAmount;
43 private int mActualHeight;
Selim Cineka686b2c2016-10-26 13:58:27 -070044 private int mClipBottomAmount;
Selim Cinek588423a2017-08-17 16:42:51 -070045 private int mTintColor;
Selim Cinek0fe07392017-11-09 13:26:34 -080046 private float[] mCornerRadii = new float[8];
Selim Cinek515b2032017-11-15 10:20:19 -080047 private boolean mBottomIsRounded;
48 private int mBackgroundTop;
Selim Cinek2871bef2017-11-22 08:40:00 -080049 private boolean mBottomAmountClips = true;
Selim Cinek2627d722018-01-19 12:16:49 -080050 private boolean mExpandAnimationRunning;
51 private float mActualWidth;
52 private int mDrawableAlpha = 255;
Jorim Jaggia8b48e12014-05-19 20:26:46 +020053
54 public NotificationBackgroundView(Context context, AttributeSet attrs) {
55 super(context, attrs);
Selim Cinek0fe07392017-11-09 13:26:34 -080056 mDontModifyCorners = getResources().getBoolean(
57 R.bool.config_clipNotificationsToOutline);
Jorim Jaggia8b48e12014-05-19 20:26:46 +020058 }
59
60 @Override
Jorim Jaggia8b48e12014-05-19 20:26:46 +020061 protected void onDraw(Canvas canvas) {
Selim Cinek2627d722018-01-19 12:16:49 -080062 if (mClipTopAmount + mClipBottomAmount < mActualHeight - mBackgroundTop
63 || mExpandAnimationRunning) {
Selim Cinek515b2032017-11-15 10:20:19 -080064 canvas.save();
Selim Cinek2627d722018-01-19 12:16:49 -080065 if (!mExpandAnimationRunning) {
66 canvas.clipRect(0, mClipTopAmount, getWidth(), mActualHeight - mClipBottomAmount);
67 }
Selim Cinek515b2032017-11-15 10:20:19 -080068 draw(canvas, mBackground);
69 canvas.restore();
70 }
Jorim Jaggia8b48e12014-05-19 20:26:46 +020071 }
72
73 private void draw(Canvas canvas, Drawable drawable) {
Selim Cinek515b2032017-11-15 10:20:19 -080074 if (drawable != null) {
75 int bottom = mActualHeight;
Selim Cinek2627d722018-01-19 12:16:49 -080076 if (mBottomIsRounded && mBottomAmountClips && !mExpandAnimationRunning) {
Selim Cinek515b2032017-11-15 10:20:19 -080077 bottom -= mClipBottomAmount;
78 }
Selim Cinek2627d722018-01-19 12:16:49 -080079 int left = 0;
80 int right = getWidth();
81 if (mExpandAnimationRunning) {
82 left = (int) ((getWidth() - mActualWidth) / 2.0f);
83 right = (int) (left + mActualWidth);
84 }
85 drawable.setBounds(left, mBackgroundTop, right, bottom);
Jorim Jaggia8b48e12014-05-19 20:26:46 +020086 drawable.draw(canvas);
87 }
88 }
89
90 @Override
91 protected boolean verifyDrawable(Drawable who) {
92 return super.verifyDrawable(who) || who == mBackground;
93 }
94
95 @Override
96 protected void drawableStateChanged() {
97 drawableStateChanged(mBackground);
98 }
99
100 private void drawableStateChanged(Drawable d) {
101 if (d != null && d.isStateful()) {
102 d.setState(getDrawableState());
103 }
104 }
105
Selim Cinek697178b2014-07-02 19:40:30 +0200106 @Override
107 public void drawableHotspotChanged(float x, float y) {
108 if (mBackground != null) {
109 mBackground.setHotspot(x, y);
110 }
111 }
112
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200113 /**
114 * Sets a background drawable. As we need to change our bounds independently of layout, we need
115 * the notion of a background independently of the regular View background..
116 */
117 public void setCustomBackground(Drawable background) {
118 if (mBackground != null) {
119 mBackground.setCallback(null);
120 unscheduleDrawable(mBackground);
121 }
122 mBackground = background;
Selim Cinek0fe07392017-11-09 13:26:34 -0800123 mBackground.mutate();
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200124 if (mBackground != null) {
125 mBackground.setCallback(this);
Selim Cinek588423a2017-08-17 16:42:51 -0700126 setTint(mTintColor);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200127 }
Jorim Jaggib7303a32015-08-19 16:51:36 -0700128 if (mBackground instanceof RippleDrawable) {
129 ((RippleDrawable) mBackground).setForceSoftware(true);
130 }
Selim Cinek0fe07392017-11-09 13:26:34 -0800131 updateBackgroundRadii();
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200132 invalidate();
133 }
134
Selim Cinek697178b2014-07-02 19:40:30 +0200135 public void setCustomBackground(int drawableResId) {
136 final Drawable d = mContext.getDrawable(drawableResId);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200137 setCustomBackground(d);
138 }
139
Selim Cinek697178b2014-07-02 19:40:30 +0200140 public void setTint(int tintColor) {
Selim Cinek697178b2014-07-02 19:40:30 +0200141 if (tintColor != 0) {
142 mBackground.setColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP);
Selim Cinek697178b2014-07-02 19:40:30 +0200143 } else {
144 mBackground.clearColorFilter();
Selim Cinek697178b2014-07-02 19:40:30 +0200145 }
Selim Cinek588423a2017-08-17 16:42:51 -0700146 mTintColor = tintColor;
Selim Cinek697178b2014-07-02 19:40:30 +0200147 invalidate();
148 }
149
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200150 public void setActualHeight(int actualHeight) {
Selim Cinek2627d722018-01-19 12:16:49 -0800151 if (mExpandAnimationRunning) {
152 return;
153 }
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200154 mActualHeight = actualHeight;
155 invalidate();
156 }
157
158 public int getActualHeight() {
159 return mActualHeight;
160 }
161
162 public void setClipTopAmount(int clipTopAmount) {
163 mClipTopAmount = clipTopAmount;
164 invalidate();
165 }
166
Selim Cineka686b2c2016-10-26 13:58:27 -0700167 public void setClipBottomAmount(int clipBottomAmount) {
168 mClipBottomAmount = clipBottomAmount;
169 invalidate();
170 }
171
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200172 @Override
173 public boolean hasOverlappingRendering() {
174
175 // Prevents this view from creating a layer when alpha is animating.
176 return false;
177 }
Selim Cinekb2da91b2014-09-02 17:35:20 +0200178
179 public void setState(int[] drawableState) {
180 mBackground.setState(drawableState);
181 }
182
183 public void setRippleColor(int color) {
184 if (mBackground instanceof RippleDrawable) {
185 RippleDrawable ripple = (RippleDrawable) mBackground;
186 ripple.setColor(ColorStateList.valueOf(color));
187 }
188 }
Selim Cinekec29d342017-05-05 18:31:49 -0700189
190 public void setDrawableAlpha(int drawableAlpha) {
Selim Cinek2627d722018-01-19 12:16:49 -0800191 mDrawableAlpha = drawableAlpha;
192 if (mExpandAnimationRunning) {
193 return;
194 }
Selim Cinekec29d342017-05-05 18:31:49 -0700195 mBackground.setAlpha(drawableAlpha);
196 }
Selim Cinek0fe07392017-11-09 13:26:34 -0800197
198 public void setRoundness(float topRoundness, float bottomRoundNess) {
Selim Cinek515b2032017-11-15 10:20:19 -0800199 mBottomIsRounded = bottomRoundNess != 0.0f;
Selim Cinek0fe07392017-11-09 13:26:34 -0800200 mCornerRadii[0] = topRoundness;
201 mCornerRadii[1] = topRoundness;
202 mCornerRadii[2] = topRoundness;
203 mCornerRadii[3] = topRoundness;
204 mCornerRadii[4] = bottomRoundNess;
205 mCornerRadii[5] = bottomRoundNess;
206 mCornerRadii[6] = bottomRoundNess;
207 mCornerRadii[7] = bottomRoundNess;
208 updateBackgroundRadii();
209 }
210
Selim Cinek2871bef2017-11-22 08:40:00 -0800211 public void setBottomAmountClips(boolean clips) {
212 if (clips != mBottomAmountClips) {
213 mBottomAmountClips = clips;
214 invalidate();
215 }
216 }
Selim Cinek0fe07392017-11-09 13:26:34 -0800217
218 private void updateBackgroundRadii() {
219 if (mDontModifyCorners) {
220 return;
221 }
222 if (mBackground instanceof LayerDrawable) {
223 GradientDrawable gradientDrawable =
224 (GradientDrawable) ((LayerDrawable) mBackground).getDrawable(0);
225 gradientDrawable.setCornerRadii(mCornerRadii);
226 }
227 }
228
Selim Cinek515b2032017-11-15 10:20:19 -0800229 public void setBackgroundTop(int backgroundTop) {
230 mBackgroundTop = backgroundTop;
231 invalidate();
232 }
Selim Cinek2627d722018-01-19 12:16:49 -0800233
234 public void setExpandAnimationParams(ActivityLaunchAnimator.ExpandAnimationParameters params) {
235 mActualHeight = params.getHeight();
236 mActualWidth = params.getWidth();
237 float alphaProgress = Interpolators.ALPHA_IN.getInterpolation(
238 params.getProgress(
239 ActivityLaunchAnimator.ANIMATION_DURATION_FADE_CONTENT /* delay */,
240 ActivityLaunchAnimator.ANIMATION_DURATION_FADE_APP /* duration */));
241 mBackground.setAlpha((int) (mDrawableAlpha * (1.0f - alphaProgress)));
242 invalidate();
243 }
244
245 public void setExpandAnimationRunning(boolean running) {
246 mExpandAnimationRunning = running;
247 if (mBackground instanceof LayerDrawable) {
248 GradientDrawable gradientDrawable =
249 (GradientDrawable) ((LayerDrawable) mBackground).getDrawable(0);
250 gradientDrawable.setXfermode(
251 running ? new PorterDuffXfermode(PorterDuff.Mode.SRC) : null);
Stan Ilievd192911e2018-02-06 16:22:01 -0500252 // Speed optimization: disable AA if transfer mode is not SRC_OVER. AA is not easy to
253 // spot during animation anyways.
254 gradientDrawable.setAntiAlias(!running);
Selim Cinek2627d722018-01-19 12:16:49 -0800255 }
256 if (!mExpandAnimationRunning) {
257 setDrawableAlpha(mDrawableAlpha);
258 }
259 invalidate();
260 }
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200261}