blob: effe581ac9ca8c3ccb6014e37d7d65b2d6df7514 [file] [log] [blame]
Kenny Root15a4d2f2010-03-11 18:20:12 -08001/*
Jorim Jaggife40f7d2014-04-28 15:20:04 +02002 * Copyright (C) 2014 The Android Open Source Project
Kenny Root15a4d2f2010-03-11 18:20:12 -08003 *
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
Jorim Jaggife40f7d2014-04-28 15:20:04 +020014 * limitations under the License
Kenny Root15a4d2f2010-03-11 18:20:12 -080015 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080016
Joe Onorato79de0c52010-05-26 17:03:26 -040017package com.android.systemui.statusbar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ObjectAnimator;
Selim Cinekd35c2792016-01-21 13:20:57 -080022import android.animation.TimeAnimator;
Jorim Jaggia8b48e12014-05-19 20:26:46 +020023import android.animation.ValueAnimator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.Context;
Selim Cinek8efa6dd2014-05-19 16:27:37 +020025import android.graphics.Canvas;
Selim Cinek8efa6dd2014-05-19 16:27:37 +020026import android.graphics.RectF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.util.AttributeSet;
Jorim Jaggi251957d2014-04-09 04:24:09 +020028import android.view.MotionEvent;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070029import android.view.View;
ztenghui62f30e02014-06-05 09:55:04 -070030import android.view.ViewAnimationUtils;
Jorim Jaggi251957d2014-04-09 04:24:09 +020031import android.view.ViewConfiguration;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +020032import android.view.animation.Interpolator;
Jorim Jaggia8b48e12014-05-19 20:26:46 +020033import android.view.animation.PathInterpolator;
ztenghui62f30e02014-06-05 09:55:04 -070034
Winsonc0d70582016-01-29 10:24:39 -080035import com.android.systemui.Interpolators;
Jorim Jaggia8b48e12014-05-19 20:26:46 +020036import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070037import com.android.systemui.classifier.FalsingManager;
Selim Cinek33223572016-02-19 19:32:22 -080038import com.android.systemui.statusbar.notification.FakeShadowView;
Selim Cinekd35c2792016-01-21 13:20:57 -080039import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Jorim Jaggi46739852014-04-15 09:58:24 +020040
Jorim Jaggife40f7d2014-04-28 15:20:04 +020041/**
42 * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
43 * to implement dimming/activating on Keyguard for the double-tap gesture
44 */
Jorim Jaggibe565df2014-04-28 17:51:23 +020045public abstract class ActivatableNotificationView extends ExpandableOutlineView {
Jorim Jaggi251957d2014-04-09 04:24:09 +020046
Jorim Jaggia8b48e12014-05-19 20:26:46 +020047 private static final long DOUBLETAP_TIMEOUT_MS = 1200;
Jorim Jaggid552d9d2014-05-07 19:41:13 +020048 private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
Jorim Jaggia8b48e12014-05-19 20:26:46 +020049 private static final int ACTIVATE_ANIMATION_LENGTH = 220;
Jorim Jaggi4e857f42014-11-17 19:14:04 +010050 private static final int DARK_ANIMATION_LENGTH = 170;
Jorim Jaggia8b48e12014-05-19 20:26:46 +020051
Selim Cinek8efa6dd2014-05-19 16:27:37 +020052 /**
53 * The amount of width, which is kept in the end when performing a disappear animation (also
54 * the amount from which the horizontal appearing begins)
55 */
56 private static final float HORIZONTAL_COLLAPSED_REST_PARTIAL = 0.05f;
57
58 /**
59 * At which point from [0,1] does the horizontal collapse animation end (or start when
60 * expanding)? 1.0 meaning that it ends immediately and 0.0 that it is continuously animated.
61 */
62 private static final float HORIZONTAL_ANIMATION_END = 0.2f;
63
64 /**
65 * At which point from [0,1] does the alpha animation end (or start when
66 * expanding)? 1.0 meaning that it ends immediately and 0.0 that it is continuously animated.
67 */
68 private static final float ALPHA_ANIMATION_END = 0.0f;
69
70 /**
71 * At which point from [0,1] does the horizontal collapse animation start (or start when
72 * expanding)? 1.0 meaning that it starts immediately and 0.0 that it is animated at all.
73 */
74 private static final float HORIZONTAL_ANIMATION_START = 1.0f;
75
76 /**
77 * At which point from [0,1] does the vertical collapse animation start (or end when
78 * expanding) 1.0 meaning that it starts immediately and 0.0 that it is animated at all.
79 */
80 private static final float VERTICAL_ANIMATION_START = 1.0f;
81
Jorim Jaggi4e857f42014-11-17 19:14:04 +010082 /**
83 * Scale for the background to animate from when exiting dark mode.
84 */
85 private static final float DARK_EXIT_SCALE_START = 0.93f;
86
Jorim Jaggia8b48e12014-05-19 20:26:46 +020087 private static final Interpolator ACTIVATE_INVERSE_INTERPOLATOR
88 = new PathInterpolator(0.6f, 0, 0.5f, 1);
89 private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
90 = new PathInterpolator(0, 0, 0.5f, 1);
Selim Cinekb2da91b2014-09-02 17:35:20 +020091 private final int mTintedRippleColor;
92 private final int mLowPriorityRippleColor;
Selim Cinekb5605e52015-02-20 18:21:41 +010093 protected final int mNormalRippleColor;
Jorim Jaggi251957d2014-04-09 04:24:09 +020094
95 private boolean mDimmed;
John Spurlockbf370992014-06-17 13:58:31 -040096 private boolean mDark;
Jorim Jaggi251957d2014-04-09 04:24:09 +020097
Dan Sandlerfe266a32014-05-15 22:28:06 -040098 private int mBgTint = 0;
Dan Sandlerfe266a32014-05-15 22:28:06 -040099
Jorim Jaggi251957d2014-04-09 04:24:09 +0200100 /**
101 * Flag to indicate that the notification has been touched once and the second touch will
102 * click it.
103 */
104 private boolean mActivated;
105
106 private float mDownX;
107 private float mDownY;
108 private final float mTouchSlop;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200109
110 private OnActivatedListener mOnActivatedListener;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200111
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200112 private final Interpolator mSlowOutFastInInterpolator;
113 private final Interpolator mSlowOutLinearInInterpolator;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200114 private Interpolator mCurrentAppearInterpolator;
115 private Interpolator mCurrentAlphaInterpolator;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200116
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200117 private NotificationBackgroundView mBackgroundNormal;
118 private NotificationBackgroundView mBackgroundDimmed;
119 private ObjectAnimator mBackgroundAnimator;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200120 private RectF mAppearAnimationRect = new RectF();
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200121 private float mAnimationTranslationY;
122 private boolean mDrawingAppearAnimation;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200123 private ValueAnimator mAppearAnimator;
124 private float mAppearAnimationFraction = -1.0f;
125 private float mAppearAnimationTranslation;
Selim Cinek697178b2014-07-02 19:40:30 +0200126 private boolean mShowingLegacyBackground;
127 private final int mLegacyColor;
128 private final int mNormalColor;
Selim Cinek3d2b94bf2014-07-02 22:12:47 +0200129 private final int mLowPriorityColor;
130 private boolean mIsBelowSpeedBump;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700131 private FalsingManager mFalsingManager;
Selim Cinek570981d2015-12-01 11:37:01 -0800132 private boolean mTrackTouch;
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200133
Selim Cinekd35c2792016-01-21 13:20:57 -0800134 private float mNormalBackgroundVisibilityAmount;
135 private ValueAnimator mFadeInFromDarkAnimator;
136 private ValueAnimator.AnimatorUpdateListener mBackgroundVisibilityUpdater
137 = new ValueAnimator.AnimatorUpdateListener() {
138 @Override
139 public void onAnimationUpdate(ValueAnimator animation) {
140 setNormalBackgroundVisibilityAmount(mBackgroundNormal.getAlpha());
141 }
142 };
143 private AnimatorListenerAdapter mFadeInEndListener = new AnimatorListenerAdapter() {
144 @Override
145 public void onAnimationEnd(Animator animation) {
146 super.onAnimationEnd(animation);
147 mFadeInFromDarkAnimator = null;
148 updateOutlineAlpha();
149 }
150 };
151 private ValueAnimator.AnimatorUpdateListener mUpdateOutlineListener
152 = new ValueAnimator.AnimatorUpdateListener() {
153 @Override
154 public void onAnimationUpdate(ValueAnimator animation) {
155 updateOutlineAlpha();
156 }
157 };
Selim Cinek277a8aa2016-01-22 12:12:37 -0800158 private float mShadowAlpha = 1.0f;
Selim Cinek33223572016-02-19 19:32:22 -0800159 private FakeShadowView mFakeShadow;
Selim Cinekd35c2792016-01-21 13:20:57 -0800160
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200161 public ActivatableNotificationView(Context context, AttributeSet attrs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 super(context, attrs);
Jorim Jaggi251957d2014-04-09 04:24:09 +0200163 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200164 mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200165 mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200166 setClipChildren(false);
167 setClipToPadding(false);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700168 mLegacyColor = context.getColor(R.color.notification_legacy_background_color);
169 mNormalColor = context.getColor(R.color.notification_material_background_color);
170 mLowPriorityColor = context.getColor(
Selim Cinek3d2b94bf2014-07-02 22:12:47 +0200171 R.color.notification_material_background_low_priority_color);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700172 mTintedRippleColor = context.getColor(
Selim Cinekb2da91b2014-09-02 17:35:20 +0200173 R.color.notification_ripple_tinted_color);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700174 mLowPriorityRippleColor = context.getColor(
Selim Cinekb2da91b2014-09-02 17:35:20 +0200175 R.color.notification_ripple_color_low_priority);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700176 mNormalRippleColor = context.getColor(
Selim Cinekb2da91b2014-09-02 17:35:20 +0200177 R.color.notification_ripple_untinted_color);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700178 mFalsingManager = FalsingManager.getInstance(context);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200179 }
180
181 @Override
182 protected void onFinishInflate() {
183 super.onFinishInflate();
184 mBackgroundNormal = (NotificationBackgroundView) findViewById(R.id.backgroundNormal);
Selim Cinek33223572016-02-19 19:32:22 -0800185 mFakeShadow = (FakeShadowView) findViewById(R.id.fake_shadow);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200186 mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
Selim Cinek697178b2014-07-02 19:40:30 +0200187 mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg);
188 mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
Adrian Roosbcbb75a2014-05-27 16:38:11 +0200189 updateBackground();
Selim Cinek697178b2014-07-02 19:40:30 +0200190 updateBackgroundTint();
Selim Cinekd35c2792016-01-21 13:20:57 -0800191 updateOutlineAlpha();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 }
193
Jorim Jaggi251957d2014-04-09 04:24:09 +0200194 private final Runnable mTapTimeoutRunnable = new Runnable() {
195 @Override
196 public void run() {
Selim Cineka32ab602014-06-11 15:06:01 +0200197 makeInactive(true /* animate */);
Jorim Jaggi251957d2014-04-09 04:24:09 +0200198 }
199 };
200
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700201 @Override
Selim Cinek6183d122016-01-14 18:48:41 -0800202 public boolean onInterceptTouchEvent(MotionEvent ev) {
203 if (mDimmed && !mActivated
204 && ev.getActionMasked() == MotionEvent.ACTION_DOWN && disallowSingleClick(ev)) {
205 return true;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200206 }
Selim Cinek6183d122016-01-14 18:48:41 -0800207 return super.onInterceptTouchEvent(ev);
208 }
209
210 protected boolean disallowSingleClick(MotionEvent ev) {
211 return false;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200212 }
213
Mady Mellorf0625802016-02-11 18:03:48 -0800214 protected boolean handleSlideBack() {
215 return false;
216 }
217
Selim Cinek697178b2014-07-02 19:40:30 +0200218 @Override
Selim Cinek570981d2015-12-01 11:37:01 -0800219 public boolean onTouchEvent(MotionEvent event) {
220 boolean result;
Selim Cinek6183d122016-01-14 18:48:41 -0800221 if (mDimmed) {
222 boolean wasActivated = mActivated;
Selim Cinek570981d2015-12-01 11:37:01 -0800223 result = handleTouchEventDimmed(event);
Selim Cinek6183d122016-01-14 18:48:41 -0800224 if (wasActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
225 mFalsingManager.onNotificationDoubleTap();
226 removeCallbacks(mTapTimeoutRunnable);
227 }
Selim Cinek570981d2015-12-01 11:37:01 -0800228 } else {
229 result = super.onTouchEvent(event);
230 }
Selim Cinek570981d2015-12-01 11:37:01 -0800231 return result;
232 }
233
234 @Override
Selim Cinek697178b2014-07-02 19:40:30 +0200235 public void drawableHotspotChanged(float x, float y) {
236 if (!mDimmed){
237 mBackgroundNormal.drawableHotspotChanged(x, y);
238 }
239 }
240
Selim Cinekb2da91b2014-09-02 17:35:20 +0200241 @Override
242 protected void drawableStateChanged() {
243 super.drawableStateChanged();
244 if (mDimmed) {
245 mBackgroundDimmed.setState(getDrawableState());
246 } else {
247 mBackgroundNormal.setState(getDrawableState());
248 }
249 }
250
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200251 private boolean handleTouchEventDimmed(MotionEvent event) {
Jorim Jaggi251957d2014-04-09 04:24:09 +0200252 int action = event.getActionMasked();
Jorim Jaggi251957d2014-04-09 04:24:09 +0200253 switch (action) {
254 case MotionEvent.ACTION_DOWN:
255 mDownX = event.getX();
256 mDownY = event.getY();
Selim Cinek570981d2015-12-01 11:37:01 -0800257 mTrackTouch = true;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200258 if (mDownY > getActualHeight()) {
Selim Cinek570981d2015-12-01 11:37:01 -0800259 mTrackTouch = false;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200260 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200261 break;
262 case MotionEvent.ACTION_MOVE:
263 if (!isWithinTouchSlop(event)) {
Selim Cineka32ab602014-06-11 15:06:01 +0200264 makeInactive(true /* animate */);
Selim Cinek570981d2015-12-01 11:37:01 -0800265 mTrackTouch = false;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200266 }
267 break;
268 case MotionEvent.ACTION_UP:
269 if (isWithinTouchSlop(event)) {
Mady Mellorf0625802016-02-11 18:03:48 -0800270 if (handleSlideBack()) {
271 return true;
272 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200273 if (!mActivated) {
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200274 makeActive();
Jorim Jaggi251957d2014-04-09 04:24:09 +0200275 postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
276 } else {
Selim Cinek570981d2015-12-01 11:37:01 -0800277 if (!performClick()) {
278 return false;
Selim Cineka32ab602014-06-11 15:06:01 +0200279 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200280 }
281 } else {
Selim Cineka32ab602014-06-11 15:06:01 +0200282 makeInactive(true /* animate */);
Selim Cinek570981d2015-12-01 11:37:01 -0800283 mTrackTouch = false;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200284 }
285 break;
286 case MotionEvent.ACTION_CANCEL:
Selim Cineka32ab602014-06-11 15:06:01 +0200287 makeInactive(true /* animate */);
Selim Cinek570981d2015-12-01 11:37:01 -0800288 mTrackTouch = false;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200289 break;
290 default:
291 break;
292 }
Selim Cinek570981d2015-12-01 11:37:01 -0800293 return mTrackTouch;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200294 }
295
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200296 private void makeActive() {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700297 mFalsingManager.onNotificationActive();
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200298 startActivateAnimation(false /* reverse */);
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200299 mActivated = true;
Jorim Jaggiecbab362014-04-23 16:13:15 +0200300 if (mOnActivatedListener != null) {
301 mOnActivatedListener.onActivated(this);
302 }
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200303 }
304
Selim Cinekd35c2792016-01-21 13:20:57 -0800305 private void startActivateAnimation(final boolean reverse) {
Selim Cinekf4d7fc32014-09-26 17:15:34 +0200306 if (!isAttachedToWindow()) {
307 return;
308 }
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200309 int widthHalf = mBackgroundNormal.getWidth()/2;
310 int heightHalf = mBackgroundNormal.getActualHeight()/2;
311 float radius = (float) Math.sqrt(widthHalf*widthHalf + heightHalf*heightHalf);
Selim Cinek6aaf2172014-08-25 19:29:49 +0200312 Animator animator;
313 if (reverse) {
314 animator = ViewAnimationUtils.createCircularReveal(mBackgroundNormal,
315 widthHalf, heightHalf, radius, 0);
316 } else {
317 animator = ViewAnimationUtils.createCircularReveal(mBackgroundNormal,
318 widthHalf, heightHalf, 0, radius);
319 }
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200320 mBackgroundNormal.setVisibility(View.VISIBLE);
321 Interpolator interpolator;
322 Interpolator alphaInterpolator;
323 if (!reverse) {
Selim Cinekc18010f2016-01-20 13:41:30 -0800324 interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
325 alphaInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200326 } else {
327 interpolator = ACTIVATE_INVERSE_INTERPOLATOR;
328 alphaInterpolator = ACTIVATE_INVERSE_ALPHA_INTERPOLATOR;
329 }
330 animator.setInterpolator(interpolator);
331 animator.setDuration(ACTIVATE_ANIMATION_LENGTH);
332 if (reverse) {
333 mBackgroundNormal.setAlpha(1f);
334 animator.addListener(new AnimatorListenerAdapter() {
335 @Override
336 public void onAnimationEnd(Animator animation) {
Selim Cinek23e6acb2014-08-12 16:01:41 +0200337 if (mDimmed) {
338 mBackgroundNormal.setVisibility(View.INVISIBLE);
339 }
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200340 }
341 });
Selim Cinek6aaf2172014-08-25 19:29:49 +0200342 animator.start();
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200343 } else {
344 mBackgroundNormal.setAlpha(0.4f);
345 animator.start();
346 }
347 mBackgroundNormal.animate()
348 .alpha(reverse ? 0f : 1f)
349 .setInterpolator(alphaInterpolator)
Selim Cinekd35c2792016-01-21 13:20:57 -0800350 .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
351 @Override
352 public void onAnimationUpdate(ValueAnimator animation) {
353 float animatedFraction = animation.getAnimatedFraction();
354 if (reverse) {
355 animatedFraction = 1.0f - animatedFraction;
356 }
357 setNormalBackgroundVisibilityAmount(animatedFraction);
358 }
359 })
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200360 .setDuration(ACTIVATE_ANIMATION_LENGTH);
361 }
362
Jorim Jaggi251957d2014-04-09 04:24:09 +0200363 /**
364 * Cancels the hotspot and makes the notification inactive.
365 */
Selim Cineka32ab602014-06-11 15:06:01 +0200366 public void makeInactive(boolean animate) {
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200367 if (mActivated) {
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200368 if (mDimmed) {
Selim Cineka32ab602014-06-11 15:06:01 +0200369 if (animate) {
370 startActivateAnimation(true /* reverse */);
371 } else {
372 mBackgroundNormal.setVisibility(View.INVISIBLE);
373 }
Jorim Jaggibccb9122014-05-08 14:55:48 +0200374 }
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200375 mActivated = false;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200376 }
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200377 if (mOnActivatedListener != null) {
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200378 mOnActivatedListener.onActivationReset(this);
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200379 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200380 removeCallbacks(mTapTimeoutRunnable);
381 }
382
383 private boolean isWithinTouchSlop(MotionEvent event) {
384 return Math.abs(event.getX() - mDownX) < mTouchSlop
385 && Math.abs(event.getY() - mDownY) < mTouchSlop;
386 }
387
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200388 public void setDimmed(boolean dimmed, boolean fade) {
Jorim Jaggi251957d2014-04-09 04:24:09 +0200389 if (mDimmed != dimmed) {
390 mDimmed = dimmed;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200391 if (fade) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100392 fadeDimmedBackground();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200393 } else {
Jorim Jaggi3c3c3fc2014-05-20 23:16:42 +0200394 updateBackground();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200395 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200396 }
397 }
398
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100399 public void setDark(boolean dark, boolean fade, long delay) {
400 super.setDark(dark, fade, delay);
401 if (mDark == dark) {
402 return;
John Spurlockbf370992014-06-17 13:58:31 -0400403 }
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100404 mDark = dark;
Selim Cinek34d93b02015-10-22 12:30:38 -0700405 if (!dark && fade && !shouldHideBackground()) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100406 if (mActivated) {
407 mBackgroundDimmed.setVisibility(View.VISIBLE);
408 mBackgroundNormal.setVisibility(View.VISIBLE);
Selim Cinekc430a5b2014-12-10 16:29:01 +0100409 } else if (mDimmed) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100410 mBackgroundDimmed.setVisibility(View.VISIBLE);
411 mBackgroundNormal.setVisibility(View.INVISIBLE);
Selim Cinekc430a5b2014-12-10 16:29:01 +0100412 } else {
413 mBackgroundDimmed.setVisibility(View.INVISIBLE);
414 mBackgroundNormal.setVisibility(View.VISIBLE);
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100415 }
Selim Cinekc430a5b2014-12-10 16:29:01 +0100416 fadeInFromDark(delay);
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100417 } else {
418 updateBackground();
419 }
Selim Cinekd35c2792016-01-21 13:20:57 -0800420 updateOutlineAlpha();
421 }
422
423 private void updateOutlineAlpha() {
424 if (mDark) {
425 setOutlineAlpha(0f);
426 return;
427 }
428 float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED;
429 alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount);
Selim Cinek277a8aa2016-01-22 12:12:37 -0800430 alpha *= mShadowAlpha;
Selim Cinekd35c2792016-01-21 13:20:57 -0800431 if (mFadeInFromDarkAnimator != null) {
432 alpha *= mFadeInFromDarkAnimator.getAnimatedFraction();
433 }
434 setOutlineAlpha(alpha);
435 }
436
437 public void setNormalBackgroundVisibilityAmount(float normalBackgroundVisibilityAmount) {
438 mNormalBackgroundVisibilityAmount = normalBackgroundVisibilityAmount;
439 updateOutlineAlpha();
440 }
John Spurlockbf370992014-06-17 13:58:31 -0400441
Selim Cinek697178b2014-07-02 19:40:30 +0200442 public void setShowingLegacyBackground(boolean showing) {
443 mShowingLegacyBackground = showing;
444 updateBackgroundTint();
Jorim Jaggi46739852014-04-15 09:58:24 +0200445 }
446
Selim Cinek3d2b94bf2014-07-02 22:12:47 +0200447 @Override
448 public void setBelowSpeedBump(boolean below) {
449 super.setBelowSpeedBump(below);
450 if (below != mIsBelowSpeedBump) {
451 mIsBelowSpeedBump = below;
452 updateBackgroundTint();
453 }
454 }
455
Selim Cinek697178b2014-07-02 19:40:30 +0200456 /**
457 * Sets the tint color of the background
458 */
459 public void setTintColor(int color) {
460 mBgTint = color;
461 updateBackgroundTint();
462 }
463
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700464 protected void updateBackgroundTint() {
Chet Haase5058c382015-01-06 06:29:35 -0800465 int color = getBgColor();
Selim Cinekb2da91b2014-09-02 17:35:20 +0200466 int rippleColor = getRippleColor();
Selim Cinek697178b2014-07-02 19:40:30 +0200467 if (color == mNormalColor) {
468 // We don't need to tint a normal notification
469 color = 0;
470 }
471 mBackgroundDimmed.setTint(color);
472 mBackgroundNormal.setTint(color);
Selim Cinekb2da91b2014-09-02 17:35:20 +0200473 mBackgroundDimmed.setRippleColor(rippleColor);
474 mBackgroundNormal.setRippleColor(rippleColor);
Dan Sandlerfe266a32014-05-15 22:28:06 -0400475 }
476
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100477 /**
Selim Cinekc430a5b2014-12-10 16:29:01 +0100478 * Fades in the background when exiting dark mode.
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100479 */
Selim Cinekc430a5b2014-12-10 16:29:01 +0100480 private void fadeInFromDark(long delay) {
481 final View background = mDimmed ? mBackgroundDimmed : mBackgroundNormal;
482 background.setAlpha(0f);
483 background.setPivotX(mBackgroundDimmed.getWidth() / 2f);
484 background.setPivotY(getActualHeight() / 2f);
485 background.setScaleX(DARK_EXIT_SCALE_START);
486 background.setScaleY(DARK_EXIT_SCALE_START);
487 background.animate()
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100488 .alpha(1f)
489 .scaleX(1f)
490 .scaleY(1f)
491 .setDuration(DARK_ANIMATION_LENGTH)
492 .setStartDelay(delay)
Selim Cinekc18010f2016-01-20 13:41:30 -0800493 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100494 .setListener(new AnimatorListenerAdapter() {
495 @Override
496 public void onAnimationCancel(Animator animation) {
497 // Jump state if we are cancelled
Selim Cinekc430a5b2014-12-10 16:29:01 +0100498 background.setScaleX(1f);
499 background.setScaleY(1f);
500 background.setAlpha(1f);
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100501 }
502 })
Selim Cinekd35c2792016-01-21 13:20:57 -0800503 .setUpdateListener(mBackgroundVisibilityUpdater)
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100504 .start();
Selim Cinekd35c2792016-01-21 13:20:57 -0800505 mFadeInFromDarkAnimator = TimeAnimator.ofFloat(0.0f, 1.0f);
506 mFadeInFromDarkAnimator.setDuration(DARK_ANIMATION_LENGTH);
507 mFadeInFromDarkAnimator.setStartDelay(delay);
508 mFadeInFromDarkAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
509 mFadeInFromDarkAnimator.addListener(mFadeInEndListener);
510 mFadeInFromDarkAnimator.addUpdateListener(mUpdateOutlineListener);
511 mFadeInFromDarkAnimator.start();
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100512 }
513
514 /**
515 * Fades the background when the dimmed state changes.
516 */
517 private void fadeDimmedBackground() {
518 mBackgroundDimmed.animate().cancel();
Selim Cinek59d97232014-10-09 15:54:40 -0700519 mBackgroundNormal.animate().cancel();
Selim Cinek34d93b02015-10-22 12:30:38 -0700520 if (!shouldHideBackground()) {
521 if (mDimmed) {
522 mBackgroundDimmed.setVisibility(View.VISIBLE);
523 } else {
524 mBackgroundNormal.setVisibility(View.VISIBLE);
525 }
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200526 }
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200527 float startAlpha = mDimmed ? 1f : 0;
528 float endAlpha = mDimmed ? 0 : 1f;
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200529 int duration = BACKGROUND_ANIMATION_LENGTH_MS;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200530 // Check whether there is already a background animation running.
531 if (mBackgroundAnimator != null) {
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200532 startAlpha = (Float) mBackgroundAnimator.getAnimatedValue();
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200533 duration = (int) mBackgroundAnimator.getCurrentPlayTime();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200534 mBackgroundAnimator.removeAllListeners();
535 mBackgroundAnimator.cancel();
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200536 if (duration <= 0) {
Jorim Jaggi3c3c3fc2014-05-20 23:16:42 +0200537 updateBackground();
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200538 return;
539 }
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200540 }
541 mBackgroundNormal.setAlpha(startAlpha);
542 mBackgroundAnimator =
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200543 ObjectAnimator.ofFloat(mBackgroundNormal, View.ALPHA, startAlpha, endAlpha);
Selim Cinekc18010f2016-01-20 13:41:30 -0800544 mBackgroundAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200545 mBackgroundAnimator.setDuration(duration);
546 mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
547 @Override
548 public void onAnimationEnd(Animator animation) {
549 if (mDimmed) {
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200550 mBackgroundNormal.setVisibility(View.INVISIBLE);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200551 } else {
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200552 mBackgroundDimmed.setVisibility(View.INVISIBLE);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200553 }
554 mBackgroundAnimator = null;
555 }
556 });
Selim Cinekd35c2792016-01-21 13:20:57 -0800557 mBackgroundAnimator.addUpdateListener(mBackgroundVisibilityUpdater);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200558 mBackgroundAnimator.start();
559 }
560
Selim Cinek34d93b02015-10-22 12:30:38 -0700561 protected void updateBackground() {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100562 cancelFadeAnimations();
Selim Cinek34d93b02015-10-22 12:30:38 -0700563 if (shouldHideBackground()) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100564 mBackgroundDimmed.setVisibility(View.INVISIBLE);
565 mBackgroundNormal.setVisibility(View.INVISIBLE);
566 } else if (mDimmed) {
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200567 mBackgroundDimmed.setVisibility(View.VISIBLE);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200568 mBackgroundNormal.setVisibility(View.INVISIBLE);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200569 } else {
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200570 mBackgroundDimmed.setVisibility(View.INVISIBLE);
571 mBackgroundNormal.setVisibility(View.VISIBLE);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200572 mBackgroundNormal.setAlpha(1f);
Selim Cineka32ab602014-06-11 15:06:01 +0200573 removeCallbacks(mTapTimeoutRunnable);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200574 }
Selim Cinekd35c2792016-01-21 13:20:57 -0800575 setNormalBackgroundVisibilityAmount(
576 mBackgroundNormal.getVisibility() == View.VISIBLE ? 1.0f : 0.0f);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200577 }
578
Selim Cinek34d93b02015-10-22 12:30:38 -0700579 protected boolean shouldHideBackground() {
580 return mDark;
581 }
582
Selim Cinek59d97232014-10-09 15:54:40 -0700583 private void cancelFadeAnimations() {
584 if (mBackgroundAnimator != null) {
585 mBackgroundAnimator.cancel();
586 }
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100587 mBackgroundDimmed.animate().cancel();
Selim Cinek59d97232014-10-09 15:54:40 -0700588 mBackgroundNormal.animate().cancel();
589 }
590
Jorim Jaggibe565df2014-04-28 17:51:23 +0200591 @Override
592 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
593 super.onLayout(changed, left, top, right, bottom);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200594 setPivotX(getWidth() / 2);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200595 }
596
597 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200598 public void setActualHeight(int actualHeight, boolean notifyListeners) {
599 super.setActualHeight(actualHeight, notifyListeners);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200600 setPivotY(actualHeight / 2);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200601 mBackgroundNormal.setActualHeight(actualHeight);
602 mBackgroundDimmed.setActualHeight(actualHeight);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200603 }
604
605 @Override
606 public void setClipTopAmount(int clipTopAmount) {
607 super.setClipTopAmount(clipTopAmount);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200608 mBackgroundNormal.setClipTopAmount(clipTopAmount);
609 mBackgroundDimmed.setClipTopAmount(clipTopAmount);
Jorim Jaggi46739852014-04-15 09:58:24 +0200610 }
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200611
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200612 @Override
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200613 public void performRemoveAnimation(long duration, float translationDirection,
614 Runnable onFinishedRunnable) {
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200615 enableAppearDrawing(true);
616 if (mDrawingAppearAnimation) {
617 startAppearAnimation(false /* isAppearing */, translationDirection,
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200618 0, duration, onFinishedRunnable);
Selim Cinek95ed5922014-08-28 14:30:12 +0200619 } else if (onFinishedRunnable != null) {
620 onFinishedRunnable.run();
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200621 }
622 }
623
624 @Override
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200625 public void performAddAnimation(long delay, long duration) {
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200626 enableAppearDrawing(true);
627 if (mDrawingAppearAnimation) {
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200628 startAppearAnimation(true /* isAppearing */, -1.0f, delay, duration, null);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200629 }
630 }
631
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200632 private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay,
633 long duration, final Runnable onFinishedRunnable) {
Selim Cinek2cd45df2015-06-09 18:00:07 -0700634 cancelAppearAnimation();
Chris Wren310df312014-10-31 14:29:46 -0400635 mAnimationTranslationY = translationDirection * getActualHeight();
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200636 if (mAppearAnimationFraction == -1.0f) {
637 // not initialized yet, we start anew
638 if (isAppearing) {
639 mAppearAnimationFraction = 0.0f;
640 mAppearAnimationTranslation = mAnimationTranslationY;
641 } else {
642 mAppearAnimationFraction = 1.0f;
643 mAppearAnimationTranslation = 0;
644 }
645 }
646
647 float targetValue;
648 if (isAppearing) {
649 mCurrentAppearInterpolator = mSlowOutFastInInterpolator;
Selim Cinekc18010f2016-01-20 13:41:30 -0800650 mCurrentAlphaInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200651 targetValue = 1.0f;
652 } else {
Selim Cinekc18010f2016-01-20 13:41:30 -0800653 mCurrentAppearInterpolator = Interpolators.FAST_OUT_SLOW_IN;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200654 mCurrentAlphaInterpolator = mSlowOutLinearInInterpolator;
655 targetValue = 0.0f;
656 }
657 mAppearAnimator = ValueAnimator.ofFloat(mAppearAnimationFraction,
658 targetValue);
Selim Cinekc18010f2016-01-20 13:41:30 -0800659 mAppearAnimator.setInterpolator(Interpolators.LINEAR);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200660 mAppearAnimator.setDuration(
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200661 (long) (duration * Math.abs(mAppearAnimationFraction - targetValue)));
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200662 mAppearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
663 @Override
664 public void onAnimationUpdate(ValueAnimator animation) {
665 mAppearAnimationFraction = (float) animation.getAnimatedValue();
666 updateAppearAnimationAlpha();
667 updateAppearRect();
668 invalidate();
669 }
670 });
671 if (delay > 0) {
672 // we need to apply the initial state already to avoid drawn frames in the wrong state
673 updateAppearAnimationAlpha();
674 updateAppearRect();
675 mAppearAnimator.setStartDelay(delay);
676 }
677 mAppearAnimator.addListener(new AnimatorListenerAdapter() {
678 private boolean mWasCancelled;
679
680 @Override
681 public void onAnimationEnd(Animator animation) {
682 if (onFinishedRunnable != null) {
683 onFinishedRunnable.run();
684 }
685 if (!mWasCancelled) {
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200686 enableAppearDrawing(false);
687 }
688 }
689
690 @Override
691 public void onAnimationStart(Animator animation) {
692 mWasCancelled = false;
693 }
694
695 @Override
696 public void onAnimationCancel(Animator animation) {
697 mWasCancelled = true;
698 }
699 });
700 mAppearAnimator.start();
701 }
702
Selim Cinek2cd45df2015-06-09 18:00:07 -0700703 private void cancelAppearAnimation() {
704 if (mAppearAnimator != null) {
705 mAppearAnimator.cancel();
Selim Cinekb65c6db2015-12-28 12:48:15 +0100706 mAppearAnimator = null;
Selim Cinek2cd45df2015-06-09 18:00:07 -0700707 }
708 }
709
710 public void cancelAppearDrawing() {
711 cancelAppearAnimation();
712 enableAppearDrawing(false);
713 }
714
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200715 private void updateAppearRect() {
716 float inverseFraction = (1.0f - mAppearAnimationFraction);
717 float translationFraction = mCurrentAppearInterpolator.getInterpolation(inverseFraction);
718 float translateYTotalAmount = translationFraction * mAnimationTranslationY;
719 mAppearAnimationTranslation = translateYTotalAmount;
720
721 // handle width animation
722 float widthFraction = (inverseFraction - (1.0f - HORIZONTAL_ANIMATION_START))
723 / (HORIZONTAL_ANIMATION_START - HORIZONTAL_ANIMATION_END);
724 widthFraction = Math.min(1.0f, Math.max(0.0f, widthFraction));
725 widthFraction = mCurrentAppearInterpolator.getInterpolation(widthFraction);
726 float left = (getWidth() * (0.5f - HORIZONTAL_COLLAPSED_REST_PARTIAL / 2.0f) *
727 widthFraction);
728 float right = getWidth() - left;
729
730 // handle top animation
731 float heightFraction = (inverseFraction - (1.0f - VERTICAL_ANIMATION_START)) /
732 VERTICAL_ANIMATION_START;
733 heightFraction = Math.max(0.0f, heightFraction);
734 heightFraction = mCurrentAppearInterpolator.getInterpolation(heightFraction);
735
736 float top;
737 float bottom;
Chris Wren310df312014-10-31 14:29:46 -0400738 final int actualHeight = getActualHeight();
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200739 if (mAnimationTranslationY > 0.0f) {
Chris Wren310df312014-10-31 14:29:46 -0400740 bottom = actualHeight - heightFraction * mAnimationTranslationY * 0.1f
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200741 - translateYTotalAmount;
742 top = bottom * heightFraction;
743 } else {
Chris Wren310df312014-10-31 14:29:46 -0400744 top = heightFraction * (actualHeight + mAnimationTranslationY) * 0.1f -
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200745 translateYTotalAmount;
Chris Wren310df312014-10-31 14:29:46 -0400746 bottom = actualHeight * (1 - heightFraction) + top * heightFraction;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200747 }
748 mAppearAnimationRect.set(left, top, right, bottom);
749 setOutlineRect(left, top + mAppearAnimationTranslation, right,
750 bottom + mAppearAnimationTranslation);
751 }
752
753 private void updateAppearAnimationAlpha() {
Selim Cinek560e64d2015-06-09 19:58:11 -0700754 float contentAlphaProgress = mAppearAnimationFraction;
755 contentAlphaProgress = contentAlphaProgress / (1.0f - ALPHA_ANIMATION_END);
756 contentAlphaProgress = Math.min(1.0f, contentAlphaProgress);
757 contentAlphaProgress = mCurrentAlphaInterpolator.getInterpolation(contentAlphaProgress);
758 setContentAlpha(contentAlphaProgress);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200759 }
760
Selim Cinek560e64d2015-06-09 19:58:11 -0700761 private void setContentAlpha(float contentAlpha) {
Selim Cinek560e64d2015-06-09 19:58:11 -0700762 View contentView = getContentView();
Jorim Jaggi1f98c622015-07-20 11:43:27 -0700763 if (contentView.hasOverlappingRendering()) {
764 int layerType = contentAlpha == 0.0f || contentAlpha == 1.0f ? LAYER_TYPE_NONE
765 : LAYER_TYPE_HARDWARE;
766 int currentLayerType = contentView.getLayerType();
767 if (currentLayerType != layerType) {
768 contentView.setLayerType(layerType, null);
769 }
Selim Cinek560e64d2015-06-09 19:58:11 -0700770 }
771 contentView.setAlpha(contentAlpha);
772 }
773
774 protected abstract View getContentView();
775
Selim Cinek34d93b02015-10-22 12:30:38 -0700776 public int getBgColor() {
Selim Cinek697178b2014-07-02 19:40:30 +0200777 if (mBgTint != 0) {
778 return mBgTint;
779 } else if (mShowingLegacyBackground) {
780 return mLegacyColor;
Selim Cinek3d2b94bf2014-07-02 22:12:47 +0200781 } else if (mIsBelowSpeedBump) {
782 return mLowPriorityColor;
Selim Cinek697178b2014-07-02 19:40:30 +0200783 } else {
784 return mNormalColor;
785 }
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200786 }
787
Selim Cinekb5605e52015-02-20 18:21:41 +0100788 protected int getRippleColor() {
Selim Cinekb2da91b2014-09-02 17:35:20 +0200789 if (mBgTint != 0) {
790 return mTintedRippleColor;
791 } else if (mShowingLegacyBackground) {
792 return mTintedRippleColor;
793 } else if (mIsBelowSpeedBump) {
794 return mLowPriorityRippleColor;
795 } else {
796 return mNormalRippleColor;
797 }
798 }
799
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200800 /**
801 * When we draw the appear animation, we render the view in a bitmap and render this bitmap
802 * as a shader of a rect. This call creates the Bitmap and switches the drawing mode,
803 * such that the normal drawing of the views does not happen anymore.
804 *
805 * @param enable Should it be enabled.
806 */
807 private void enableAppearDrawing(boolean enable) {
808 if (enable != mDrawingAppearAnimation) {
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200809 mDrawingAppearAnimation = enable;
Selim Cinek560e64d2015-06-09 19:58:11 -0700810 if (!enable) {
811 setContentAlpha(1.0f);
Selim Cinekb65c6db2015-12-28 12:48:15 +0100812 mAppearAnimationFraction = -1;
813 setOutlineRect(null);
Selim Cinek560e64d2015-06-09 19:58:11 -0700814 }
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200815 invalidate();
816 }
817 }
818
819 @Override
820 protected void dispatchDraw(Canvas canvas) {
Selim Cinek560e64d2015-06-09 19:58:11 -0700821 if (mDrawingAppearAnimation) {
822 canvas.save();
823 canvas.translate(0, mAppearAnimationTranslation);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200824 }
Selim Cinek560e64d2015-06-09 19:58:11 -0700825 super.dispatchDraw(canvas);
826 if (mDrawingAppearAnimation) {
827 canvas.restore();
828 }
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200829 }
830
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200831 public void setOnActivatedListener(OnActivatedListener onActivatedListener) {
832 mOnActivatedListener = onActivatedListener;
833 }
834
Christoph Studer22f2ee52014-07-29 22:57:21 +0200835 public void reset() {
836 setTintColor(0);
837 setShowingLegacyBackground(false);
838 setBelowSpeedBump(false);
839 }
840
Selim Cinek34d93b02015-10-22 12:30:38 -0700841 public boolean hasSameBgColor(ActivatableNotificationView otherView) {
842 return getBgColor() == otherView.getBgColor();
843 }
844
Selim Cinek277a8aa2016-01-22 12:12:37 -0800845 @Override
846 public float getShadowAlpha() {
847 return mShadowAlpha;
848 }
849
850 @Override
851 public void setShadowAlpha(float shadowAlpha) {
852 if (shadowAlpha != mShadowAlpha) {
853 mShadowAlpha = shadowAlpha;
854 updateOutlineAlpha();
855 }
856 }
857
Selim Cinek33223572016-02-19 19:32:22 -0800858 @Override
859 public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
860 int outlineTranslation) {
861 mFakeShadow.setFakeShadowTranslationZ(shadowIntensity * (getTranslationZ()
862 + FakeShadowView.SHADOW_SIBLING_TRESHOLD), outlineAlpha, shadowYEnd,
863 outlineTranslation);
864 }
865
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200866 public interface OnActivatedListener {
Selim Cineka32ab602014-06-11 15:06:01 +0200867 void onActivated(ActivatableNotificationView view);
868 void onActivationReset(ActivatableNotificationView view);
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200869 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870}