blob: bc4654823f777b17d3612ce686aa18d7c05d5578 [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 Cinekc3179332016-03-04 14:44:56 -080039import com.android.systemui.statusbar.notification.NotificationUtils;
Selim Cinekd35c2792016-01-21 13:20:57 -080040import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Selim Cinekc3179332016-03-04 14:44:56 -080041import com.android.systemui.statusbar.stack.StackStateAnimator;
Jorim Jaggi46739852014-04-15 09:58:24 +020042
Jorim Jaggife40f7d2014-04-28 15:20:04 +020043/**
44 * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
45 * to implement dimming/activating on Keyguard for the double-tap gesture
46 */
Jorim Jaggibe565df2014-04-28 17:51:23 +020047public abstract class ActivatableNotificationView extends ExpandableOutlineView {
Jorim Jaggi251957d2014-04-09 04:24:09 +020048
Jorim Jaggia8b48e12014-05-19 20:26:46 +020049 private static final long DOUBLETAP_TIMEOUT_MS = 1200;
Jorim Jaggid552d9d2014-05-07 19:41:13 +020050 private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
Jorim Jaggia8b48e12014-05-19 20:26:46 +020051 private static final int ACTIVATE_ANIMATION_LENGTH = 220;
Jorim Jaggi4e857f42014-11-17 19:14:04 +010052 private static final int DARK_ANIMATION_LENGTH = 170;
Jorim Jaggia8b48e12014-05-19 20:26:46 +020053
Selim Cinek8efa6dd2014-05-19 16:27:37 +020054 /**
55 * The amount of width, which is kept in the end when performing a disappear animation (also
56 * the amount from which the horizontal appearing begins)
57 */
58 private static final float HORIZONTAL_COLLAPSED_REST_PARTIAL = 0.05f;
59
60 /**
61 * At which point from [0,1] does the horizontal collapse animation end (or start when
62 * expanding)? 1.0 meaning that it ends immediately and 0.0 that it is continuously animated.
63 */
64 private static final float HORIZONTAL_ANIMATION_END = 0.2f;
65
66 /**
67 * At which point from [0,1] does the alpha animation end (or start when
68 * expanding)? 1.0 meaning that it ends immediately and 0.0 that it is continuously animated.
69 */
70 private static final float ALPHA_ANIMATION_END = 0.0f;
71
72 /**
73 * At which point from [0,1] does the horizontal collapse animation start (or start when
74 * expanding)? 1.0 meaning that it starts immediately and 0.0 that it is animated at all.
75 */
76 private static final float HORIZONTAL_ANIMATION_START = 1.0f;
77
78 /**
79 * At which point from [0,1] does the vertical collapse animation start (or end when
80 * expanding) 1.0 meaning that it starts immediately and 0.0 that it is animated at all.
81 */
82 private static final float VERTICAL_ANIMATION_START = 1.0f;
83
Jorim Jaggi4e857f42014-11-17 19:14:04 +010084 /**
85 * Scale for the background to animate from when exiting dark mode.
86 */
87 private static final float DARK_EXIT_SCALE_START = 0.93f;
88
Jorim Jaggia8b48e12014-05-19 20:26:46 +020089 private static final Interpolator ACTIVATE_INVERSE_INTERPOLATOR
90 = new PathInterpolator(0.6f, 0, 0.5f, 1);
91 private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
92 = new PathInterpolator(0, 0, 0.5f, 1);
Selim Cinekb2da91b2014-09-02 17:35:20 +020093 private final int mTintedRippleColor;
94 private final int mLowPriorityRippleColor;
Selim Cinekb5605e52015-02-20 18:21:41 +010095 protected final int mNormalRippleColor;
Jorim Jaggi251957d2014-04-09 04:24:09 +020096
97 private boolean mDimmed;
John Spurlockbf370992014-06-17 13:58:31 -040098 private boolean mDark;
Jorim Jaggi251957d2014-04-09 04:24:09 +020099
Dan Sandlerfe266a32014-05-15 22:28:06 -0400100 private int mBgTint = 0;
Mady Mellorc7d65b42016-05-04 11:44:57 -0400101 private float mBgAlpha = 1f;
Dan Sandlerfe266a32014-05-15 22:28:06 -0400102
Jorim Jaggi251957d2014-04-09 04:24:09 +0200103 /**
104 * Flag to indicate that the notification has been touched once and the second touch will
105 * click it.
106 */
107 private boolean mActivated;
108
109 private float mDownX;
110 private float mDownY;
111 private final float mTouchSlop;
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200112
113 private OnActivatedListener mOnActivatedListener;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200114
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200115 private final Interpolator mSlowOutFastInInterpolator;
116 private final Interpolator mSlowOutLinearInInterpolator;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200117 private Interpolator mCurrentAppearInterpolator;
118 private Interpolator mCurrentAlphaInterpolator;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200119
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200120 private NotificationBackgroundView mBackgroundNormal;
121 private NotificationBackgroundView mBackgroundDimmed;
122 private ObjectAnimator mBackgroundAnimator;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200123 private RectF mAppearAnimationRect = new RectF();
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200124 private float mAnimationTranslationY;
125 private boolean mDrawingAppearAnimation;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200126 private ValueAnimator mAppearAnimator;
Selim Cinekc3179332016-03-04 14:44:56 -0800127 private ValueAnimator mBackgroundColorAnimator;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200128 private float mAppearAnimationFraction = -1.0f;
129 private float mAppearAnimationTranslation;
Selim Cinek697178b2014-07-02 19:40:30 +0200130 private boolean mShowingLegacyBackground;
131 private final int mLegacyColor;
132 private final int mNormalColor;
Selim Cinek3d2b94bf2014-07-02 22:12:47 +0200133 private final int mLowPriorityColor;
134 private boolean mIsBelowSpeedBump;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700135 private FalsingManager mFalsingManager;
Selim Cinek570981d2015-12-01 11:37:01 -0800136 private boolean mTrackTouch;
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200137
Selim Cinekd35c2792016-01-21 13:20:57 -0800138 private float mNormalBackgroundVisibilityAmount;
139 private ValueAnimator mFadeInFromDarkAnimator;
Selim Cinek7baaa9e2016-07-21 17:21:09 -0700140 private float mDimmedBackgroundFadeInAmount = -1;
Selim Cinekd35c2792016-01-21 13:20:57 -0800141 private ValueAnimator.AnimatorUpdateListener mBackgroundVisibilityUpdater
142 = new ValueAnimator.AnimatorUpdateListener() {
143 @Override
144 public void onAnimationUpdate(ValueAnimator animation) {
145 setNormalBackgroundVisibilityAmount(mBackgroundNormal.getAlpha());
Selim Cinek7baaa9e2016-07-21 17:21:09 -0700146 mDimmedBackgroundFadeInAmount = mBackgroundDimmed.getAlpha();
Selim Cinekd35c2792016-01-21 13:20:57 -0800147 }
148 };
149 private AnimatorListenerAdapter mFadeInEndListener = new AnimatorListenerAdapter() {
150 @Override
151 public void onAnimationEnd(Animator animation) {
152 super.onAnimationEnd(animation);
153 mFadeInFromDarkAnimator = null;
Selim Cinek7baaa9e2016-07-21 17:21:09 -0700154 mDimmedBackgroundFadeInAmount = -1;
Selim Cinek3ac08172016-03-09 10:48:36 -0800155 updateBackground();
Selim Cinekd35c2792016-01-21 13:20:57 -0800156 }
157 };
158 private ValueAnimator.AnimatorUpdateListener mUpdateOutlineListener
159 = new ValueAnimator.AnimatorUpdateListener() {
160 @Override
161 public void onAnimationUpdate(ValueAnimator animation) {
162 updateOutlineAlpha();
163 }
164 };
Selim Cinek277a8aa2016-01-22 12:12:37 -0800165 private float mShadowAlpha = 1.0f;
Selim Cinek33223572016-02-19 19:32:22 -0800166 private FakeShadowView mFakeShadow;
Selim Cinekc3179332016-03-04 14:44:56 -0800167 private int mCurrentBackgroundTint;
168 private int mTargetTint;
169 private int mStartTint;
Selim Cinekd35c2792016-01-21 13:20:57 -0800170
Jorim Jaggife40f7d2014-04-28 15:20:04 +0200171 public ActivatableNotificationView(Context context, AttributeSet attrs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 super(context, attrs);
Jorim Jaggi251957d2014-04-09 04:24:09 +0200173 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200174 mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200175 mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200176 setClipChildren(false);
177 setClipToPadding(false);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700178 mLegacyColor = context.getColor(R.color.notification_legacy_background_color);
179 mNormalColor = context.getColor(R.color.notification_material_background_color);
180 mLowPriorityColor = context.getColor(
Selim Cinek3d2b94bf2014-07-02 22:12:47 +0200181 R.color.notification_material_background_low_priority_color);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700182 mTintedRippleColor = context.getColor(
Selim Cinekb2da91b2014-09-02 17:35:20 +0200183 R.color.notification_ripple_tinted_color);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700184 mLowPriorityRippleColor = context.getColor(
Selim Cinekb2da91b2014-09-02 17:35:20 +0200185 R.color.notification_ripple_color_low_priority);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700186 mNormalRippleColor = context.getColor(
Selim Cinekb2da91b2014-09-02 17:35:20 +0200187 R.color.notification_ripple_untinted_color);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700188 mFalsingManager = FalsingManager.getInstance(context);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200189 }
190
191 @Override
192 protected void onFinishInflate() {
193 super.onFinishInflate();
194 mBackgroundNormal = (NotificationBackgroundView) findViewById(R.id.backgroundNormal);
Selim Cinek33223572016-02-19 19:32:22 -0800195 mFakeShadow = (FakeShadowView) findViewById(R.id.fake_shadow);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200196 mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
Selim Cinek697178b2014-07-02 19:40:30 +0200197 mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg);
198 mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
Adrian Roosbcbb75a2014-05-27 16:38:11 +0200199 updateBackground();
Selim Cinek697178b2014-07-02 19:40:30 +0200200 updateBackgroundTint();
Selim Cinekd35c2792016-01-21 13:20:57 -0800201 updateOutlineAlpha();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 }
203
Jorim Jaggi251957d2014-04-09 04:24:09 +0200204 private final Runnable mTapTimeoutRunnable = new Runnable() {
205 @Override
206 public void run() {
Selim Cineka32ab602014-06-11 15:06:01 +0200207 makeInactive(true /* animate */);
Jorim Jaggi251957d2014-04-09 04:24:09 +0200208 }
209 };
210
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700211 @Override
Selim Cinek6183d122016-01-14 18:48:41 -0800212 public boolean onInterceptTouchEvent(MotionEvent ev) {
213 if (mDimmed && !mActivated
214 && ev.getActionMasked() == MotionEvent.ACTION_DOWN && disallowSingleClick(ev)) {
215 return true;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200216 }
Selim Cinek6183d122016-01-14 18:48:41 -0800217 return super.onInterceptTouchEvent(ev);
218 }
219
220 protected boolean disallowSingleClick(MotionEvent ev) {
221 return false;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200222 }
223
Mady Mellorf0625802016-02-11 18:03:48 -0800224 protected boolean handleSlideBack() {
225 return false;
226 }
227
Selim Cinek697178b2014-07-02 19:40:30 +0200228 @Override
Selim Cinek570981d2015-12-01 11:37:01 -0800229 public boolean onTouchEvent(MotionEvent event) {
230 boolean result;
Selim Cinek6183d122016-01-14 18:48:41 -0800231 if (mDimmed) {
232 boolean wasActivated = mActivated;
Selim Cinek570981d2015-12-01 11:37:01 -0800233 result = handleTouchEventDimmed(event);
Selim Cinek6183d122016-01-14 18:48:41 -0800234 if (wasActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
235 mFalsingManager.onNotificationDoubleTap();
236 removeCallbacks(mTapTimeoutRunnable);
237 }
Selim Cinek570981d2015-12-01 11:37:01 -0800238 } else {
239 result = super.onTouchEvent(event);
240 }
Selim Cinek570981d2015-12-01 11:37:01 -0800241 return result;
242 }
243
244 @Override
Selim Cinek697178b2014-07-02 19:40:30 +0200245 public void drawableHotspotChanged(float x, float y) {
246 if (!mDimmed){
247 mBackgroundNormal.drawableHotspotChanged(x, y);
248 }
249 }
250
Selim Cinekb2da91b2014-09-02 17:35:20 +0200251 @Override
252 protected void drawableStateChanged() {
253 super.drawableStateChanged();
254 if (mDimmed) {
255 mBackgroundDimmed.setState(getDrawableState());
256 } else {
257 mBackgroundNormal.setState(getDrawableState());
258 }
259 }
260
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200261 private boolean handleTouchEventDimmed(MotionEvent event) {
Jorim Jaggi251957d2014-04-09 04:24:09 +0200262 int action = event.getActionMasked();
Jorim Jaggi251957d2014-04-09 04:24:09 +0200263 switch (action) {
264 case MotionEvent.ACTION_DOWN:
265 mDownX = event.getX();
266 mDownY = event.getY();
Selim Cinek570981d2015-12-01 11:37:01 -0800267 mTrackTouch = true;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200268 if (mDownY > getActualHeight()) {
Selim Cinek570981d2015-12-01 11:37:01 -0800269 mTrackTouch = false;
Jorim Jaggibe565df2014-04-28 17:51:23 +0200270 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200271 break;
272 case MotionEvent.ACTION_MOVE:
273 if (!isWithinTouchSlop(event)) {
Selim Cineka32ab602014-06-11 15:06:01 +0200274 makeInactive(true /* animate */);
Selim Cinek570981d2015-12-01 11:37:01 -0800275 mTrackTouch = false;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200276 }
277 break;
278 case MotionEvent.ACTION_UP:
279 if (isWithinTouchSlop(event)) {
Mady Mellorf0625802016-02-11 18:03:48 -0800280 if (handleSlideBack()) {
281 return true;
282 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200283 if (!mActivated) {
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200284 makeActive();
Jorim Jaggi251957d2014-04-09 04:24:09 +0200285 postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
286 } else {
Selim Cinek570981d2015-12-01 11:37:01 -0800287 if (!performClick()) {
288 return false;
Selim Cineka32ab602014-06-11 15:06:01 +0200289 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200290 }
291 } else {
Selim Cineka32ab602014-06-11 15:06:01 +0200292 makeInactive(true /* animate */);
Selim Cinek570981d2015-12-01 11:37:01 -0800293 mTrackTouch = false;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200294 }
295 break;
296 case MotionEvent.ACTION_CANCEL:
Selim Cineka32ab602014-06-11 15:06:01 +0200297 makeInactive(true /* animate */);
Selim Cinek570981d2015-12-01 11:37:01 -0800298 mTrackTouch = false;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200299 break;
300 default:
301 break;
302 }
Selim Cinek570981d2015-12-01 11:37:01 -0800303 return mTrackTouch;
Jorim Jaggi251957d2014-04-09 04:24:09 +0200304 }
305
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200306 private void makeActive() {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700307 mFalsingManager.onNotificationActive();
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200308 startActivateAnimation(false /* reverse */);
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200309 mActivated = true;
Jorim Jaggiecbab362014-04-23 16:13:15 +0200310 if (mOnActivatedListener != null) {
311 mOnActivatedListener.onActivated(this);
312 }
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200313 }
314
Selim Cinekd35c2792016-01-21 13:20:57 -0800315 private void startActivateAnimation(final boolean reverse) {
Selim Cinekf4d7fc32014-09-26 17:15:34 +0200316 if (!isAttachedToWindow()) {
317 return;
318 }
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200319 int widthHalf = mBackgroundNormal.getWidth()/2;
320 int heightHalf = mBackgroundNormal.getActualHeight()/2;
321 float radius = (float) Math.sqrt(widthHalf*widthHalf + heightHalf*heightHalf);
Selim Cinek6aaf2172014-08-25 19:29:49 +0200322 Animator animator;
323 if (reverse) {
324 animator = ViewAnimationUtils.createCircularReveal(mBackgroundNormal,
325 widthHalf, heightHalf, radius, 0);
326 } else {
327 animator = ViewAnimationUtils.createCircularReveal(mBackgroundNormal,
328 widthHalf, heightHalf, 0, radius);
329 }
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200330 mBackgroundNormal.setVisibility(View.VISIBLE);
331 Interpolator interpolator;
332 Interpolator alphaInterpolator;
333 if (!reverse) {
Selim Cinekc18010f2016-01-20 13:41:30 -0800334 interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
335 alphaInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200336 } else {
337 interpolator = ACTIVATE_INVERSE_INTERPOLATOR;
338 alphaInterpolator = ACTIVATE_INVERSE_ALPHA_INTERPOLATOR;
339 }
340 animator.setInterpolator(interpolator);
341 animator.setDuration(ACTIVATE_ANIMATION_LENGTH);
342 if (reverse) {
343 mBackgroundNormal.setAlpha(1f);
344 animator.addListener(new AnimatorListenerAdapter() {
345 @Override
346 public void onAnimationEnd(Animator animation) {
Selim Cinek3ac08172016-03-09 10:48:36 -0800347 updateBackground();
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200348 }
349 });
Selim Cinek6aaf2172014-08-25 19:29:49 +0200350 animator.start();
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200351 } else {
352 mBackgroundNormal.setAlpha(0.4f);
353 animator.start();
354 }
355 mBackgroundNormal.animate()
356 .alpha(reverse ? 0f : 1f)
357 .setInterpolator(alphaInterpolator)
Selim Cinekd35c2792016-01-21 13:20:57 -0800358 .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
359 @Override
360 public void onAnimationUpdate(ValueAnimator animation) {
361 float animatedFraction = animation.getAnimatedFraction();
362 if (reverse) {
363 animatedFraction = 1.0f - animatedFraction;
364 }
365 setNormalBackgroundVisibilityAmount(animatedFraction);
366 }
367 })
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200368 .setDuration(ACTIVATE_ANIMATION_LENGTH);
369 }
370
Jorim Jaggi251957d2014-04-09 04:24:09 +0200371 /**
372 * Cancels the hotspot and makes the notification inactive.
373 */
Selim Cineka32ab602014-06-11 15:06:01 +0200374 public void makeInactive(boolean animate) {
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200375 if (mActivated) {
Selim Cinek3ac08172016-03-09 10:48:36 -0800376 mActivated = false;
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200377 if (mDimmed) {
Selim Cineka32ab602014-06-11 15:06:01 +0200378 if (animate) {
379 startActivateAnimation(true /* reverse */);
380 } else {
Selim Cinek3ac08172016-03-09 10:48:36 -0800381 updateBackground();
Selim Cineka32ab602014-06-11 15:06:01 +0200382 }
Jorim Jaggibccb9122014-05-08 14:55:48 +0200383 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200384 }
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200385 if (mOnActivatedListener != null) {
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200386 mOnActivatedListener.onActivationReset(this);
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200387 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200388 removeCallbacks(mTapTimeoutRunnable);
389 }
390
391 private boolean isWithinTouchSlop(MotionEvent event) {
392 return Math.abs(event.getX() - mDownX) < mTouchSlop
393 && Math.abs(event.getY() - mDownY) < mTouchSlop;
394 }
395
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200396 public void setDimmed(boolean dimmed, boolean fade) {
Jorim Jaggi251957d2014-04-09 04:24:09 +0200397 if (mDimmed != dimmed) {
398 mDimmed = dimmed;
Mady Mellorc7d65b42016-05-04 11:44:57 -0400399 resetBackgroundAlpha();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200400 if (fade) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100401 fadeDimmedBackground();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200402 } else {
Jorim Jaggi3c3c3fc2014-05-20 23:16:42 +0200403 updateBackground();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200404 }
Jorim Jaggi251957d2014-04-09 04:24:09 +0200405 }
406 }
407
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100408 public void setDark(boolean dark, boolean fade, long delay) {
409 super.setDark(dark, fade, delay);
410 if (mDark == dark) {
411 return;
John Spurlockbf370992014-06-17 13:58:31 -0400412 }
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100413 mDark = dark;
Selim Cinek3ac08172016-03-09 10:48:36 -0800414 updateBackground();
Selim Cinek34d93b02015-10-22 12:30:38 -0700415 if (!dark && fade && !shouldHideBackground()) {
Selim Cinekc430a5b2014-12-10 16:29:01 +0100416 fadeInFromDark(delay);
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100417 }
Selim Cinekd35c2792016-01-21 13:20:57 -0800418 updateOutlineAlpha();
419 }
420
421 private void updateOutlineAlpha() {
422 if (mDark) {
423 setOutlineAlpha(0f);
424 return;
425 }
426 float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED;
427 alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount);
Selim Cinek277a8aa2016-01-22 12:12:37 -0800428 alpha *= mShadowAlpha;
Selim Cinekd35c2792016-01-21 13:20:57 -0800429 if (mFadeInFromDarkAnimator != null) {
430 alpha *= mFadeInFromDarkAnimator.getAnimatedFraction();
431 }
432 setOutlineAlpha(alpha);
433 }
434
435 public void setNormalBackgroundVisibilityAmount(float normalBackgroundVisibilityAmount) {
436 mNormalBackgroundVisibilityAmount = normalBackgroundVisibilityAmount;
437 updateOutlineAlpha();
438 }
John Spurlockbf370992014-06-17 13:58:31 -0400439
Selim Cinek697178b2014-07-02 19:40:30 +0200440 public void setShowingLegacyBackground(boolean showing) {
441 mShowingLegacyBackground = showing;
442 updateBackgroundTint();
Jorim Jaggi46739852014-04-15 09:58:24 +0200443 }
444
Selim Cinek3d2b94bf2014-07-02 22:12:47 +0200445 @Override
446 public void setBelowSpeedBump(boolean below) {
447 super.setBelowSpeedBump(below);
448 if (below != mIsBelowSpeedBump) {
449 mIsBelowSpeedBump = below;
450 updateBackgroundTint();
451 }
452 }
453
Selim Cinek697178b2014-07-02 19:40:30 +0200454 /**
455 * Sets the tint color of the background
456 */
457 public void setTintColor(int color) {
Selim Cinekc3179332016-03-04 14:44:56 -0800458 setTintColor(color, false);
459 }
460
461 /**
462 * Sets the tint color of the background
463 */
464 public void setTintColor(int color, boolean animated) {
Selim Cinek697178b2014-07-02 19:40:30 +0200465 mBgTint = color;
Selim Cinekc3179332016-03-04 14:44:56 -0800466 updateBackgroundTint(animated);
Selim Cinek697178b2014-07-02 19:40:30 +0200467 }
468
Selim Cineka6c6bfb2015-10-29 16:27:08 -0700469 protected void updateBackgroundTint() {
Selim Cinekc3179332016-03-04 14:44:56 -0800470 updateBackgroundTint(false /* animated */);
471 }
472
473 private void updateBackgroundTint(boolean animated) {
474 if (mBackgroundColorAnimator != null) {
475 mBackgroundColorAnimator.cancel();
476 }
Selim Cinekb2da91b2014-09-02 17:35:20 +0200477 int rippleColor = getRippleColor();
Selim Cinekc3179332016-03-04 14:44:56 -0800478 mBackgroundDimmed.setRippleColor(rippleColor);
479 mBackgroundNormal.setRippleColor(rippleColor);
480 int color = calculateBgColor();
481 if (!animated) {
482 setBackgroundTintColor(color);
483 } else if (color != mCurrentBackgroundTint) {
484 mStartTint = mCurrentBackgroundTint;
485 mTargetTint = color;
486 mBackgroundColorAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
487 mBackgroundColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
488 @Override
489 public void onAnimationUpdate(ValueAnimator animation) {
490 int newColor = NotificationUtils.interpolateColors(mStartTint, mTargetTint,
491 animation.getAnimatedFraction());
492 setBackgroundTintColor(newColor);
493 }
494 });
495 mBackgroundColorAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
496 mBackgroundColorAnimator.setInterpolator(Interpolators.LINEAR);
497 mBackgroundColorAnimator.addListener(new AnimatorListenerAdapter() {
498 @Override
499 public void onAnimationEnd(Animator animation) {
500 mBackgroundColorAnimator = null;
501 }
502 });
503 mBackgroundColorAnimator.start();
504 }
505 }
506
507 private void setBackgroundTintColor(int color) {
508 mCurrentBackgroundTint = color;
Selim Cinek697178b2014-07-02 19:40:30 +0200509 if (color == mNormalColor) {
510 // We don't need to tint a normal notification
511 color = 0;
512 }
513 mBackgroundDimmed.setTint(color);
514 mBackgroundNormal.setTint(color);
Dan Sandlerfe266a32014-05-15 22:28:06 -0400515 }
516
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100517 /**
Selim Cinekc430a5b2014-12-10 16:29:01 +0100518 * Fades in the background when exiting dark mode.
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100519 */
Selim Cinekc430a5b2014-12-10 16:29:01 +0100520 private void fadeInFromDark(long delay) {
521 final View background = mDimmed ? mBackgroundDimmed : mBackgroundNormal;
522 background.setAlpha(0f);
Selim Cinek3ac08172016-03-09 10:48:36 -0800523 mBackgroundVisibilityUpdater.onAnimationUpdate(null);
Selim Cinekc430a5b2014-12-10 16:29:01 +0100524 background.setPivotX(mBackgroundDimmed.getWidth() / 2f);
525 background.setPivotY(getActualHeight() / 2f);
526 background.setScaleX(DARK_EXIT_SCALE_START);
527 background.setScaleY(DARK_EXIT_SCALE_START);
528 background.animate()
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100529 .alpha(1f)
530 .scaleX(1f)
531 .scaleY(1f)
532 .setDuration(DARK_ANIMATION_LENGTH)
533 .setStartDelay(delay)
Selim Cinekc18010f2016-01-20 13:41:30 -0800534 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100535 .setListener(new AnimatorListenerAdapter() {
536 @Override
537 public void onAnimationCancel(Animator animation) {
538 // Jump state if we are cancelled
Selim Cinekc430a5b2014-12-10 16:29:01 +0100539 background.setScaleX(1f);
540 background.setScaleY(1f);
541 background.setAlpha(1f);
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100542 }
543 })
Selim Cinekd35c2792016-01-21 13:20:57 -0800544 .setUpdateListener(mBackgroundVisibilityUpdater)
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100545 .start();
Selim Cinekd35c2792016-01-21 13:20:57 -0800546 mFadeInFromDarkAnimator = TimeAnimator.ofFloat(0.0f, 1.0f);
547 mFadeInFromDarkAnimator.setDuration(DARK_ANIMATION_LENGTH);
548 mFadeInFromDarkAnimator.setStartDelay(delay);
549 mFadeInFromDarkAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
550 mFadeInFromDarkAnimator.addListener(mFadeInEndListener);
551 mFadeInFromDarkAnimator.addUpdateListener(mUpdateOutlineListener);
552 mFadeInFromDarkAnimator.start();
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100553 }
554
555 /**
556 * Fades the background when the dimmed state changes.
557 */
558 private void fadeDimmedBackground() {
559 mBackgroundDimmed.animate().cancel();
Selim Cinek59d97232014-10-09 15:54:40 -0700560 mBackgroundNormal.animate().cancel();
Selim Cinek3ac08172016-03-09 10:48:36 -0800561 if (mActivated) {
562 updateBackground();
563 return;
564 }
Selim Cinek34d93b02015-10-22 12:30:38 -0700565 if (!shouldHideBackground()) {
566 if (mDimmed) {
567 mBackgroundDimmed.setVisibility(View.VISIBLE);
568 } else {
569 mBackgroundNormal.setVisibility(View.VISIBLE);
570 }
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200571 }
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200572 float startAlpha = mDimmed ? 1f : 0;
573 float endAlpha = mDimmed ? 0 : 1f;
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200574 int duration = BACKGROUND_ANIMATION_LENGTH_MS;
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200575 // Check whether there is already a background animation running.
576 if (mBackgroundAnimator != null) {
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200577 startAlpha = (Float) mBackgroundAnimator.getAnimatedValue();
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200578 duration = (int) mBackgroundAnimator.getCurrentPlayTime();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200579 mBackgroundAnimator.removeAllListeners();
580 mBackgroundAnimator.cancel();
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200581 if (duration <= 0) {
Jorim Jaggi3c3c3fc2014-05-20 23:16:42 +0200582 updateBackground();
Jorim Jaggi98fb09c2014-05-01 22:40:56 +0200583 return;
584 }
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200585 }
586 mBackgroundNormal.setAlpha(startAlpha);
587 mBackgroundAnimator =
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200588 ObjectAnimator.ofFloat(mBackgroundNormal, View.ALPHA, startAlpha, endAlpha);
Selim Cinekc18010f2016-01-20 13:41:30 -0800589 mBackgroundAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200590 mBackgroundAnimator.setDuration(duration);
591 mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
592 @Override
593 public void onAnimationEnd(Animator animation) {
Selim Cinek3ac08172016-03-09 10:48:36 -0800594 updateBackground();
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200595 mBackgroundAnimator = null;
Selim Cinek3334a182016-09-22 16:19:42 -0700596 if (mFadeInFromDarkAnimator == null) {
597 mDimmedBackgroundFadeInAmount = -1;
598 }
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200599 }
600 });
Selim Cinekd35c2792016-01-21 13:20:57 -0800601 mBackgroundAnimator.addUpdateListener(mBackgroundVisibilityUpdater);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200602 mBackgroundAnimator.start();
603 }
604
Mady Mellorc7d65b42016-05-04 11:44:57 -0400605 protected void updateBackgroundAlpha(float transformationAmount) {
Selim Cinek7baaa9e2016-07-21 17:21:09 -0700606 mBgAlpha = isChildInGroup() && mDimmed ? transformationAmount : 1f;
607 if (mDimmedBackgroundFadeInAmount != -1) {
608 mBgAlpha *= mDimmedBackgroundFadeInAmount;
609 }
Mady Mellorc7d65b42016-05-04 11:44:57 -0400610 mBackgroundDimmed.setAlpha(mBgAlpha);
611 }
612
613 protected void resetBackgroundAlpha() {
614 updateBackgroundAlpha(0f /* transformationAmount */);
615 }
616
Selim Cinek34d93b02015-10-22 12:30:38 -0700617 protected void updateBackground() {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100618 cancelFadeAnimations();
Selim Cinek34d93b02015-10-22 12:30:38 -0700619 if (shouldHideBackground()) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100620 mBackgroundDimmed.setVisibility(View.INVISIBLE);
621 mBackgroundNormal.setVisibility(View.INVISIBLE);
622 } else if (mDimmed) {
Mady Mellorc7d65b42016-05-04 11:44:57 -0400623 // When groups are animating to the expanded state from the lockscreen, show the
624 // normal background instead of the dimmed background
625 final boolean dontShowDimmed = isGroupExpansionChanging() && isChildInGroup();
626 mBackgroundDimmed.setVisibility(dontShowDimmed ? View.INVISIBLE : View.VISIBLE);
627 mBackgroundNormal.setVisibility((mActivated || dontShowDimmed)
628 ? View.VISIBLE
629 : View.INVISIBLE);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200630 } else {
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200631 mBackgroundDimmed.setVisibility(View.INVISIBLE);
632 mBackgroundNormal.setVisibility(View.VISIBLE);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200633 mBackgroundNormal.setAlpha(1f);
Selim Cineka32ab602014-06-11 15:06:01 +0200634 removeCallbacks(mTapTimeoutRunnable);
Selim Cinek3ac08172016-03-09 10:48:36 -0800635 // make in inactive to avoid it sticking around active
636 makeInactive(false /* animate */);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200637 }
Selim Cinekd35c2792016-01-21 13:20:57 -0800638 setNormalBackgroundVisibilityAmount(
639 mBackgroundNormal.getVisibility() == View.VISIBLE ? 1.0f : 0.0f);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200640 }
641
Selim Cinek34d93b02015-10-22 12:30:38 -0700642 protected boolean shouldHideBackground() {
643 return mDark;
644 }
645
Selim Cinek59d97232014-10-09 15:54:40 -0700646 private void cancelFadeAnimations() {
647 if (mBackgroundAnimator != null) {
648 mBackgroundAnimator.cancel();
649 }
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100650 mBackgroundDimmed.animate().cancel();
Selim Cinek59d97232014-10-09 15:54:40 -0700651 mBackgroundNormal.animate().cancel();
652 }
653
Jorim Jaggibe565df2014-04-28 17:51:23 +0200654 @Override
655 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
656 super.onLayout(changed, left, top, right, bottom);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200657 setPivotX(getWidth() / 2);
Jorim Jaggibe565df2014-04-28 17:51:23 +0200658 }
659
660 @Override
Jorim Jaggid552d9d2014-05-07 19:41:13 +0200661 public void setActualHeight(int actualHeight, boolean notifyListeners) {
662 super.setActualHeight(actualHeight, notifyListeners);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200663 setPivotY(actualHeight / 2);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200664 mBackgroundNormal.setActualHeight(actualHeight);
665 mBackgroundDimmed.setActualHeight(actualHeight);
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200666 }
667
668 @Override
669 public void setClipTopAmount(int clipTopAmount) {
670 super.setClipTopAmount(clipTopAmount);
Jorim Jaggia8b48e12014-05-19 20:26:46 +0200671 mBackgroundNormal.setClipTopAmount(clipTopAmount);
672 mBackgroundDimmed.setClipTopAmount(clipTopAmount);
Jorim Jaggi46739852014-04-15 09:58:24 +0200673 }
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200674
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200675 @Override
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200676 public void performRemoveAnimation(long duration, float translationDirection,
677 Runnable onFinishedRunnable) {
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200678 enableAppearDrawing(true);
679 if (mDrawingAppearAnimation) {
680 startAppearAnimation(false /* isAppearing */, translationDirection,
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200681 0, duration, onFinishedRunnable);
Selim Cinek95ed5922014-08-28 14:30:12 +0200682 } else if (onFinishedRunnable != null) {
683 onFinishedRunnable.run();
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200684 }
685 }
686
687 @Override
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200688 public void performAddAnimation(long delay, long duration) {
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200689 enableAppearDrawing(true);
690 if (mDrawingAppearAnimation) {
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200691 startAppearAnimation(true /* isAppearing */, -1.0f, delay, duration, null);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200692 }
693 }
694
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200695 private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay,
696 long duration, final Runnable onFinishedRunnable) {
Selim Cinek2cd45df2015-06-09 18:00:07 -0700697 cancelAppearAnimation();
Chris Wren310df312014-10-31 14:29:46 -0400698 mAnimationTranslationY = translationDirection * getActualHeight();
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200699 if (mAppearAnimationFraction == -1.0f) {
700 // not initialized yet, we start anew
701 if (isAppearing) {
702 mAppearAnimationFraction = 0.0f;
703 mAppearAnimationTranslation = mAnimationTranslationY;
704 } else {
705 mAppearAnimationFraction = 1.0f;
706 mAppearAnimationTranslation = 0;
707 }
708 }
709
710 float targetValue;
711 if (isAppearing) {
712 mCurrentAppearInterpolator = mSlowOutFastInInterpolator;
Selim Cinekc18010f2016-01-20 13:41:30 -0800713 mCurrentAlphaInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200714 targetValue = 1.0f;
715 } else {
Selim Cinekc18010f2016-01-20 13:41:30 -0800716 mCurrentAppearInterpolator = Interpolators.FAST_OUT_SLOW_IN;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200717 mCurrentAlphaInterpolator = mSlowOutLinearInInterpolator;
718 targetValue = 0.0f;
719 }
720 mAppearAnimator = ValueAnimator.ofFloat(mAppearAnimationFraction,
721 targetValue);
Selim Cinekc18010f2016-01-20 13:41:30 -0800722 mAppearAnimator.setInterpolator(Interpolators.LINEAR);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200723 mAppearAnimator.setDuration(
Jorim Jaggi60d07c52014-07-31 15:38:21 +0200724 (long) (duration * Math.abs(mAppearAnimationFraction - targetValue)));
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200725 mAppearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
726 @Override
727 public void onAnimationUpdate(ValueAnimator animation) {
728 mAppearAnimationFraction = (float) animation.getAnimatedValue();
729 updateAppearAnimationAlpha();
730 updateAppearRect();
731 invalidate();
732 }
733 });
734 if (delay > 0) {
735 // we need to apply the initial state already to avoid drawn frames in the wrong state
736 updateAppearAnimationAlpha();
737 updateAppearRect();
738 mAppearAnimator.setStartDelay(delay);
739 }
740 mAppearAnimator.addListener(new AnimatorListenerAdapter() {
741 private boolean mWasCancelled;
742
743 @Override
744 public void onAnimationEnd(Animator animation) {
745 if (onFinishedRunnable != null) {
746 onFinishedRunnable.run();
747 }
748 if (!mWasCancelled) {
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200749 enableAppearDrawing(false);
Selim Cinekaa3901a2016-08-05 11:04:37 -0700750 onAppearAnimationFinished(isAppearing);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200751 }
752 }
753
754 @Override
755 public void onAnimationStart(Animator animation) {
756 mWasCancelled = false;
757 }
758
759 @Override
760 public void onAnimationCancel(Animator animation) {
761 mWasCancelled = true;
762 }
763 });
764 mAppearAnimator.start();
765 }
766
Selim Cinekaa3901a2016-08-05 11:04:37 -0700767 protected void onAppearAnimationFinished(boolean wasAppearing) {
768 }
769
Selim Cinek2cd45df2015-06-09 18:00:07 -0700770 private void cancelAppearAnimation() {
771 if (mAppearAnimator != null) {
772 mAppearAnimator.cancel();
Selim Cinekb65c6db2015-12-28 12:48:15 +0100773 mAppearAnimator = null;
Selim Cinek2cd45df2015-06-09 18:00:07 -0700774 }
775 }
776
777 public void cancelAppearDrawing() {
778 cancelAppearAnimation();
779 enableAppearDrawing(false);
780 }
781
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200782 private void updateAppearRect() {
783 float inverseFraction = (1.0f - mAppearAnimationFraction);
784 float translationFraction = mCurrentAppearInterpolator.getInterpolation(inverseFraction);
785 float translateYTotalAmount = translationFraction * mAnimationTranslationY;
786 mAppearAnimationTranslation = translateYTotalAmount;
787
788 // handle width animation
789 float widthFraction = (inverseFraction - (1.0f - HORIZONTAL_ANIMATION_START))
790 / (HORIZONTAL_ANIMATION_START - HORIZONTAL_ANIMATION_END);
791 widthFraction = Math.min(1.0f, Math.max(0.0f, widthFraction));
792 widthFraction = mCurrentAppearInterpolator.getInterpolation(widthFraction);
793 float left = (getWidth() * (0.5f - HORIZONTAL_COLLAPSED_REST_PARTIAL / 2.0f) *
794 widthFraction);
795 float right = getWidth() - left;
796
797 // handle top animation
798 float heightFraction = (inverseFraction - (1.0f - VERTICAL_ANIMATION_START)) /
799 VERTICAL_ANIMATION_START;
800 heightFraction = Math.max(0.0f, heightFraction);
801 heightFraction = mCurrentAppearInterpolator.getInterpolation(heightFraction);
802
803 float top;
804 float bottom;
Chris Wren310df312014-10-31 14:29:46 -0400805 final int actualHeight = getActualHeight();
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200806 if (mAnimationTranslationY > 0.0f) {
Chris Wren310df312014-10-31 14:29:46 -0400807 bottom = actualHeight - heightFraction * mAnimationTranslationY * 0.1f
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200808 - translateYTotalAmount;
809 top = bottom * heightFraction;
810 } else {
Chris Wren310df312014-10-31 14:29:46 -0400811 top = heightFraction * (actualHeight + mAnimationTranslationY) * 0.1f -
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200812 translateYTotalAmount;
Chris Wren310df312014-10-31 14:29:46 -0400813 bottom = actualHeight * (1 - heightFraction) + top * heightFraction;
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200814 }
815 mAppearAnimationRect.set(left, top, right, bottom);
816 setOutlineRect(left, top + mAppearAnimationTranslation, right,
817 bottom + mAppearAnimationTranslation);
818 }
819
820 private void updateAppearAnimationAlpha() {
Selim Cinek560e64d2015-06-09 19:58:11 -0700821 float contentAlphaProgress = mAppearAnimationFraction;
822 contentAlphaProgress = contentAlphaProgress / (1.0f - ALPHA_ANIMATION_END);
823 contentAlphaProgress = Math.min(1.0f, contentAlphaProgress);
824 contentAlphaProgress = mCurrentAlphaInterpolator.getInterpolation(contentAlphaProgress);
825 setContentAlpha(contentAlphaProgress);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200826 }
827
Selim Cinek560e64d2015-06-09 19:58:11 -0700828 private void setContentAlpha(float contentAlpha) {
Selim Cinek560e64d2015-06-09 19:58:11 -0700829 View contentView = getContentView();
Jorim Jaggi1f98c622015-07-20 11:43:27 -0700830 if (contentView.hasOverlappingRendering()) {
831 int layerType = contentAlpha == 0.0f || contentAlpha == 1.0f ? LAYER_TYPE_NONE
832 : LAYER_TYPE_HARDWARE;
833 int currentLayerType = contentView.getLayerType();
834 if (currentLayerType != layerType) {
835 contentView.setLayerType(layerType, null);
836 }
Selim Cinek560e64d2015-06-09 19:58:11 -0700837 }
838 contentView.setAlpha(contentAlpha);
839 }
840
841 protected abstract View getContentView();
842
Selim Cinekc3179332016-03-04 14:44:56 -0800843 public int calculateBgColor() {
844 return calculateBgColor(true /* withTint */);
845 }
846
847 private int calculateBgColor(boolean withTint) {
848 if (withTint && mBgTint != 0) {
Selim Cinek697178b2014-07-02 19:40:30 +0200849 return mBgTint;
850 } else if (mShowingLegacyBackground) {
851 return mLegacyColor;
Selim Cinek3d2b94bf2014-07-02 22:12:47 +0200852 } else if (mIsBelowSpeedBump) {
853 return mLowPriorityColor;
Selim Cinek697178b2014-07-02 19:40:30 +0200854 } else {
855 return mNormalColor;
856 }
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200857 }
858
Selim Cinekb5605e52015-02-20 18:21:41 +0100859 protected int getRippleColor() {
Selim Cinekb2da91b2014-09-02 17:35:20 +0200860 if (mBgTint != 0) {
861 return mTintedRippleColor;
862 } else if (mShowingLegacyBackground) {
863 return mTintedRippleColor;
864 } else if (mIsBelowSpeedBump) {
865 return mLowPriorityRippleColor;
866 } else {
867 return mNormalRippleColor;
868 }
869 }
870
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200871 /**
872 * When we draw the appear animation, we render the view in a bitmap and render this bitmap
873 * as a shader of a rect. This call creates the Bitmap and switches the drawing mode,
874 * such that the normal drawing of the views does not happen anymore.
875 *
876 * @param enable Should it be enabled.
877 */
878 private void enableAppearDrawing(boolean enable) {
879 if (enable != mDrawingAppearAnimation) {
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200880 mDrawingAppearAnimation = enable;
Selim Cinek560e64d2015-06-09 19:58:11 -0700881 if (!enable) {
882 setContentAlpha(1.0f);
Selim Cinekb65c6db2015-12-28 12:48:15 +0100883 mAppearAnimationFraction = -1;
884 setOutlineRect(null);
Selim Cinek560e64d2015-06-09 19:58:11 -0700885 }
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200886 invalidate();
887 }
888 }
889
890 @Override
891 protected void dispatchDraw(Canvas canvas) {
Selim Cinek560e64d2015-06-09 19:58:11 -0700892 if (mDrawingAppearAnimation) {
893 canvas.save();
894 canvas.translate(0, mAppearAnimationTranslation);
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200895 }
Selim Cinek560e64d2015-06-09 19:58:11 -0700896 super.dispatchDraw(canvas);
897 if (mDrawingAppearAnimation) {
898 canvas.restore();
899 }
Selim Cinek8efa6dd2014-05-19 16:27:37 +0200900 }
901
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200902 public void setOnActivatedListener(OnActivatedListener onActivatedListener) {
903 mOnActivatedListener = onActivatedListener;
904 }
905
Christoph Studer22f2ee52014-07-29 22:57:21 +0200906 public void reset() {
907 setTintColor(0);
Mady Mellorc7d65b42016-05-04 11:44:57 -0400908 resetBackgroundAlpha();
Christoph Studer22f2ee52014-07-29 22:57:21 +0200909 setShowingLegacyBackground(false);
910 setBelowSpeedBump(false);
911 }
912
Selim Cinek34d93b02015-10-22 12:30:38 -0700913 public boolean hasSameBgColor(ActivatableNotificationView otherView) {
Selim Cinekc3179332016-03-04 14:44:56 -0800914 return calculateBgColor() == otherView.calculateBgColor();
Selim Cinek34d93b02015-10-22 12:30:38 -0700915 }
916
Selim Cinek277a8aa2016-01-22 12:12:37 -0800917 @Override
918 public float getShadowAlpha() {
919 return mShadowAlpha;
920 }
921
922 @Override
923 public void setShadowAlpha(float shadowAlpha) {
924 if (shadowAlpha != mShadowAlpha) {
925 mShadowAlpha = shadowAlpha;
926 updateOutlineAlpha();
927 }
928 }
929
Selim Cinek33223572016-02-19 19:32:22 -0800930 @Override
931 public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
932 int outlineTranslation) {
933 mFakeShadow.setFakeShadowTranslationZ(shadowIntensity * (getTranslationZ()
934 + FakeShadowView.SHADOW_SIBLING_TRESHOLD), outlineAlpha, shadowYEnd,
935 outlineTranslation);
936 }
937
Selim Cinekc3179332016-03-04 14:44:56 -0800938 public int getBackgroundColorWithoutTint() {
939 return calculateBgColor(false /* withTint */);
940 }
941
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200942 public interface OnActivatedListener {
Selim Cineka32ab602014-06-11 15:06:01 +0200943 void onActivated(ActivatableNotificationView view);
944 void onActivationReset(ActivatableNotificationView view);
Jorim Jaggic5dc0d02014-04-15 15:42:55 +0200945 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946}