blob: 46dd5e62ddda7f9bc43097c88c4281b2f6019479 [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
Selim Cinekc7e4cb52019-06-20 15:41:45 -070019import static com.android.systemui.SysUiServiceProvider.getComponent;
20
felkachang3d00f352018-05-22 12:53:50 +080021import android.graphics.Point;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080022import android.graphics.Rect;
felkachang7749c9a2018-06-11 15:56:15 +080023import android.view.DisplayCutout;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080024import android.view.View;
felkachang3d00f352018-05-22 12:53:50 +080025import android.view.WindowInsets;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080026
27import com.android.internal.annotations.VisibleForTesting;
Peter Caia8178f52019-05-22 13:01:01 +080028import com.android.internal.widget.ViewClippingUtil;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080029import com.android.systemui.Dependency;
30import com.android.systemui.R;
Beverly1be62f42018-12-19 17:17:48 -050031import com.android.systemui.plugins.DarkIconDispatcher;
Selim Cinekc7e4cb52019-06-20 15:41:45 -070032import com.android.systemui.plugins.statusbar.StatusBarStateController;
33import com.android.systemui.statusbar.CommandQueue;
Selim Cinekd03518c2018-03-15 12:13:51 -070034import com.android.systemui.statusbar.CrossFadeHelper;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080035import com.android.systemui.statusbar.HeadsUpStatusBarView;
Selim Cinekc7e4cb52019-06-20 15:41:45 -070036import com.android.systemui.statusbar.StatusBarState;
37import com.android.systemui.statusbar.SysuiStatusBarStateController;
Ned Burnsf81c4c42019-01-07 14:10:43 -050038import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Gus Prevasab336792018-11-14 13:52:20 -050039import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
40import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
Selim Cinekc7e4cb52019-06-20 15:41:45 -070041import com.android.systemui.statusbar.policy.KeyguardMonitor;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080042import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080043
Selim Cinek60ffea62018-03-22 13:16:44 -070044import java.util.function.BiConsumer;
45import java.util.function.Consumer;
46
Selim Cinekaa9db1f2018-02-27 17:35:47 -080047/**
48 * Controls the appearance of heads up notifications in the icon area and the header itself.
49 */
Selim Cinekf0c79e12018-05-14 17:17:31 -070050public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
Selim Cinekaa9db1f2018-02-27 17:35:47 -080051 DarkIconDispatcher.DarkReceiver {
Selim Cinekd03518c2018-03-15 12:13:51 -070052 public static final int CONTENT_FADE_DURATION = 110;
53 public static final int CONTENT_FADE_DELAY = 100;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080054 private final NotificationIconAreaController mNotificationIconAreaController;
55 private final HeadsUpManagerPhone mHeadsUpManager;
56 private final NotificationStackScrollLayout mStackScroller;
57 private final HeadsUpStatusBarView mHeadsUpStatusBarView;
Beverly40770652019-02-15 15:49:49 -050058 private final View mCenteredIconView;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080059 private final View mClockView;
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +090060 private final View mOperatorNameView;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080061 private final DarkIconDispatcher mDarkIconDispatcher;
Selim Cinek60ffea62018-03-22 13:16:44 -070062 private final NotificationPanelView mPanelView;
63 private final Consumer<ExpandableNotificationRow>
64 mSetTrackingHeadsUp = this::setTrackingHeadsUp;
65 private final Runnable mUpdatePanelTranslation = this::updatePanelTranslation;
Selim Cinekc7e4cb52019-06-20 15:41:45 -070066 private final BiConsumer<Float, Float> mSetExpandedHeight = this::setAppearFraction;
67 private final KeyguardBypassController mBypassController;
68 private final StatusBarStateController mStatusBarStateController;
69 private final CommandQueue mCommandQueue;
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;
Selim Cinekc7e4cb52019-06-20 15:41:45 -070090 private KeyguardMonitor mKeyguardMonitor;
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,
95 HeadsUpManagerPhone headsUpManager,
Selim Cinekc7e4cb52019-06-20 15:41:45 -070096 View statusbarView,
97 SysuiStatusBarStateController statusBarStateController,
98 KeyguardBypassController keyguardBypassController) {
99 this(notificationIconAreaController, headsUpManager, statusBarStateController,
100 keyguardBypassController,
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800101 statusbarView.findViewById(R.id.heads_up_status_bar_view),
102 statusbarView.findViewById(R.id.notification_stack_scroller),
103 statusbarView.findViewById(R.id.notification_panel),
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900104 statusbarView.findViewById(R.id.clock),
Beverly40770652019-02-15 15:49:49 -0500105 statusbarView.findViewById(R.id.operator_name_frame),
106 statusbarView.findViewById(R.id.centered_icon_area));
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800107 }
108
109 @VisibleForTesting
110 public HeadsUpAppearanceController(
111 NotificationIconAreaController notificationIconAreaController,
112 HeadsUpManagerPhone headsUpManager,
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700113 StatusBarStateController stateController,
114 KeyguardBypassController bypassController,
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800115 HeadsUpStatusBarView headsUpStatusBarView,
116 NotificationStackScrollLayout stackScroller,
117 NotificationPanelView panelView,
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900118 View clockView,
Beverly40770652019-02-15 15:49:49 -0500119 View operatorNameView,
120 View centeredIconView) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800121 mNotificationIconAreaController = notificationIconAreaController;
122 mHeadsUpManager = headsUpManager;
123 mHeadsUpManager.addListener(this);
124 mHeadsUpStatusBarView = headsUpStatusBarView;
Beverly40770652019-02-15 15:49:49 -0500125 mCenteredIconView = centeredIconView;
Selim Cinek332c23f2018-03-16 17:37:50 -0700126 headsUpStatusBarView.setOnDrawingRectChangedListener(
127 () -> updateIsolatedIconLocation(true /* requireUpdate */));
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800128 mStackScroller = stackScroller;
Selim Cinek60ffea62018-03-22 13:16:44 -0700129 mPanelView = panelView;
130 panelView.addTrackingHeadsUpListener(mSetTrackingHeadsUp);
131 panelView.addVerticalTranslationListener(mUpdatePanelTranslation);
Selim Cinek332c23f2018-03-16 17:37:50 -0700132 panelView.setHeadsUpAppearanceController(this);
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700133 mStackScroller.addOnExpandedHeightChangedListener(mSetExpandedHeight);
Selim Cinek60ffea62018-03-22 13:16:44 -0700134 mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
Selim Cinekf0c79e12018-05-14 17:17:31 -0700135 mStackScroller.setHeadsUpAppearanceController(this);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800136 mClockView = clockView;
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900137 mOperatorNameView = operatorNameView;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800138 mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
139 mDarkIconDispatcher.addDarkReceiver(this);
felkachange6c03a02018-05-24 15:38:04 +0800140
141 mHeadsUpStatusBarView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
142 @Override
143 public void onLayoutChange(View v, int left, int top, int right, int bottom,
144 int oldLeft, int oldTop, int oldRight, int oldBottom) {
145 if (shouldBeVisible()) {
146 updateTopEntry();
147
148 // trigger scroller to notify the latest panel translation
149 mStackScroller.requestLayout();
150 }
151 mHeadsUpStatusBarView.removeOnLayoutChangeListener(this);
152 }
153 });
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700154 mBypassController = bypassController;
155 mStatusBarStateController = stateController;
156 mCommandQueue = getComponent(headsUpStatusBarView.getContext(), CommandQueue.class);
157 mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800158 }
159
Selim Cinek60ffea62018-03-22 13:16:44 -0700160
161 public void destroy() {
162 mHeadsUpManager.removeListener(this);
163 mHeadsUpStatusBarView.setOnDrawingRectChangedListener(null);
164 mPanelView.removeTrackingHeadsUpListener(mSetTrackingHeadsUp);
165 mPanelView.removeVerticalTranslationListener(mUpdatePanelTranslation);
166 mPanelView.setHeadsUpAppearanceController(null);
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700167 mStackScroller.removeOnExpandedHeightChangedListener(mSetExpandedHeight);
Selim Cinek60ffea62018-03-22 13:16:44 -0700168 mStackScroller.removeOnLayoutChangeListener(mStackScrollLayoutChangeListener);
169 mDarkIconDispatcher.removeDarkReceiver(this);
170 }
171
Selim Cinek332c23f2018-03-16 17:37:50 -0700172 private void updateIsolatedIconLocation(boolean requireStateUpdate) {
173 mNotificationIconAreaController.setIsolatedIconLocation(
174 mHeadsUpStatusBarView.getIconDrawingRect(), requireStateUpdate);
175 }
176
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800177 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500178 public void onHeadsUpPinned(NotificationEntry entry) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800179 updateTopEntry();
Evan Laird94492852018-10-25 13:43:01 -0400180 updateHeader(entry);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800181 }
182
felkachang3d00f352018-05-22 12:53:50 +0800183 /** To count the distance from the window right boundary to scroller right boundary. The
184 * distance formula is the following:
185 * Y = screenSize - (SystemWindow's width + Scroller.getRight())
186 * There are four modes MUST to be considered in Cut Out of RTL.
187 * No Cut Out:
188 * Scroller + NB
189 * NB + Scroller
190 * => SystemWindow = NavigationBar's width
191 * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
192 * Corner Cut Out or Tall Cut Out:
193 * cut out + Scroller + NB
194 * NB + Scroller + cut out
195 * => SystemWindow = NavigationBar's width
196 * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
197 * Double Cut Out:
198 * cut out left + Scroller + (NB + cut out right)
199 * SystemWindow = NavigationBar's width + cut out right width
200 * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
201 * (cut out left + NB) + Scroller + cut out right
202 * SystemWindow = NavigationBar's width + cut out left width
203 * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
204 * @return the translation X value for RTL. In theory, it should be negative. i.e. -Y
205 */
206 private int getRtlTranslation() {
felkachang3d00f352018-05-22 12:53:50 +0800207 if (mPoint == null) {
208 mPoint = new Point();
209 }
210
211 int realDisplaySize = 0;
212 if (mStackScroller.getDisplay() != null) {
213 mStackScroller.getDisplay().getRealSize(mPoint);
214 realDisplaySize = mPoint.x;
215 }
216
217 WindowInsets windowInset = mStackScroller.getRootWindowInsets();
felkachang7749c9a2018-06-11 15:56:15 +0800218 DisplayCutout cutout = (windowInset != null) ? windowInset.getDisplayCutout() : null;
219 int sysWinLeft = (windowInset != null) ? windowInset.getStableInsetLeft() : 0;
220 int sysWinRight = (windowInset != null) ? windowInset.getStableInsetRight() : 0;
221 int cutoutLeft = (cutout != null) ? cutout.getSafeInsetLeft() : 0;
222 int cutoutRight = (cutout != null) ? cutout.getSafeInsetRight() : 0;
223 int leftInset = Math.max(sysWinLeft, cutoutLeft);
224 int rightInset = Math.max(sysWinRight, cutoutRight);
225
226 return leftInset + mStackScroller.getRight() + rightInset - realDisplaySize;
felkachang3d00f352018-05-22 12:53:50 +0800227 }
228
Selim Cinek332c23f2018-03-16 17:37:50 -0700229 public void updatePanelTranslation() {
felkachang3d00f352018-05-22 12:53:50 +0800230 float newTranslation;
231 if (mStackScroller.isLayoutRtl()) {
232 newTranslation = getRtlTranslation();
233 } else {
234 newTranslation = mStackScroller.getLeft();
235 }
236 newTranslation += mStackScroller.getTranslationX();
felkachange8a35362018-05-18 20:11:38 +0800237 mHeadsUpStatusBarView.setPanelTranslation(newTranslation);
Selim Cinek332c23f2018-03-16 17:37:50 -0700238 }
239
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800240 private void updateTopEntry() {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500241 NotificationEntry newEntry = null;
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700242 if (shouldBeVisible()) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800243 newEntry = mHeadsUpManager.getTopEntry();
244 }
Ned Burnsf81c4c42019-01-07 14:10:43 -0500245 NotificationEntry previousEntry = mHeadsUpStatusBarView.getShowingEntry();
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800246 mHeadsUpStatusBarView.setEntry(newEntry);
247 if (newEntry != previousEntry) {
Selim Cinekd03518c2018-03-15 12:13:51 -0700248 boolean animateIsolation = false;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800249 if (newEntry == null) {
250 // no heads up anymore, lets start the disappear animation
251
252 setShown(false);
Selim Cinekd03518c2018-03-15 12:13:51 -0700253 animateIsolation = !mIsExpanded;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800254 } else if (previousEntry == null) {
255 // We now have a headsUp and didn't have one before. Let's start the disappear
256 // animation
257 setShown(true);
Selim Cinek332c23f2018-03-16 17:37:50 -0700258 animateIsolation = !mIsExpanded;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800259 }
Selim Cinek332c23f2018-03-16 17:37:50 -0700260 updateIsolatedIconLocation(false /* requireUpdate */);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800261 mNotificationIconAreaController.showIconIsolated(newEntry == null ? null
Selim Cinek332c23f2018-03-16 17:37:50 -0700262 : newEntry.icon, animateIsolation);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800263 }
264 }
265
266 private void setShown(boolean isShown) {
Selim Cinekd03518c2018-03-15 12:13:51 -0700267 if (mShown != isShown) {
268 mShown = isShown;
269 if (isShown) {
Peter Caia8178f52019-05-22 13:01:01 +0800270 updateParentClipping(false /* shouldClip */);
Selim Cinekd03518c2018-03-15 12:13:51 -0700271 mHeadsUpStatusBarView.setVisibility(View.VISIBLE);
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900272 show(mHeadsUpStatusBarView);
273 hide(mClockView, View.INVISIBLE);
Beverly40770652019-02-15 15:49:49 -0500274 if (mCenteredIconView.getVisibility() != View.GONE) {
275 hide(mCenteredIconView, View.INVISIBLE);
276 }
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900277 if (mOperatorNameView != null) {
278 hide(mOperatorNameView, View.INVISIBLE);
279 }
Selim Cinekd03518c2018-03-15 12:13:51 -0700280 } else {
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900281 show(mClockView);
Beverly40770652019-02-15 15:49:49 -0500282 if (mCenteredIconView.getVisibility() != View.GONE) {
283 show(mCenteredIconView);
284 }
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900285 if (mOperatorNameView != null) {
286 show(mOperatorNameView);
287 }
Peter Caia8178f52019-05-22 13:01:01 +0800288 hide(mHeadsUpStatusBarView, View.GONE, () -> {
289 updateParentClipping(true /* shouldClip */);
290 });
Selim Cinekd03518c2018-03-15 12:13:51 -0700291 }
292 }
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800293 }
294
Peter Caia8178f52019-05-22 13:01:01 +0800295 private void updateParentClipping(boolean shouldClip) {
296 ViewClippingUtil.setClippingDeactivated(
297 mHeadsUpStatusBarView, !shouldClip, mParentClippingParams);
298 }
299
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900300 /**
301 * Hides the view and sets the state to endState when finished.
302 *
303 * @param view The view to hide.
304 * @param endState One of {@link View#INVISIBLE} or {@link View#GONE}.
Peter Caia8178f52019-05-22 13:01:01 +0800305 * @see HeadsUpAppearanceController#hide(View, int, Runnable)
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900306 * @see View#setVisibility(int)
307 *
308 */
309 private void hide(View view, int endState) {
Peter Caia8178f52019-05-22 13:01:01 +0800310 hide(view, endState, null);
311 }
312
313 /**
314 * Hides the view and sets the state to endState when finished.
315 *
316 * @param view The view to hide.
317 * @param endState One of {@link View#INVISIBLE} or {@link View#GONE}.
318 * @param callback Runnable to be executed after the view has been hidden.
319 * @see View#setVisibility(int)
320 *
321 */
322 private void hide(View view, int endState, Runnable callback) {
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900323 if (mAnimationsEnabled) {
324 CrossFadeHelper.fadeOut(view, CONTENT_FADE_DURATION /* duration */,
Peter Caia8178f52019-05-22 13:01:01 +0800325 0 /* delay */, () -> {
326 view.setVisibility(endState);
327 if (callback != null) {
328 callback.run();
329 }
330 });
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900331 } else {
332 view.setVisibility(endState);
Peter Caia8178f52019-05-22 13:01:01 +0800333 if (callback != null) {
334 callback.run();
335 }
Tetsutoki Shiozawace9645b2018-09-05 13:17:01 +0900336 }
337 }
338
339 private void show(View view) {
340 if (mAnimationsEnabled) {
341 CrossFadeHelper.fadeIn(view, CONTENT_FADE_DURATION /* duration */,
342 CONTENT_FADE_DELAY /* delay */);
343 } else {
344 view.setVisibility(View.VISIBLE);
345 }
346 }
347
348 @VisibleForTesting
349 void setAnimationsEnabled(boolean enabled) {
350 mAnimationsEnabled = enabled;
351 }
352
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800353 @VisibleForTesting
354 public boolean isShown() {
355 return mShown;
356 }
357
Selim Cinek332c23f2018-03-16 17:37:50 -0700358 /**
359 * Should the headsup status bar view be visible right now? This may be different from isShown,
360 * since the headsUp manager might not have notified us yet of the state change.
361 *
362 * @return if the heads up status bar view should be shown
363 */
364 public boolean shouldBeVisible() {
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700365 boolean canShow = !mIsExpanded;
366 if (mBypassController.getBypassEnabled() &&
367 (mStatusBarStateController.getState() == StatusBarState.KEYGUARD
368 || mKeyguardMonitor.isKeyguardGoingAway())) {
369 canShow = true;
370 }
371 return canShow && mHeadsUpManager.hasPinnedHeadsUp();
Selim Cinek332c23f2018-03-16 17:37:50 -0700372 }
373
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800374 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500375 public void onHeadsUpUnPinned(NotificationEntry entry) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800376 updateTopEntry();
Evan Laird94492852018-10-25 13:43:01 -0400377 updateHeader(entry);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800378 }
379
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700380 @Override
381 public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
382 if (mStatusBarStateController.getState() != StatusBarState.SHADE) {
383 // Show the status bar icons when the pinned mode changes
384 mCommandQueue.recomputeDisableFlags(
385 mHeadsUpStatusBarView.getContext().getDisplayId(), false);
386 }
387 }
388
389 public void setAppearFraction(float expandedHeight, float appearFraction) {
390 boolean changed = expandedHeight != mExpandedHeight;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800391 mExpandedHeight = expandedHeight;
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700392 mAppearFraction = appearFraction;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800393 boolean isExpanded = expandedHeight > 0;
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700394 // We only notify if the expandedHeight changed and not on the appearFraction, since
395 // otherwise we may run into an infinite loop where the panel and this are constantly
396 // updating themselves over just a small fraction
397 if (changed) {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800398 updateHeadsUpHeaders();
399 }
400 if (isExpanded != mIsExpanded) {
401 mIsExpanded = isExpanded;
402 updateTopEntry();
403 }
404 }
405
406 /**
407 * Set a headsUp to be tracked, meaning that it is currently being pulled down after being
408 * in a pinned state on the top. The expand animation is different in that case and we need
409 * to update the header constantly afterwards.
410 *
411 * @param trackedChild the tracked headsUp or null if it's not tracking anymore.
412 */
413 public void setTrackingHeadsUp(ExpandableNotificationRow trackedChild) {
414 ExpandableNotificationRow previousTracked = mTrackedChild;
415 mTrackedChild = trackedChild;
416 if (previousTracked != null) {
417 updateHeader(previousTracked.getEntry());
418 }
419 }
420
421 private void updateHeadsUpHeaders() {
422 mHeadsUpManager.getAllEntries().forEach(entry -> {
423 updateHeader(entry);
424 });
425 }
426
Ned Burnsf81c4c42019-01-07 14:10:43 -0500427 public void updateHeader(NotificationEntry entry) {
Evan Laird94492852018-10-25 13:43:01 -0400428 ExpandableNotificationRow row = entry.getRow();
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800429 float headerVisibleAmount = 1.0f;
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700430 if (row.isPinned() || row.isHeadsUpAnimatingAway() || row == mTrackedChild
431 || row.showingPulsing()) {
432 headerVisibleAmount = mAppearFraction;
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800433 }
434 row.setHeaderVisibleAmount(headerVisibleAmount);
435 }
436
437 @Override
438 public void onDarkChanged(Rect area, float darkIntensity, int tint) {
439 mHeadsUpStatusBarView.onDarkChanged(area, darkIntensity, tint);
440 }
441
Selim Cinekb2c5dc52019-06-24 15:46:52 -0700442 public void onStateChanged() {
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800443 updateTopEntry();
444 }
felkachange6c03a02018-05-24 15:38:04 +0800445
446 void readFrom(HeadsUpAppearanceController oldController) {
447 if (oldController != null) {
448 mTrackedChild = oldController.mTrackedChild;
449 mExpandedHeight = oldController.mExpandedHeight;
450 mIsExpanded = oldController.mIsExpanded;
Selim Cinekc7e4cb52019-06-20 15:41:45 -0700451 mAppearFraction = oldController.mAppearFraction;
felkachange6c03a02018-05-24 15:38:04 +0800452 }
453 }
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800454}