blob: c39ee3a902308560518f21f82a697e2ea1f1ec17 [file] [log] [blame]
Selim Cinekaa9db1f2018-02-27 17:35:47 -08001/*
2 * Copyright (C) 2018 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.phone;
18
felkachang3d00f352018-05-22 12:53:50 +080019import android.graphics.Point;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080020import android.graphics.Rect;
felkachang7749c9a2018-06-11 15:56:15 +080021import android.view.DisplayCutout;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080022import android.view.View;
felkachang3d00f352018-05-22 12:53:50 +080023import android.view.WindowInsets;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080024
25import com.android.internal.annotations.VisibleForTesting;
Peter Caia8178f52019-05-22 13:01:01 +080026import com.android.internal.widget.ViewClippingUtil;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080027import com.android.systemui.Dependency;
28import com.android.systemui.R;
Beverly1be62f42018-12-19 17:17:48 -050029import com.android.systemui.plugins.DarkIconDispatcher;
Selim Cinekc7e4cb52019-06-20 15:41:45 -070030import com.android.systemui.plugins.statusbar.StatusBarStateController;
31import com.android.systemui.statusbar.CommandQueue;
Selim Cinekd03518c2018-03-15 12:13:51 -070032import com.android.systemui.statusbar.CrossFadeHelper;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080033import com.android.systemui.statusbar.HeadsUpStatusBarView;
Selim Cinekc7e4cb52019-06-20 15:41:45 -070034import com.android.systemui.statusbar.StatusBarState;
35import com.android.systemui.statusbar.SysuiStatusBarStateController;
Selim Cinek8ee02b12019-07-22 14:49:18 -070036import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
Ned Burnsf81c4c42019-01-07 14:10:43 -050037import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Gus Prevasab336792018-11-14 13:52:20 -050038import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
39import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
Lucas Dupinc8f16e82019-09-17 18:24:50 -040040import com.android.systemui.statusbar.policy.KeyguardStateController;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080041import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080042
Selim Cinek60ffea62018-03-22 13:16:44 -070043import java.util.function.BiConsumer;
44import java.util.function.Consumer;
45
Selim Cinekaa9db1f2018-02-27 17:35:47 -080046/**
47 * Controls the appearance of heads up notifications in the icon area and the header itself.
48 */
Selim Cinekf0c79e12018-05-14 17:17:31 -070049public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
Selim Cinek8ee02b12019-07-22 14:49:18 -070050 DarkIconDispatcher.DarkReceiver, NotificationWakeUpCoordinator.WakeUpListener {
Selim Cinekd03518c2018-03-15 12:13:51 -070051 public static final int CONTENT_FADE_DURATION = 110;
52 public static final int CONTENT_FADE_DELAY = 100;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080053 private final NotificationIconAreaController mNotificationIconAreaController;
54 private final HeadsUpManagerPhone mHeadsUpManager;
55 private final NotificationStackScrollLayout mStackScroller;
56 private final HeadsUpStatusBarView mHeadsUpStatusBarView;
Beverly40770652019-02-15 15:49:49 -050057 private final View mCenteredIconView;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080058 private final View mClockView;
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +090059 private final View mOperatorNameView;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080060 private final DarkIconDispatcher mDarkIconDispatcher;
Dave Mankoffaf8163f2020-01-08 14:24:35 -050061 private final NotificationPanelViewController mNotificationPanelViewController;
Selim Cinek60ffea62018-03-22 13:16:44 -070062 private final Consumer<ExpandableNotificationRow>
63 mSetTrackingHeadsUp = this::setTrackingHeadsUp;
64 private final Runnable mUpdatePanelTranslation = this::updatePanelTranslation;
Selim Cinekc7e4cb52019-06-20 15:41:45 -070065 private final BiConsumer<Float, Float> mSetExpandedHeight = this::setAppearFraction;
66 private final KeyguardBypassController mBypassController;
67 private final StatusBarStateController mStatusBarStateController;
68 private final CommandQueue mCommandQueue;
Selim Cinek8ee02b12019-07-22 14:49:18 -070069 private final NotificationWakeUpCoordinator mWakeUpCoordinator;
felkachange6c03a02018-05-24 15:38:04 +080070 @VisibleForTesting
71 float mExpandedHeight;
72 @VisibleForTesting
73 boolean mIsExpanded;
74 @VisibleForTesting
Selim Cinekc7e4cb52019-06-20 15:41:45 -070075 float mAppearFraction;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080076 private ExpandableNotificationRow mTrackedChild;
77 private boolean mShown;
Selim Cinek60ffea62018-03-22 13:16:44 -070078 private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
79 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
80 -> updatePanelTranslation();
Peter Caia8178f52019-05-22 13:01:01 +080081 private final ViewClippingUtil.ClippingParameters mParentClippingParams =
82 new ViewClippingUtil.ClippingParameters() {
83 @Override
84 public boolean shouldFinish(View view) {
85 return view.getId() == R.id.status_bar;
86 }
87 };
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +090088 private boolean mAnimationsEnabled = true;
felkachang3d00f352018-05-22 12:53:50 +080089 Point mPoint;
Lucas Dupinc8f16e82019-09-17 18:24:50 -040090 private KeyguardStateController mKeyguardStateController;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080091
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +090092
Selim Cinekaa9db1f2018-02-27 17:35:47 -080093 public HeadsUpAppearanceController(
94 NotificationIconAreaController notificationIconAreaController,
wilsonshihe8321942019-10-18 18:39:46 +080095 HeadsUpManagerPhone headsUpManager,
96 View notificationShadeView,
Selim Cinekc7e4cb52019-06-20 15:41:45 -070097 SysuiStatusBarStateController statusBarStateController,
Selim Cinek8ee02b12019-07-22 14:49:18 -070098 KeyguardBypassController keyguardBypassController,
Lucas Dupind236ee32019-10-08 15:33:59 -070099 KeyguardStateController keyguardStateController,
Dave Mankoffaf8163f2020-01-08 14:24:35 -0500100 NotificationWakeUpCoordinator wakeUpCoordinator, CommandQueue commandQueue,
wilsonshihe8321942019-10-18 18:39:46 +0800101 NotificationPanelViewController notificationPanelViewController, View statusBarView) {
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700102 this(notificationIconAreaController, headsUpManager, statusBarStateController,
Lucas Dupind236ee32019-10-08 15:33:59 -0700103 keyguardBypassController, wakeUpCoordinator, keyguardStateController,
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400104 commandQueue,
wilsonshihe8321942019-10-18 18:39:46 +0800105 statusBarView.findViewById(R.id.heads_up_status_bar_view),
106 notificationShadeView.findViewById(R.id.notification_stack_scroller),
Dave Mankoffaf8163f2020-01-08 14:24:35 -0500107 notificationPanelViewController,
wilsonshihe8321942019-10-18 18:39:46 +0800108 statusBarView.findViewById(R.id.clock),
109 statusBarView.findViewById(R.id.operator_name_frame),
110 statusBarView.findViewById(R.id.centered_icon_area));
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800111 }
112
113 @VisibleForTesting
114 public HeadsUpAppearanceController(
115 NotificationIconAreaController notificationIconAreaController,
116 HeadsUpManagerPhone headsUpManager,
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700117 StatusBarStateController stateController,
118 KeyguardBypassController bypassController,
Selim Cinek8ee02b12019-07-22 14:49:18 -0700119 NotificationWakeUpCoordinator wakeUpCoordinator,
Lucas Dupind236ee32019-10-08 15:33:59 -0700120 KeyguardStateController keyguardStateController,
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400121 CommandQueue commandQueue,
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800122 HeadsUpStatusBarView headsUpStatusBarView,
123 NotificationStackScrollLayout stackScroller,
Dave Mankoffaf8163f2020-01-08 14:24:35 -0500124 NotificationPanelViewController notificationPanelViewController,
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900125 View clockView,
Beverly40770652019-02-15 15:49:49 -0500126 View operatorNameView,
127 View centeredIconView) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800128 mNotificationIconAreaController = notificationIconAreaController;
129 mHeadsUpManager = headsUpManager;
130 mHeadsUpManager.addListener(this);
131 mHeadsUpStatusBarView = headsUpStatusBarView;
Beverly40770652019-02-15 15:49:49 -0500132 mCenteredIconView = centeredIconView;
Selim Cinek332c23f2018-03-16 17:37:50 -0700133 headsUpStatusBarView.setOnDrawingRectChangedListener(
134 () -> updateIsolatedIconLocation(true /* requireUpdate */));
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800135 mStackScroller = stackScroller;
Dave Mankoffaf8163f2020-01-08 14:24:35 -0500136 mNotificationPanelViewController = notificationPanelViewController;
137 notificationPanelViewController.addTrackingHeadsUpListener(mSetTrackingHeadsUp);
138 notificationPanelViewController.addVerticalTranslationListener(mUpdatePanelTranslation);
139 notificationPanelViewController.setHeadsUpAppearanceController(this);
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700140 mStackScroller.addOnExpandedHeightChangedListener(mSetExpandedHeight);
Selim Cinek60ffea62018-03-22 13:16:44 -0700141 mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
Selim Cinekf0c79e12018-05-14 17:17:31 -0700142 mStackScroller.setHeadsUpAppearanceController(this);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800143 mClockView = clockView;
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900144 mOperatorNameView = operatorNameView;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800145 mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
146 mDarkIconDispatcher.addDarkReceiver(this);
felkachange6c03a02018-05-24 15:38:04 +0800147
148 mHeadsUpStatusBarView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
149 @Override
150 public void onLayoutChange(View v, int left, int top, int right, int bottom,
151 int oldLeft, int oldTop, int oldRight, int oldBottom) {
152 if (shouldBeVisible()) {
153 updateTopEntry();
154
155 // trigger scroller to notify the latest panel translation
156 mStackScroller.requestLayout();
157 }
158 mHeadsUpStatusBarView.removeOnLayoutChangeListener(this);
159 }
160 });
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700161 mBypassController = bypassController;
162 mStatusBarStateController = stateController;
Selim Cinek8ee02b12019-07-22 14:49:18 -0700163 mWakeUpCoordinator = wakeUpCoordinator;
164 wakeUpCoordinator.addListener(this);
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400165 mCommandQueue = commandQueue;
Lucas Dupind236ee32019-10-08 15:33:59 -0700166 mKeyguardStateController = keyguardStateController;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800167 }
168
Selim Cinek60ffea62018-03-22 13:16:44 -0700169
170 public void destroy() {
171 mHeadsUpManager.removeListener(this);
172 mHeadsUpStatusBarView.setOnDrawingRectChangedListener(null);
Selim Cinek8ee02b12019-07-22 14:49:18 -0700173 mWakeUpCoordinator.removeListener(this);
Dave Mankoffaf8163f2020-01-08 14:24:35 -0500174 mNotificationPanelViewController.removeTrackingHeadsUpListener(mSetTrackingHeadsUp);
175 mNotificationPanelViewController.removeVerticalTranslationListener(mUpdatePanelTranslation);
176 mNotificationPanelViewController.setHeadsUpAppearanceController(null);
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700177 mStackScroller.removeOnExpandedHeightChangedListener(mSetExpandedHeight);
Selim Cinek60ffea62018-03-22 13:16:44 -0700178 mStackScroller.removeOnLayoutChangeListener(mStackScrollLayoutChangeListener);
179 mDarkIconDispatcher.removeDarkReceiver(this);
180 }
181
Selim Cinek332c23f2018-03-16 17:37:50 -0700182 private void updateIsolatedIconLocation(boolean requireStateUpdate) {
183 mNotificationIconAreaController.setIsolatedIconLocation(
184 mHeadsUpStatusBarView.getIconDrawingRect(), requireStateUpdate);
185 }
186
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800187 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500188 public void onHeadsUpPinned(NotificationEntry entry) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800189 updateTopEntry();
Evan Laird94492852018-10-25 13:43:01 -0400190 updateHeader(entry);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800191 }
192
felkachang3d00f352018-05-22 12:53:50 +0800193 /** To count the distance from the window right boundary to scroller right boundary. The
194 * distance formula is the following:
195 * Y = screenSize - (SystemWindow's width + Scroller.getRight())
196 * There are four modes MUST to be considered in Cut Out of RTL.
197 * No Cut Out:
198 * Scroller + NB
199 * NB + Scroller
200 * => SystemWindow = NavigationBar's width
201 * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
202 * Corner Cut Out or Tall Cut Out:
203 * cut out + Scroller + NB
204 * NB + Scroller + cut out
205 * => SystemWindow = NavigationBar's width
206 * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
207 * Double Cut Out:
208 * cut out left + Scroller + (NB + cut out right)
209 * SystemWindow = NavigationBar's width + cut out right width
210 * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
211 * (cut out left + NB) + Scroller + cut out right
212 * SystemWindow = NavigationBar's width + cut out left width
213 * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
214 * @return the translation X value for RTL. In theory, it should be negative. i.e. -Y
215 */
216 private int getRtlTranslation() {
felkachang3d00f352018-05-22 12:53:50 +0800217 if (mPoint == null) {
218 mPoint = new Point();
219 }
220
221 int realDisplaySize = 0;
222 if (mStackScroller.getDisplay() != null) {
223 mStackScroller.getDisplay().getRealSize(mPoint);
224 realDisplaySize = mPoint.x;
225 }
226
227 WindowInsets windowInset = mStackScroller.getRootWindowInsets();
felkachang7749c9a2018-06-11 15:56:15 +0800228 DisplayCutout cutout = (windowInset != null) ? windowInset.getDisplayCutout() : null;
229 int sysWinLeft = (windowInset != null) ? windowInset.getStableInsetLeft() : 0;
230 int sysWinRight = (windowInset != null) ? windowInset.getStableInsetRight() : 0;
231 int cutoutLeft = (cutout != null) ? cutout.getSafeInsetLeft() : 0;
232 int cutoutRight = (cutout != null) ? cutout.getSafeInsetRight() : 0;
233 int leftInset = Math.max(sysWinLeft, cutoutLeft);
234 int rightInset = Math.max(sysWinRight, cutoutRight);
235
236 return leftInset + mStackScroller.getRight() + rightInset - realDisplaySize;
felkachang3d00f352018-05-22 12:53:50 +0800237 }
238
Selim Cinek332c23f2018-03-16 17:37:50 -0700239 public void updatePanelTranslation() {
felkachang3d00f352018-05-22 12:53:50 +0800240 float newTranslation;
241 if (mStackScroller.isLayoutRtl()) {
242 newTranslation = getRtlTranslation();
243 } else {
244 newTranslation = mStackScroller.getLeft();
245 }
246 newTranslation += mStackScroller.getTranslationX();
felkachange8a35362018-05-18 20:11:38 +0800247 mHeadsUpStatusBarView.setPanelTranslation(newTranslation);
Selim Cinek332c23f2018-03-16 17:37:50 -0700248 }
249
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800250 private void updateTopEntry() {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500251 NotificationEntry newEntry = null;
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700252 if (shouldBeVisible()) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800253 newEntry = mHeadsUpManager.getTopEntry();
254 }
Ned Burnsf81c4c42019-01-07 14:10:43 -0500255 NotificationEntry previousEntry = mHeadsUpStatusBarView.getShowingEntry();
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800256 mHeadsUpStatusBarView.setEntry(newEntry);
257 if (newEntry != previousEntry) {
Selim Cinekd03518c2018-03-15 12:13:51 -0700258 boolean animateIsolation = false;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800259 if (newEntry == null) {
260 // no heads up anymore, lets start the disappear animation
261
262 setShown(false);
Selim Cinekd03518c2018-03-15 12:13:51 -0700263 animateIsolation = !mIsExpanded;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800264 } else if (previousEntry == null) {
265 // We now have a headsUp and didn't have one before. Let's start the disappear
266 // animation
267 setShown(true);
Selim Cinek332c23f2018-03-16 17:37:50 -0700268 animateIsolation = !mIsExpanded;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800269 }
Selim Cinek332c23f2018-03-16 17:37:50 -0700270 updateIsolatedIconLocation(false /* requireUpdate */);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800271 mNotificationIconAreaController.showIconIsolated(newEntry == null ? null
Selim Cinek332c23f2018-03-16 17:37:50 -0700272 : newEntry.icon, animateIsolation);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800273 }
274 }
275
276 private void setShown(boolean isShown) {
Selim Cinekd03518c2018-03-15 12:13:51 -0700277 if (mShown != isShown) {
278 mShown = isShown;
279 if (isShown) {
Peter Caia8178f52019-05-22 13:01:01 +0800280 updateParentClipping(false /* shouldClip */);
Selim Cinekd03518c2018-03-15 12:13:51 -0700281 mHeadsUpStatusBarView.setVisibility(View.VISIBLE);
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900282 show(mHeadsUpStatusBarView);
283 hide(mClockView, View.INVISIBLE);
Beverly40770652019-02-15 15:49:49 -0500284 if (mCenteredIconView.getVisibility() != View.GONE) {
285 hide(mCenteredIconView, View.INVISIBLE);
286 }
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900287 if (mOperatorNameView != null) {
288 hide(mOperatorNameView, View.INVISIBLE);
289 }
Selim Cinekd03518c2018-03-15 12:13:51 -0700290 } else {
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900291 show(mClockView);
Beverly40770652019-02-15 15:49:49 -0500292 if (mCenteredIconView.getVisibility() != View.GONE) {
293 show(mCenteredIconView);
294 }
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900295 if (mOperatorNameView != null) {
296 show(mOperatorNameView);
297 }
Peter Caia8178f52019-05-22 13:01:01 +0800298 hide(mHeadsUpStatusBarView, View.GONE, () -> {
299 updateParentClipping(true /* shouldClip */);
300 });
Selim Cinekd03518c2018-03-15 12:13:51 -0700301 }
Selim Cinek8ee02b12019-07-22 14:49:18 -0700302 // Show the status bar icons when the view gets shown / hidden
303 if (mStatusBarStateController.getState() != StatusBarState.SHADE) {
304 mCommandQueue.recomputeDisableFlags(
305 mHeadsUpStatusBarView.getContext().getDisplayId(), false);
306 }
Selim Cinekd03518c2018-03-15 12:13:51 -0700307 }
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800308 }
309
Peter Caia8178f52019-05-22 13:01:01 +0800310 private void updateParentClipping(boolean shouldClip) {
311 ViewClippingUtil.setClippingDeactivated(
312 mHeadsUpStatusBarView, !shouldClip, mParentClippingParams);
313 }
314
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900315 /**
316 * Hides the view and sets the state to endState when finished.
317 *
318 * @param view The view to hide.
319 * @param endState One of {@link View#INVISIBLE} or {@link View#GONE}.
Peter Caia8178f52019-05-22 13:01:01 +0800320 * @see HeadsUpAppearanceController#hide(View, int, Runnable)
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900321 * @see View#setVisibility(int)
322 *
323 */
324 private void hide(View view, int endState) {
Peter Caia8178f52019-05-22 13:01:01 +0800325 hide(view, endState, null);
326 }
327
328 /**
329 * Hides the view and sets the state to endState when finished.
330 *
331 * @param view The view to hide.
332 * @param endState One of {@link View#INVISIBLE} or {@link View#GONE}.
333 * @param callback Runnable to be executed after the view has been hidden.
334 * @see View#setVisibility(int)
335 *
336 */
337 private void hide(View view, int endState, Runnable callback) {
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900338 if (mAnimationsEnabled) {
339 CrossFadeHelper.fadeOut(view, CONTENT_FADE_DURATION /* duration */,
Peter Caia8178f52019-05-22 13:01:01 +0800340 0 /* delay */, () -> {
341 view.setVisibility(endState);
342 if (callback != null) {
343 callback.run();
344 }
345 });
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900346 } else {
347 view.setVisibility(endState);
Peter Caia8178f52019-05-22 13:01:01 +0800348 if (callback != null) {
349 callback.run();
350 }
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900351 }
352 }
353
354 private void show(View view) {
355 if (mAnimationsEnabled) {
356 CrossFadeHelper.fadeIn(view, CONTENT_FADE_DURATION /* duration */,
357 CONTENT_FADE_DELAY /* delay */);
358 } else {
359 view.setVisibility(View.VISIBLE);
360 }
361 }
362
363 @VisibleForTesting
364 void setAnimationsEnabled(boolean enabled) {
365 mAnimationsEnabled = enabled;
366 }
367
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800368 @VisibleForTesting
369 public boolean isShown() {
370 return mShown;
371 }
372
Selim Cinek332c23f2018-03-16 17:37:50 -0700373 /**
374 * Should the headsup status bar view be visible right now? This may be different from isShown,
375 * since the headsUp manager might not have notified us yet of the state change.
376 *
377 * @return if the heads up status bar view should be shown
378 */
379 public boolean shouldBeVisible() {
Selim Cinek8ee02b12019-07-22 14:49:18 -0700380 boolean notificationsShown = !mWakeUpCoordinator.getNotificationsFullyHidden();
381 boolean canShow = !mIsExpanded && notificationsShown;
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700382 if (mBypassController.getBypassEnabled() &&
383 (mStatusBarStateController.getState() == StatusBarState.KEYGUARD
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400384 || mKeyguardStateController.isKeyguardGoingAway())
Selim Cinek8ee02b12019-07-22 14:49:18 -0700385 && notificationsShown) {
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700386 canShow = true;
387 }
388 return canShow && mHeadsUpManager.hasPinnedHeadsUp();
Selim Cinek332c23f2018-03-16 17:37:50 -0700389 }
390
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800391 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500392 public void onHeadsUpUnPinned(NotificationEntry entry) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800393 updateTopEntry();
Evan Laird94492852018-10-25 13:43:01 -0400394 updateHeader(entry);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800395 }
396
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700397 public void setAppearFraction(float expandedHeight, float appearFraction) {
398 boolean changed = expandedHeight != mExpandedHeight;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800399 mExpandedHeight = expandedHeight;
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700400 mAppearFraction = appearFraction;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800401 boolean isExpanded = expandedHeight > 0;
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700402 // We only notify if the expandedHeight changed and not on the appearFraction, since
403 // otherwise we may run into an infinite loop where the panel and this are constantly
404 // updating themselves over just a small fraction
405 if (changed) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800406 updateHeadsUpHeaders();
407 }
408 if (isExpanded != mIsExpanded) {
409 mIsExpanded = isExpanded;
410 updateTopEntry();
411 }
412 }
413
414 /**
415 * Set a headsUp to be tracked, meaning that it is currently being pulled down after being
416 * in a pinned state on the top. The expand animation is different in that case and we need
417 * to update the header constantly afterwards.
418 *
419 * @param trackedChild the tracked headsUp or null if it's not tracking anymore.
420 */
421 public void setTrackingHeadsUp(ExpandableNotificationRow trackedChild) {
422 ExpandableNotificationRow previousTracked = mTrackedChild;
423 mTrackedChild = trackedChild;
424 if (previousTracked != null) {
425 updateHeader(previousTracked.getEntry());
426 }
427 }
428
429 private void updateHeadsUpHeaders() {
430 mHeadsUpManager.getAllEntries().forEach(entry -> {
431 updateHeader(entry);
432 });
433 }
434
Ned Burnsf81c4c42019-01-07 14:10:43 -0500435 public void updateHeader(NotificationEntry entry) {
Evan Laird94492852018-10-25 13:43:01 -0400436 ExpandableNotificationRow row = entry.getRow();
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800437 float headerVisibleAmount = 1.0f;
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700438 if (row.isPinned() || row.isHeadsUpAnimatingAway() || row == mTrackedChild
439 || row.showingPulsing()) {
440 headerVisibleAmount = mAppearFraction;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800441 }
442 row.setHeaderVisibleAmount(headerVisibleAmount);
443 }
444
445 @Override
446 public void onDarkChanged(Rect area, float darkIntensity, int tint) {
447 mHeadsUpStatusBarView.onDarkChanged(area, darkIntensity, tint);
448 }
449
Selim Cinekb2c5dc52019-06-24 15:46:52 -0700450 public void onStateChanged() {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800451 updateTopEntry();
452 }
felkachange6c03a02018-05-24 15:38:04 +0800453
454 void readFrom(HeadsUpAppearanceController oldController) {
455 if (oldController != null) {
456 mTrackedChild = oldController.mTrackedChild;
457 mExpandedHeight = oldController.mExpandedHeight;
458 mIsExpanded = oldController.mIsExpanded;
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700459 mAppearFraction = oldController.mAppearFraction;
felkachange6c03a02018-05-24 15:38:04 +0800460 }
461 }
Selim Cinek8ee02b12019-07-22 14:49:18 -0700462
463 @Override
464 public void onFullyHiddenChanged(boolean isFullyHidden) {
465 updateTopEntry();
466 }
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800467}