Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.systemui.statusbar.notification |
| 18 | |
| 19 | import android.animation.ObjectAnimator |
Selim Cinek | 15af976 | 2019-03-19 18:32:37 -0700 | [diff] [blame] | 20 | import android.content.Context |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 21 | import android.util.FloatProperty |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 22 | import com.android.systemui.Interpolators |
Selim Cinek | 34518f6 | 2019-02-28 19:41:18 -0800 | [diff] [blame] | 23 | import com.android.systemui.plugins.statusbar.StatusBarStateController |
Selim Cinek | c1d9ab2 | 2019-05-21 18:08:30 -0700 | [diff] [blame] | 24 | import com.android.systemui.statusbar.StatusBarState |
Selim Cinek | 624d6ca | 2019-02-19 15:39:08 -0800 | [diff] [blame] | 25 | import com.android.systemui.statusbar.notification.collection.NotificationEntry |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 26 | import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout |
| 27 | import com.android.systemui.statusbar.notification.stack.StackStateAnimator |
Selim Cinek | 15af976 | 2019-03-19 18:32:37 -0700 | [diff] [blame] | 28 | import com.android.systemui.statusbar.phone.DozeParameters |
Selim Cinek | c3fec68 | 2019-06-06 18:11:07 -0700 | [diff] [blame] | 29 | import com.android.systemui.statusbar.phone.HeadsUpManagerPhone |
Selim Cinek | c1d9ab2 | 2019-05-21 18:08:30 -0700 | [diff] [blame] | 30 | import com.android.systemui.statusbar.phone.KeyguardBypassController |
Selim Cinek | 195dfc5 | 2019-05-30 19:35:05 -0700 | [diff] [blame] | 31 | import com.android.systemui.statusbar.phone.NotificationIconAreaController |
Selim Cinek | c3fec68 | 2019-06-06 18:11:07 -0700 | [diff] [blame] | 32 | import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 33 | |
| 34 | import javax.inject.Inject |
| 35 | import javax.inject.Singleton |
| 36 | |
| 37 | @Singleton |
Selim Cinek | 5040f2e | 2019-02-14 18:22:42 -0800 | [diff] [blame] | 38 | class NotificationWakeUpCoordinator @Inject constructor( |
Selim Cinek | 15af976 | 2019-03-19 18:32:37 -0700 | [diff] [blame] | 39 | private val mContext: Context, |
Selim Cinek | c3fec68 | 2019-06-06 18:11:07 -0700 | [diff] [blame] | 40 | private val mHeadsUpManagerPhone: HeadsUpManagerPhone, |
Selim Cinek | 601cda6 | 2019-06-24 17:37:57 -0700 | [diff] [blame] | 41 | private val statusBarStateController: StatusBarStateController, |
Selim Cinek | b57dd8a | 2019-06-14 12:27:58 -0700 | [diff] [blame] | 42 | private val bypassController: KeyguardBypassController) |
Selim Cinek | c3fec68 | 2019-06-06 18:11:07 -0700 | [diff] [blame] | 43 | : OnHeadsUpChangedListener, StatusBarStateController.StateListener { |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 44 | |
| 45 | private val mNotificationVisibility |
| 46 | = object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") { |
| 47 | |
| 48 | override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) { |
| 49 | coordinator.setVisibilityAmount(value) |
| 50 | } |
| 51 | |
| 52 | override fun get(coordinator: NotificationWakeUpCoordinator): Float? { |
| 53 | return coordinator.mLinearVisibilityAmount |
| 54 | } |
| 55 | } |
| 56 | private lateinit var mStackScroller: NotificationStackScrollLayout |
| 57 | private var mVisibilityInterpolator = Interpolators.FAST_OUT_SLOW_IN_REVERSE |
| 58 | |
| 59 | private var mLinearDozeAmount: Float = 0.0f |
| 60 | private var mDozeAmount: Float = 0.0f |
| 61 | private var mNotificationVisibleAmount = 0.0f |
| 62 | private var mNotificationsVisible = false |
Selim Cinek | 624d6ca | 2019-02-19 15:39:08 -0800 | [diff] [blame] | 63 | private var mNotificationsVisibleForExpansion = false |
Selim Cinek | 195dfc5 | 2019-05-30 19:35:05 -0700 | [diff] [blame] | 64 | private var mVisibilityAnimator: ObjectAnimator? = null |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 65 | private var mVisibilityAmount = 0.0f |
| 66 | private var mLinearVisibilityAmount = 0.0f |
Selim Cinek | 459aee3 | 2019-02-20 11:18:56 -0800 | [diff] [blame] | 67 | private var mWakingUp = false |
| 68 | private val mEntrySetToClearWhenFinished = mutableSetOf<NotificationEntry>() |
Selim Cinek | 820ba2d | 2019-06-18 18:59:09 -0700 | [diff] [blame] | 69 | private val mDozeParameters: DozeParameters |
| 70 | private var pulseExpanding: Boolean = false |
| 71 | private val wakeUpListeners = arrayListOf<WakeUpListener>() |
Selim Cinek | 601cda6 | 2019-06-24 17:37:57 -0700 | [diff] [blame] | 72 | private var state: Int = StatusBarState.KEYGUARD |
| 73 | |
Selim Cinek | b57dd8a | 2019-06-14 12:27:58 -0700 | [diff] [blame] | 74 | var fullyAwake: Boolean = false |
| 75 | |
Selim Cinek | d0b48e3 | 2019-05-24 20:49:23 -0700 | [diff] [blame] | 76 | var willWakeUp = false |
| 77 | set(value) { |
Selim Cinek | 2bbd457 | 2019-05-28 15:31:10 -0700 | [diff] [blame] | 78 | if (!value || mDozeAmount != 0.0f) { |
Selim Cinek | d0b48e3 | 2019-05-24 20:49:23 -0700 | [diff] [blame] | 79 | field = value |
| 80 | } |
| 81 | } |
| 82 | |
Selim Cinek | 195dfc5 | 2019-05-30 19:35:05 -0700 | [diff] [blame] | 83 | lateinit var iconAreaController : NotificationIconAreaController |
Selim Cinek | d0b48e3 | 2019-05-24 20:49:23 -0700 | [diff] [blame] | 84 | var pulsing: Boolean = false |
| 85 | set(value) { |
| 86 | field = value |
| 87 | if (value) { |
| 88 | // Only when setting pulsing to true we want an immediate update, since we get |
| 89 | // this already when the doze service finishes which is usually before we get |
| 90 | // the waking up callback |
| 91 | updateNotificationVisibility(animate = shouldAnimateVisibility(), |
| 92 | increaseSpeed = false) |
| 93 | } |
| 94 | } |
| 95 | |
Selim Cinek | 820ba2d | 2019-06-18 18:59:09 -0700 | [diff] [blame] | 96 | var notificationsFullyHidden: Boolean = false |
| 97 | private set(value) { |
| 98 | if (field != value) { |
| 99 | field = value |
| 100 | for (listener in wakeUpListeners) { |
| 101 | listener.onFullyHiddenChanged(value) |
| 102 | } |
| 103 | } |
| 104 | } |
| 105 | |
Selim Cinek | b8cc6ef | 2019-06-14 16:37:53 -0700 | [diff] [blame] | 106 | /** |
| 107 | * True if we can show pulsing heads up notifications |
| 108 | */ |
| 109 | var canShowPulsingHuns: Boolean = false |
| 110 | private set |
| 111 | get() { |
| 112 | var canShow = pulsing |
| 113 | if (bypassController.bypassEnabled) { |
| 114 | // We also allow pulsing on the lock screen! |
| 115 | canShow = canShow || (mWakingUp || willWakeUp || fullyAwake) |
Selim Cinek | 601cda6 | 2019-06-24 17:37:57 -0700 | [diff] [blame] | 116 | && statusBarStateController.state == StatusBarState.KEYGUARD |
Selim Cinek | b8cc6ef | 2019-06-14 16:37:53 -0700 | [diff] [blame] | 117 | } |
| 118 | return canShow |
| 119 | } |
| 120 | |
Selim Cinek | 624d6ca | 2019-02-19 15:39:08 -0800 | [diff] [blame] | 121 | init { |
Selim Cinek | c3fec68 | 2019-06-06 18:11:07 -0700 | [diff] [blame] | 122 | mHeadsUpManagerPhone.addListener(this) |
Selim Cinek | 601cda6 | 2019-06-24 17:37:57 -0700 | [diff] [blame] | 123 | statusBarStateController.addCallback(this) |
Selim Cinek | 15af976 | 2019-03-19 18:32:37 -0700 | [diff] [blame] | 124 | mDozeParameters = DozeParameters.getInstance(mContext) |
Selim Cinek | 624d6ca | 2019-02-19 15:39:08 -0800 | [diff] [blame] | 125 | } |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 126 | |
| 127 | fun setStackScroller(stackScroller: NotificationStackScrollLayout) { |
| 128 | mStackScroller = stackScroller |
Selim Cinek | 820ba2d | 2019-06-18 18:59:09 -0700 | [diff] [blame] | 129 | pulseExpanding = stackScroller.isPulseExpanding |
| 130 | stackScroller.setOnPulseHeightChangedListener { |
| 131 | val nowExpanding = isPulseExpanding() |
| 132 | val changed = nowExpanding != pulseExpanding |
| 133 | pulseExpanding = nowExpanding |
| 134 | for (listener in wakeUpListeners) { |
| 135 | listener.onPulseExpansionChanged(changed) |
| 136 | } |
| 137 | } |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 138 | } |
| 139 | |
Selim Cinek | 820ba2d | 2019-06-18 18:59:09 -0700 | [diff] [blame] | 140 | fun isPulseExpanding(): Boolean = mStackScroller.isPulseExpanding |
| 141 | |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 142 | /** |
| 143 | * @param visible should notifications be visible |
| 144 | * @param animate should this change be animated |
| 145 | * @param increaseSpeed should the speed be increased of the animation |
| 146 | */ |
Selim Cinek | 624d6ca | 2019-02-19 15:39:08 -0800 | [diff] [blame] | 147 | fun setNotificationsVisibleForExpansion(visible: Boolean, animate: Boolean, |
| 148 | increaseSpeed: Boolean) { |
| 149 | mNotificationsVisibleForExpansion = visible |
| 150 | updateNotificationVisibility(animate, increaseSpeed) |
Selim Cinek | 34518f6 | 2019-02-28 19:41:18 -0800 | [diff] [blame] | 151 | if (!visible && mNotificationsVisible) { |
| 152 | // If we stopped expanding and we're still visible because we had a pulse that hasn't |
| 153 | // times out, let's release them all to make sure were not stuck in a state where |
| 154 | // notifications are visible |
Selim Cinek | c3fec68 | 2019-06-06 18:11:07 -0700 | [diff] [blame] | 155 | mHeadsUpManagerPhone.releaseAllImmediately() |
Selim Cinek | 34518f6 | 2019-02-28 19:41:18 -0800 | [diff] [blame] | 156 | } |
Selim Cinek | 624d6ca | 2019-02-19 15:39:08 -0800 | [diff] [blame] | 157 | } |
| 158 | |
Selim Cinek | 820ba2d | 2019-06-18 18:59:09 -0700 | [diff] [blame] | 159 | fun addListener(listener: WakeUpListener) { |
| 160 | wakeUpListeners.add(listener); |
| 161 | } |
| 162 | |
| 163 | fun removeFullyHiddenChangedListener(listener: WakeUpListener) { |
| 164 | wakeUpListeners.remove(listener); |
| 165 | } |
| 166 | |
Selim Cinek | 624d6ca | 2019-02-19 15:39:08 -0800 | [diff] [blame] | 167 | private fun updateNotificationVisibility(animate: Boolean, increaseSpeed: Boolean) { |
Selim Cinek | c3fec68 | 2019-06-06 18:11:07 -0700 | [diff] [blame] | 168 | // TODO: handle Lockscreen wakeup for bypass when we're not pulsing anymore |
Selim Cinek | b57dd8a | 2019-06-14 12:27:58 -0700 | [diff] [blame] | 169 | var visible = mNotificationsVisibleForExpansion || mHeadsUpManagerPhone.hasNotifications() |
Selim Cinek | b8cc6ef | 2019-06-14 16:37:53 -0700 | [diff] [blame] | 170 | visible = visible && canShowPulsingHuns |
Selim Cinek | b57dd8a | 2019-06-14 12:27:58 -0700 | [diff] [blame] | 171 | |
Selim Cinek | d0b48e3 | 2019-05-24 20:49:23 -0700 | [diff] [blame] | 172 | if (!visible && mNotificationsVisible && (mWakingUp || willWakeUp) && mDozeAmount != 0.0f) { |
Selim Cinek | 459aee3 | 2019-02-20 11:18:56 -0800 | [diff] [blame] | 173 | // let's not make notifications invisible while waking up, otherwise the animation |
| 174 | // is strange |
| 175 | return; |
Selim Cinek | 624d6ca | 2019-02-19 15:39:08 -0800 | [diff] [blame] | 176 | } |
| 177 | setNotificationsVisible(visible, animate, increaseSpeed) |
| 178 | } |
| 179 | |
| 180 | private fun setNotificationsVisible(visible: Boolean, animate: Boolean, |
| 181 | increaseSpeed: Boolean) { |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 182 | if (mNotificationsVisible == visible) { |
| 183 | return |
| 184 | } |
| 185 | mNotificationsVisible = visible |
Selim Cinek | 195dfc5 | 2019-05-30 19:35:05 -0700 | [diff] [blame] | 186 | mVisibilityAnimator?.cancel(); |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 187 | if (animate) { |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 188 | notifyAnimationStart(visible) |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 189 | startVisibilityAnimation(increaseSpeed) |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 190 | } else { |
| 191 | setVisibilityAmount(if (visible) 1.0f else 0.0f) |
| 192 | } |
| 193 | } |
| 194 | |
Selim Cinek | 34518f6 | 2019-02-28 19:41:18 -0800 | [diff] [blame] | 195 | override fun onDozeAmountChanged(linear: Float, eased: Float) { |
Selim Cinek | c1d9ab2 | 2019-05-21 18:08:30 -0700 | [diff] [blame] | 196 | if (updateDozeAmountIfBypass()) { |
| 197 | return |
| 198 | } |
Selim Cinek | 34518f6 | 2019-02-28 19:41:18 -0800 | [diff] [blame] | 199 | if (linear != 1.0f && linear != 0.0f |
| 200 | && (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) { |
| 201 | // Let's notify the scroller that an animation started |
| 202 | notifyAnimationStart(mLinearDozeAmount == 1.0f) |
| 203 | } |
Selim Cinek | 9a7520a | 2019-05-29 17:27:21 -0700 | [diff] [blame] | 204 | setDozeAmount(linear, eased) |
| 205 | } |
| 206 | |
| 207 | fun setDozeAmount(linear: Float, eased: Float) { |
| 208 | val changed = linear != mLinearDozeAmount |
Selim Cinek | 34518f6 | 2019-02-28 19:41:18 -0800 | [diff] [blame] | 209 | mLinearDozeAmount = linear |
| 210 | mDozeAmount = eased |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 211 | mStackScroller.setDozeAmount(mDozeAmount) |
Selim Cinek | 195dfc5 | 2019-05-30 19:35:05 -0700 | [diff] [blame] | 212 | updateHideAmount() |
Selim Cinek | 9a7520a | 2019-05-29 17:27:21 -0700 | [diff] [blame] | 213 | if (changed && linear == 0.0f) { |
Selim Cinek | 459aee3 | 2019-02-20 11:18:56 -0800 | [diff] [blame] | 214 | setNotificationsVisible(visible = false, animate = false, increaseSpeed = false); |
| 215 | setNotificationsVisibleForExpansion(visible = false, animate = false, |
| 216 | increaseSpeed = false) |
| 217 | } |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 218 | } |
| 219 | |
Selim Cinek | c1d9ab2 | 2019-05-21 18:08:30 -0700 | [diff] [blame] | 220 | override fun onStateChanged(newState: Int) { |
| 221 | updateDozeAmountIfBypass(); |
Selim Cinek | 601cda6 | 2019-06-24 17:37:57 -0700 | [diff] [blame] | 222 | if (bypassController.bypassEnabled && |
| 223 | newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED |
| 224 | && (!statusBarStateController.isDozing || shouldAnimateVisibility())) { |
| 225 | // We're leaving shade locked. Let's animate the notifications away |
| 226 | setNotificationsVisible(visible = true, increaseSpeed = false, animate = false) |
| 227 | setNotificationsVisible(visible = false, increaseSpeed = false, animate = true) |
| 228 | } |
| 229 | this.state = newState |
Selim Cinek | c1d9ab2 | 2019-05-21 18:08:30 -0700 | [diff] [blame] | 230 | } |
| 231 | |
| 232 | private fun updateDozeAmountIfBypass(): Boolean { |
Selim Cinek | b57dd8a | 2019-06-14 12:27:58 -0700 | [diff] [blame] | 233 | if (bypassController.bypassEnabled) { |
Selim Cinek | 9a7520a | 2019-05-29 17:27:21 -0700 | [diff] [blame] | 234 | var amount = 1.0f; |
Selim Cinek | 601cda6 | 2019-06-24 17:37:57 -0700 | [diff] [blame] | 235 | if (statusBarStateController.state == StatusBarState.SHADE |
| 236 | || statusBarStateController.state == StatusBarState.SHADE_LOCKED) { |
Selim Cinek | 9a7520a | 2019-05-29 17:27:21 -0700 | [diff] [blame] | 237 | amount = 0.0f; |
Selim Cinek | c1d9ab2 | 2019-05-21 18:08:30 -0700 | [diff] [blame] | 238 | } |
Selim Cinek | 9a7520a | 2019-05-29 17:27:21 -0700 | [diff] [blame] | 239 | setDozeAmount(amount, amount) |
Selim Cinek | c1d9ab2 | 2019-05-21 18:08:30 -0700 | [diff] [blame] | 240 | return true |
| 241 | } |
| 242 | return false |
| 243 | } |
| 244 | |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 245 | private fun startVisibilityAnimation(increaseSpeed: Boolean) { |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 246 | if (mNotificationVisibleAmount == 0f || mNotificationVisibleAmount == 1f) { |
| 247 | mVisibilityInterpolator = if (mNotificationsVisible) |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 248 | Interpolators.TOUCH_RESPONSE |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 249 | else |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 250 | Interpolators.FAST_OUT_SLOW_IN_REVERSE |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 251 | } |
| 252 | val target = if (mNotificationsVisible) 1.0f else 0.0f |
Selim Cinek | 195dfc5 | 2019-05-30 19:35:05 -0700 | [diff] [blame] | 253 | val visibilityAnimator = ObjectAnimator.ofFloat(this, mNotificationVisibility, target) |
| 254 | visibilityAnimator.setInterpolator(Interpolators.LINEAR) |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 255 | var duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong() |
| 256 | if (increaseSpeed) { |
| 257 | duration = (duration.toFloat() / 1.5F).toLong(); |
| 258 | } |
Selim Cinek | 195dfc5 | 2019-05-30 19:35:05 -0700 | [diff] [blame] | 259 | visibilityAnimator.setDuration(duration) |
| 260 | visibilityAnimator.start() |
| 261 | mVisibilityAnimator = visibilityAnimator |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 262 | } |
| 263 | |
| 264 | private fun setVisibilityAmount(visibilityAmount: Float) { |
| 265 | mLinearVisibilityAmount = visibilityAmount |
| 266 | mVisibilityAmount = mVisibilityInterpolator.getInterpolation( |
| 267 | visibilityAmount) |
Selim Cinek | 459aee3 | 2019-02-20 11:18:56 -0800 | [diff] [blame] | 268 | handleAnimationFinished(); |
Selim Cinek | 195dfc5 | 2019-05-30 19:35:05 -0700 | [diff] [blame] | 269 | updateHideAmount() |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 270 | } |
| 271 | |
Selim Cinek | 459aee3 | 2019-02-20 11:18:56 -0800 | [diff] [blame] | 272 | private fun handleAnimationFinished() { |
| 273 | if (mLinearDozeAmount == 0.0f || mLinearVisibilityAmount == 0.0f) { |
Selim Cinek | c3fec68 | 2019-06-06 18:11:07 -0700 | [diff] [blame] | 274 | mEntrySetToClearWhenFinished.forEach { it.setHeadsUpAnimatingAway(false) } |
Selim Cinek | 0e180ac | 2019-04-02 15:55:22 -0700 | [diff] [blame] | 275 | mEntrySetToClearWhenFinished.clear() |
Selim Cinek | 459aee3 | 2019-02-20 11:18:56 -0800 | [diff] [blame] | 276 | } |
| 277 | } |
| 278 | |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 279 | fun getWakeUpHeight() : Float { |
Selim Cinek | b0fada6 | 2019-06-17 19:03:59 -0700 | [diff] [blame] | 280 | return mStackScroller.wakeUpHeight |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 281 | } |
| 282 | |
Selim Cinek | 195dfc5 | 2019-05-30 19:35:05 -0700 | [diff] [blame] | 283 | private fun updateHideAmount() { |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 284 | val linearAmount = Math.min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount) |
| 285 | val amount = Math.min(1.0f - mVisibilityAmount, mDozeAmount) |
Selim Cinek | 195dfc5 | 2019-05-30 19:35:05 -0700 | [diff] [blame] | 286 | mStackScroller.setHideAmount(linearAmount, amount) |
Selim Cinek | 820ba2d | 2019-06-18 18:59:09 -0700 | [diff] [blame] | 287 | notificationsFullyHidden = linearAmount == 1.0f; |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 288 | } |
| 289 | |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 290 | private fun notifyAnimationStart(awake: Boolean) { |
Selim Cinek | 195dfc5 | 2019-05-30 19:35:05 -0700 | [diff] [blame] | 291 | mStackScroller.notifyHideAnimationStart(!awake) |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 292 | } |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 293 | |
Selim Cinek | 34518f6 | 2019-02-28 19:41:18 -0800 | [diff] [blame] | 294 | override fun onDozingChanged(isDozing: Boolean) { |
| 295 | if (isDozing) { |
Selim Cinek | 459aee3 | 2019-02-20 11:18:56 -0800 | [diff] [blame] | 296 | setNotificationsVisible(visible = false, animate = false, increaseSpeed = false) |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 297 | } |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 298 | } |
| 299 | |
Selim Cinek | b0fada6 | 2019-06-17 19:03:59 -0700 | [diff] [blame] | 300 | /** |
| 301 | * Set the height how tall notifications are pulsing. This is only set whenever we are expanding |
| 302 | * from a pulse and determines how much the notifications are expanded. |
| 303 | */ |
Selim Cinek | 5040f2e | 2019-02-14 18:22:42 -0800 | [diff] [blame] | 304 | fun setPulseHeight(height: Float): Float { |
Selim Cinek | b0fada6 | 2019-06-17 19:03:59 -0700 | [diff] [blame] | 305 | val overflow = mStackScroller.setPulseHeight(height) |
| 306 | // no overflow for the bypass experience |
| 307 | return if (bypassController.bypassEnabled) 0.0f else overflow |
Selim Cinek | 5040f2e | 2019-02-14 18:22:42 -0800 | [diff] [blame] | 308 | } |
| 309 | |
Selim Cinek | 459aee3 | 2019-02-20 11:18:56 -0800 | [diff] [blame] | 310 | fun setWakingUp(wakingUp: Boolean) { |
Selim Cinek | d0b48e3 | 2019-05-24 20:49:23 -0700 | [diff] [blame] | 311 | willWakeUp = false |
Selim Cinek | 459aee3 | 2019-02-20 11:18:56 -0800 | [diff] [blame] | 312 | mWakingUp = wakingUp |
Selim Cinek | b57dd8a | 2019-06-14 12:27:58 -0700 | [diff] [blame] | 313 | if (wakingUp && mNotificationsVisible && !mNotificationsVisibleForExpansion |
| 314 | && !bypassController.bypassEnabled) { |
Selim Cinek | 459aee3 | 2019-02-20 11:18:56 -0800 | [diff] [blame] | 315 | // We're waking up while pulsing, let's make sure the animation looks nice |
| 316 | mStackScroller.wakeUpFromPulse(); |
| 317 | } |
Selim Cinek | 624d6ca | 2019-02-19 15:39:08 -0800 | [diff] [blame] | 318 | } |
| 319 | |
Selim Cinek | c3fec68 | 2019-06-06 18:11:07 -0700 | [diff] [blame] | 320 | override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) { |
Selim Cinek | d0b48e3 | 2019-05-24 20:49:23 -0700 | [diff] [blame] | 321 | var animate = shouldAnimateVisibility() |
Selim Cinek | c3fec68 | 2019-06-06 18:11:07 -0700 | [diff] [blame] | 322 | if (!isHeadsUp) { |
Selim Cinek | d0b48e3 | 2019-05-24 20:49:23 -0700 | [diff] [blame] | 323 | if (mLinearDozeAmount != 0.0f && mLinearVisibilityAmount != 0.0f) { |
Selim Cinek | ae55d83 | 2019-02-22 17:43:43 -0800 | [diff] [blame] | 324 | if (entry.isRowDismissed) { |
| 325 | // if we animate, we see the shelf briefly visible. Instead we fully animate |
| 326 | // the notification and its background out |
| 327 | animate = false |
Selim Cinek | f434a74 | 2019-05-28 17:39:49 -0700 | [diff] [blame] | 328 | } else if (!mWakingUp && !willWakeUp){ |
Selim Cinek | c3fec68 | 2019-06-06 18:11:07 -0700 | [diff] [blame] | 329 | // TODO: look that this is done properly and not by anyone else |
| 330 | entry.setHeadsUpAnimatingAway(true) |
Selim Cinek | ae55d83 | 2019-02-22 17:43:43 -0800 | [diff] [blame] | 331 | mEntrySetToClearWhenFinished.add(entry) |
| 332 | } |
| 333 | } |
| 334 | } else if (mEntrySetToClearWhenFinished.contains(entry)) { |
Selim Cinek | 459aee3 | 2019-02-20 11:18:56 -0800 | [diff] [blame] | 335 | mEntrySetToClearWhenFinished.remove(entry) |
Selim Cinek | c3fec68 | 2019-06-06 18:11:07 -0700 | [diff] [blame] | 336 | entry.setHeadsUpAnimatingAway(false) |
Selim Cinek | 459aee3 | 2019-02-20 11:18:56 -0800 | [diff] [blame] | 337 | } |
Selim Cinek | ae55d83 | 2019-02-22 17:43:43 -0800 | [diff] [blame] | 338 | updateNotificationVisibility(animate, increaseSpeed = false) |
Selim Cinek | 3d6ae23 | 2019-01-04 14:14:33 -0800 | [diff] [blame] | 339 | } |
Selim Cinek | d0b48e3 | 2019-05-24 20:49:23 -0700 | [diff] [blame] | 340 | |
| 341 | private fun shouldAnimateVisibility() = |
| 342 | mDozeParameters.getAlwaysOn() && !mDozeParameters.getDisplayNeedsBlanking() |
Selim Cinek | 820ba2d | 2019-06-18 18:59:09 -0700 | [diff] [blame] | 343 | |
| 344 | interface WakeUpListener { |
| 345 | /** |
| 346 | * Called whenever the notifications are fully hidden or shown |
| 347 | */ |
| 348 | @JvmDefault fun onFullyHiddenChanged(isFullyHidden: Boolean) {} |
| 349 | |
| 350 | /** |
| 351 | * Called whenever the pulseExpansion changes |
| 352 | * @param expandingChanged if the user has started or stopped expanding |
| 353 | */ |
| 354 | @JvmDefault fun onPulseExpansionChanged(expandingChanged: Boolean) {} |
| 355 | } |
Selim Cinek | d5921a8 | 2019-01-29 19:04:08 -0800 | [diff] [blame] | 356 | } |