blob: ccb8d9bf46c13958ec050ea4f93da9d52a8c55c2 [file] [log] [blame]
Selim Cinekd5921a82019-01-29 19:04:08 -08001/*
2 * Copyright (C) 2019 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.notification
18
19import android.animation.ObjectAnimator
20import android.util.FloatProperty
Selim Cinekd5921a82019-01-29 19:04:08 -080021import com.android.systemui.Interpolators
Selim Cinek34518f62019-02-28 19:41:18 -080022import com.android.systemui.plugins.statusbar.StatusBarStateController
Selim Cinek5040f2e2019-02-14 18:22:42 -080023import com.android.systemui.statusbar.AmbientPulseManager
Selim Cinek34518f62019-02-28 19:41:18 -080024import com.android.systemui.statusbar.SysuiStatusBarStateController
Selim Cinek624d6ca2019-02-19 15:39:08 -080025import com.android.systemui.statusbar.notification.collection.NotificationEntry
Selim Cinekd5921a82019-01-29 19:04:08 -080026import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
27import com.android.systemui.statusbar.notification.stack.StackStateAnimator
28
29import javax.inject.Inject
30import javax.inject.Singleton
31
32@Singleton
Selim Cinek5040f2e2019-02-14 18:22:42 -080033class NotificationWakeUpCoordinator @Inject constructor(
Selim Cinek34518f62019-02-28 19:41:18 -080034 private val mAmbientPulseManager: AmbientPulseManager,
35 private val mStatusBarStateController: StatusBarStateController)
36 : AmbientPulseManager.OnAmbientChangedListener, StatusBarStateController.StateListener {
Selim Cinekd5921a82019-01-29 19:04:08 -080037
38 private val mNotificationVisibility
39 = object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") {
40
41 override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) {
42 coordinator.setVisibilityAmount(value)
43 }
44
45 override fun get(coordinator: NotificationWakeUpCoordinator): Float? {
46 return coordinator.mLinearVisibilityAmount
47 }
48 }
49 private lateinit var mStackScroller: NotificationStackScrollLayout
50 private var mVisibilityInterpolator = Interpolators.FAST_OUT_SLOW_IN_REVERSE
51
52 private var mLinearDozeAmount: Float = 0.0f
53 private var mDozeAmount: Float = 0.0f
54 private var mNotificationVisibleAmount = 0.0f
55 private var mNotificationsVisible = false
Selim Cinek624d6ca2019-02-19 15:39:08 -080056 private var mNotificationsVisibleForExpansion = false
Selim Cinekd5921a82019-01-29 19:04:08 -080057 private var mDarkAnimator: ObjectAnimator? = null
58 private var mVisibilityAmount = 0.0f
59 private var mLinearVisibilityAmount = 0.0f
Selim Cinek459aee32019-02-20 11:18:56 -080060 private var mWakingUp = false
61 private val mEntrySetToClearWhenFinished = mutableSetOf<NotificationEntry>()
Selim Cinek624d6ca2019-02-19 15:39:08 -080062
63 init {
64 mAmbientPulseManager.addListener(this)
Selim Cinek34518f62019-02-28 19:41:18 -080065 mStatusBarStateController.addCallback(this)
Selim Cinek624d6ca2019-02-19 15:39:08 -080066 }
Selim Cinekd5921a82019-01-29 19:04:08 -080067
68 fun setStackScroller(stackScroller: NotificationStackScrollLayout) {
69 mStackScroller = stackScroller
70 }
71
Selim Cinek3d6ae232019-01-04 14:14:33 -080072 /**
73 * @param visible should notifications be visible
74 * @param animate should this change be animated
75 * @param increaseSpeed should the speed be increased of the animation
76 */
Selim Cinek624d6ca2019-02-19 15:39:08 -080077 fun setNotificationsVisibleForExpansion(visible: Boolean, animate: Boolean,
78 increaseSpeed: Boolean) {
79 mNotificationsVisibleForExpansion = visible
80 updateNotificationVisibility(animate, increaseSpeed)
Selim Cinek34518f62019-02-28 19:41:18 -080081 if (!visible && mNotificationsVisible) {
82 // If we stopped expanding and we're still visible because we had a pulse that hasn't
83 // times out, let's release them all to make sure were not stuck in a state where
84 // notifications are visible
85 mAmbientPulseManager.releaseAllImmediately()
86 }
Selim Cinek624d6ca2019-02-19 15:39:08 -080087 }
88
89 private fun updateNotificationVisibility(animate: Boolean, increaseSpeed: Boolean) {
Selim Cinek459aee32019-02-20 11:18:56 -080090 var visible = mNotificationsVisibleForExpansion || mAmbientPulseManager.hasNotifications()
91 if (!visible && mNotificationsVisible && mWakingUp && mDozeAmount != 0.0f) {
92 // let's not make notifications invisible while waking up, otherwise the animation
93 // is strange
94 return;
Selim Cinek624d6ca2019-02-19 15:39:08 -080095 }
96 setNotificationsVisible(visible, animate, increaseSpeed)
97 }
98
99 private fun setNotificationsVisible(visible: Boolean, animate: Boolean,
100 increaseSpeed: Boolean) {
Selim Cinekd5921a82019-01-29 19:04:08 -0800101 if (mNotificationsVisible == visible) {
102 return
103 }
104 mNotificationsVisible = visible
105 mDarkAnimator?.cancel();
106 if (animate) {
Selim Cinekd5921a82019-01-29 19:04:08 -0800107 notifyAnimationStart(visible)
Selim Cinek3d6ae232019-01-04 14:14:33 -0800108 startVisibilityAnimation(increaseSpeed)
Selim Cinekd5921a82019-01-29 19:04:08 -0800109 } else {
110 setVisibilityAmount(if (visible) 1.0f else 0.0f)
111 }
112 }
113
Selim Cinek34518f62019-02-28 19:41:18 -0800114 override fun onDozeAmountChanged(linear: Float, eased: Float) {
115 if (linear != 1.0f && linear != 0.0f
116 && (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) {
117 // Let's notify the scroller that an animation started
118 notifyAnimationStart(mLinearDozeAmount == 1.0f)
119 }
120 mLinearDozeAmount = linear
121 mDozeAmount = eased
Selim Cinek3d6ae232019-01-04 14:14:33 -0800122 mStackScroller.setDozeAmount(mDozeAmount)
Selim Cinekd5921a82019-01-29 19:04:08 -0800123 updateDarkAmount()
Selim Cinek34518f62019-02-28 19:41:18 -0800124 if (linear == 0.0f) {
Selim Cinek459aee32019-02-20 11:18:56 -0800125 setNotificationsVisible(visible = false, animate = false, increaseSpeed = false);
126 setNotificationsVisibleForExpansion(visible = false, animate = false,
127 increaseSpeed = false)
128 }
Selim Cinekd5921a82019-01-29 19:04:08 -0800129 }
130
Selim Cinek3d6ae232019-01-04 14:14:33 -0800131 private fun startVisibilityAnimation(increaseSpeed: Boolean) {
Selim Cinekd5921a82019-01-29 19:04:08 -0800132 if (mNotificationVisibleAmount == 0f || mNotificationVisibleAmount == 1f) {
133 mVisibilityInterpolator = if (mNotificationsVisible)
Selim Cinek3d6ae232019-01-04 14:14:33 -0800134 Interpolators.TOUCH_RESPONSE
Selim Cinekd5921a82019-01-29 19:04:08 -0800135 else
Selim Cinek3d6ae232019-01-04 14:14:33 -0800136 Interpolators.FAST_OUT_SLOW_IN_REVERSE
Selim Cinekd5921a82019-01-29 19:04:08 -0800137 }
138 val target = if (mNotificationsVisible) 1.0f else 0.0f
139 val darkAnimator = ObjectAnimator.ofFloat(this, mNotificationVisibility, target)
140 darkAnimator.setInterpolator(Interpolators.LINEAR)
Selim Cinek3d6ae232019-01-04 14:14:33 -0800141 var duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong()
142 if (increaseSpeed) {
143 duration = (duration.toFloat() / 1.5F).toLong();
144 }
145 darkAnimator.setDuration(duration)
Selim Cinekd5921a82019-01-29 19:04:08 -0800146 darkAnimator.start()
147 mDarkAnimator = darkAnimator
148 }
149
150 private fun setVisibilityAmount(visibilityAmount: Float) {
151 mLinearVisibilityAmount = visibilityAmount
152 mVisibilityAmount = mVisibilityInterpolator.getInterpolation(
153 visibilityAmount)
Selim Cinek459aee32019-02-20 11:18:56 -0800154 handleAnimationFinished();
Selim Cinekd5921a82019-01-29 19:04:08 -0800155 updateDarkAmount()
156 }
157
Selim Cinek459aee32019-02-20 11:18:56 -0800158 private fun handleAnimationFinished() {
159 if (mLinearDozeAmount == 0.0f || mLinearVisibilityAmount == 0.0f) {
160 mEntrySetToClearWhenFinished.forEach { it.setAmbientGoingAway(false) }
161 }
162 }
163
Selim Cinek3d6ae232019-01-04 14:14:33 -0800164 fun getWakeUpHeight() : Float {
Selim Cinek34518f62019-02-28 19:41:18 -0800165 return mStackScroller.pulseHeight
Selim Cinek3d6ae232019-01-04 14:14:33 -0800166 }
167
Selim Cinekd5921a82019-01-29 19:04:08 -0800168 private fun updateDarkAmount() {
169 val linearAmount = Math.min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount)
170 val amount = Math.min(1.0f - mVisibilityAmount, mDozeAmount)
171 mStackScroller.setDarkAmount(linearAmount, amount)
172 }
173
Selim Cinek3d6ae232019-01-04 14:14:33 -0800174 private fun notifyAnimationStart(awake: Boolean) {
Selim Cinekd5921a82019-01-29 19:04:08 -0800175 mStackScroller.notifyDarkAnimationStart(!awake)
176 }
Selim Cinek3d6ae232019-01-04 14:14:33 -0800177
Selim Cinek34518f62019-02-28 19:41:18 -0800178 override fun onDozingChanged(isDozing: Boolean) {
179 if (isDozing) {
Selim Cinek459aee32019-02-20 11:18:56 -0800180 setNotificationsVisible(visible = false, animate = false, increaseSpeed = false)
Selim Cinek3d6ae232019-01-04 14:14:33 -0800181 }
Selim Cinek3d6ae232019-01-04 14:14:33 -0800182 }
183
Selim Cinek5040f2e2019-02-14 18:22:42 -0800184 fun setPulseHeight(height: Float): Float {
185 return mStackScroller.setPulseHeight(height)
186 }
187
Selim Cinek459aee32019-02-20 11:18:56 -0800188 fun setWakingUp(wakingUp: Boolean) {
189 mWakingUp = wakingUp
190 if (wakingUp && mNotificationsVisible && !mNotificationsVisibleForExpansion) {
191 // We're waking up while pulsing, let's make sure the animation looks nice
192 mStackScroller.wakeUpFromPulse();
193 }
Selim Cinek624d6ca2019-02-19 15:39:08 -0800194 }
195
Selim Cinek459aee32019-02-20 11:18:56 -0800196 override fun onAmbientStateChanged(entry: NotificationEntry, isPulsing: Boolean) {
Selim Cinekae55d832019-02-22 17:43:43 -0800197 var animate = true
198 if (!isPulsing) {
199 if (mLinearDozeAmount != 0.0f) {
200 if (entry.isRowDismissed) {
201 // if we animate, we see the shelf briefly visible. Instead we fully animate
202 // the notification and its background out
203 animate = false
204 } else {
205 entry.setAmbientGoingAway(true)
206 mEntrySetToClearWhenFinished.add(entry)
207 }
208 }
209 } else if (mEntrySetToClearWhenFinished.contains(entry)) {
Selim Cinek459aee32019-02-20 11:18:56 -0800210 mEntrySetToClearWhenFinished.remove(entry)
211 entry.setAmbientGoingAway(false)
212 }
Selim Cinekae55d832019-02-22 17:43:43 -0800213 updateNotificationVisibility(animate, increaseSpeed = false)
Selim Cinek3d6ae232019-01-04 14:14:33 -0800214 }
Selim Cinekd5921a82019-01-29 19:04:08 -0800215}