• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.phone;
18 
19 import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
20 import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
21 
22 import static com.android.systemui.Flags.updateUserSwitcherBackground;
23 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
24 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
25 
26 import android.content.Context;
27 import android.content.res.Configuration;
28 import android.content.res.Resources;
29 import android.database.ContentObserver;
30 import android.hardware.biometrics.BiometricSourceType;
31 import android.os.UserHandle;
32 import android.os.UserManager;
33 import android.provider.Settings;
34 import android.util.MathUtils;
35 import android.view.DisplayCutout;
36 import android.view.View;
37 import android.view.ViewGroup;
38 
39 import androidx.annotation.NonNull;
40 import androidx.annotation.Nullable;
41 import androidx.annotation.VisibleForTesting;
42 import androidx.compose.ui.platform.ComposeView;
43 import androidx.core.animation.Animator;
44 import androidx.core.animation.AnimatorListenerAdapter;
45 import androidx.core.animation.ValueAnimator;
46 
47 import com.android.app.animation.InterpolatorsAndroidX;
48 import com.android.keyguard.CarrierTextController;
49 import com.android.keyguard.KeyguardUpdateMonitor;
50 import com.android.keyguard.KeyguardUpdateMonitorCallback;
51 import com.android.keyguard.logging.KeyguardLogger;
52 import com.android.systemui.Flags;
53 import com.android.systemui.battery.BatteryMeterViewController;
54 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor;
55 import com.android.systemui.dagger.qualifiers.Background;
56 import com.android.systemui.dagger.qualifiers.Main;
57 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel;
58 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel;
59 import com.android.systemui.log.core.LogLevel;
60 import com.android.systemui.plugins.statusbar.StatusBarStateController;
61 import com.android.systemui.res.R;
62 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
63 import com.android.systemui.shade.ShadeDisplayAware;
64 import com.android.systemui.shade.ShadeViewStateProvider;
65 import com.android.systemui.statusbar.CommandQueue;
66 import com.android.systemui.statusbar.StatusBarState;
67 import com.android.systemui.statusbar.SysuiStatusBarStateController;
68 import com.android.systemui.statusbar.core.NewStatusBarIcons;
69 import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore;
70 import com.android.systemui.statusbar.disableflags.DisableStateTracker;
71 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
72 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
73 import com.android.systemui.statusbar.layout.StatusBarContentInsetsProvider;
74 import com.android.systemui.statusbar.notification.AnimatableProperty;
75 import com.android.systemui.statusbar.notification.PropertyAnimator;
76 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
77 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
78 import com.android.systemui.statusbar.phone.domain.interactor.DarkIconInteractor;
79 import com.android.systemui.statusbar.phone.fragment.StatusBarIconBlocklistKt;
80 import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventDefaultAnimator;
81 import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
82 import com.android.systemui.statusbar.phone.ui.TintedIconManager;
83 import com.android.systemui.statusbar.pipeline.battery.ui.binder.UnifiedBatteryViewBinder;
84 import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel;
85 import com.android.systemui.statusbar.policy.BatteryController;
86 import com.android.systemui.statusbar.policy.ConfigurationController;
87 import com.android.systemui.statusbar.policy.KeyguardStateController;
88 import com.android.systemui.statusbar.policy.UserInfoController;
89 import com.android.systemui.statusbar.ui.binder.KeyguardStatusBarViewBinder;
90 import com.android.systemui.statusbar.ui.viewmodel.KeyguardStatusBarViewModel;
91 import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel;
92 import com.android.systemui.util.ViewController;
93 import com.android.systemui.util.settings.SecureSettings;
94 
95 import kotlin.Unit;
96 
97 import kotlinx.coroutines.CoroutineDispatcher;
98 
99 import java.io.PrintWriter;
100 import java.util.ArrayList;
101 import java.util.List;
102 import java.util.concurrent.Executor;
103 import java.util.function.Consumer;
104 
105 import javax.inject.Inject;
106 
107 /** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */
108 public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> {
109     private static final String TAG = "KeyguardStatusBarViewController";
110     private static final AnimationProperties KEYGUARD_HUN_PROPERTIES =
111             new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
112 
113     private float mKeyguardHeadsUpShowingAmount = 0.0f;
114     private final AnimatableProperty mHeadsUpShowingAmountAnimation = AnimatableProperty.from(
115             "KEYGUARD_HEADS_UP_SHOWING_AMOUNT",
116             (view, aFloat) -> {
117                 mKeyguardHeadsUpShowingAmount = aFloat;
118                 updateViewState();
119             },
120             view -> mKeyguardHeadsUpShowingAmount,
121             R.id.keyguard_hun_animator_tag,
122             R.id.keyguard_hun_animator_end_tag,
123             R.id.keyguard_hun_animator_start_tag);
124 
125     private final CoroutineDispatcher mCoroutineDispatcher;
126     private final Context mContext;
127     private final CarrierTextController mCarrierTextController;
128     private final ConfigurationController mConfigurationController;
129     private final SystemStatusAnimationScheduler mAnimationScheduler;
130     private final BatteryController mBatteryController;
131     private final UserInfoController mUserInfoController;
132     private final StatusBarIconController mStatusBarIconController;
133     private final TintedIconManager.Factory mTintedIconManagerFactory;
134     private final BatteryMeterViewController mBatteryMeterViewController;
135     private final BatteryViewModel.Factory mBatteryViewModelFactory;
136     private final ShadeViewStateProvider mShadeViewStateProvider;
137     private final KeyguardStateController mKeyguardStateController;
138     private final KeyguardBypassController mKeyguardBypassController;
139     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
140     private final KeyguardStatusBarViewModel mKeyguardStatusBarViewModel;
141     private final BiometricUnlockController mBiometricUnlockController;
142     private final SysuiStatusBarStateController mStatusBarStateController;
143     private final StatusBarContentInsetsProviderStore mInsetsProviderStore;
144     private final UserManager mUserManager;
145     private final StatusBarUserChipViewModel mStatusBarUserChipViewModel;
146     private final SecureSettings mSecureSettings;
147     private final CommandQueue mCommandQueue;
148     private final Executor mMainExecutor;
149     private final Executor mBackgroundExecutor;
150     private final Object mLock = new Object();
151     private final KeyguardLogger mLogger;
152     private final CommunalSceneInteractor mCommunalSceneInteractor;
153     private final GlanceableHubToLockscreenTransitionViewModel mHubToLockscreenTransitionViewModel;
154     private final LockscreenToGlanceableHubTransitionViewModel mLockscreenToHubTransitionViewModel;
155 
156     private ViewGroup mSystemIconsContainer;
157     private final StatusOverlayHoverListenerFactory mStatusOverlayHoverListenerFactory;
158 
159     private final ConfigurationController.ConfigurationListener mConfigurationListener =
160             new ConfigurationController.ConfigurationListener() {
161                 @Override
162                 public void onDensityOrFontScaleChanged() {
163                     mView.loadDimens();
164                     // The animator is dependent on resources for offsets
165                     mSystemEventAnimator =
166                             getSystemEventAnimator(mSystemEventAnimator.isAnimationRunning());
167                 }
168 
169                 @Override
170                 public void onThemeChanged() {
171                     mView.onOverlayChanged();
172                     KeyguardStatusBarViewController.this.onThemeChanged();
173                 }
174 
175                 @Override
176                 public void onConfigChanged(Configuration newConfig) {
177                     updateUserSwitcher();
178                 }
179             };
180 
181     private final SystemStatusAnimationCallback mAnimationCallback =
182             new SystemStatusAnimationCallback() {
183                 @NonNull
184                 @Override
185                 public Animator onSystemEventAnimationFinish(boolean hasPersistentDot) {
186                     return mSystemEventAnimator.onSystemEventAnimationFinish(hasPersistentDot);
187                 }
188 
189                 @NonNull
190                 @Override
191                 public Animator onSystemEventAnimationBegin() {
192                     return mSystemEventAnimator.onSystemEventAnimationBegin();
193                 }
194             };
195 
196     private final BatteryController.BatteryStateChangeCallback mBatteryStateChangeCallback =
197             new BatteryController.BatteryStateChangeCallback() {
198                 @Override
199                 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
200                     mView.onBatteryChargingChanged(charging);
201                 }
202             };
203 
204     private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
205             (name, picture, userAccount) -> mView.onUserInfoChanged(picture);
206 
207     private final ValueAnimator.AnimatorUpdateListener mAnimatorUpdateListener =
208             animation -> {
209                 mKeyguardStatusBarAnimateAlpha =
210                         (float) ((ValueAnimator) animation).getAnimatedValue();
211                 updateViewState();
212             };
213 
214     private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
215             new KeyguardUpdateMonitorCallback() {
216                 @Override
217                 public void onBiometricAuthenticated(
218                         int userId,
219                         BiometricSourceType biometricSourceType,
220                         boolean isStrongBiometric) {
221                     if (mFirstBypassAttempt
222                             && mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
223                                     isStrongBiometric)) {
224                         mDelayShowingKeyguardStatusBar = true;
225                     }
226                 }
227 
228                 @Override
229                 public void onKeyguardVisibilityChanged(boolean visible) {
230                     if (visible) {
231                         updateUserSwitcher();
232                     }
233                 }
234 
235                 @Override
236                 public void onBiometricRunningStateChanged(
237                         boolean running,
238                         BiometricSourceType biometricSourceType) {
239                     boolean keyguardOrShadeLocked =
240                             mStatusBarState == KEYGUARD
241                                     || mStatusBarState == StatusBarState.SHADE_LOCKED;
242                     if (!running
243                             && mFirstBypassAttempt
244                             && keyguardOrShadeLocked
245                             && !mDozing
246                             && !mDelayShowingKeyguardStatusBar
247                             && !mBiometricUnlockController.isBiometricUnlock()) {
248                         mFirstBypassAttempt = false;
249                         animateKeyguardStatusBarIn();
250                     }
251                 }
252 
253                 @Override
254                 public void onFinishedGoingToSleep(int why) {
255                     mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
256                     mDelayShowingKeyguardStatusBar = false;
257                 }
258             };
259 
260     private final StatusBarStateController.StateListener mStatusBarStateListener =
261             new StatusBarStateController.StateListener() {
262                 @Override
263                 public void onStateChanged(int newState) {
264                     mStatusBarState = newState;
265                 }
266             };
267 
268     private boolean mCommunalShowing;
269 
270     private final Consumer<Boolean> mCommunalConsumer = (communalShowing) -> {
271         updateCommunalShowing(communalShowing);
272     };
273 
274     @VisibleForTesting
updateCommunalShowing(boolean communalShowing)275     void updateCommunalShowing(boolean communalShowing) {
276         mCommunalShowing = communalShowing;
277 
278         // When communal is hidden (either by transition or state change), set alpha to fully
279         // visible.
280         if (!mCommunalShowing) {
281             setAlpha(-1f);
282         }
283         updateViewState();
284     }
285 
286     private final DisableStateTracker mDisableStateTracker;
287 
288     private final List<String> mBlockedIcons = new ArrayList<>();
289     private final int mNotificationsHeaderCollideDistance;
290 
291     private boolean mBatteryListening;
292     private TintedIconManager mTintedIconManager;
293 
294     private float mKeyguardStatusBarAnimateAlpha = 1f;
295     /**
296      * If face auth with bypass is running for the first time after you turn on the screen.
297      * (From aod or screen off)
298      */
299     private boolean mFirstBypassAttempt;
300     /**
301      * If auth happens successfully during {@code mFirstBypassAttempt}, and we should wait until
302      * the keyguard is dismissed to show the status bar.
303      */
304     private boolean mDelayShowingKeyguardStatusBar;
305     private int mStatusBarState;
306     private boolean mDozing;
307     private boolean mShowingKeyguardHeadsUp;
308     private StatusBarSystemEventDefaultAnimator mSystemEventAnimator;
309     private float mSystemEventAnimatorAlpha = 1;
310     private final Consumer<Float> mToGlanceableHubStatusBarAlphaConsumer = (alpha) ->
311             updateCommunalAlphaTransition(alpha);
312 
313     private final Consumer<Float> mFromGlanceableHubStatusBarAlphaConsumer = (alpha) ->
314             updateCommunalAlphaTransition(alpha);
315 
updateCommunalAlphaTransition(float alpha)316     @VisibleForTesting  void updateCommunalAlphaTransition(float alpha) {
317         setAlpha(!mCommunalShowing || alpha == 0 ? -1 : alpha);
318     }
319 
320     /**
321      * The alpha value to be set on the View. If -1, this value is to be ignored.
322      */
323     private float mExplicitAlpha = -1f;
324 
325     @Inject
KeyguardStatusBarViewController( @ain CoroutineDispatcher dispatcher, @ShadeDisplayAware Context context, KeyguardStatusBarView view, CarrierTextController carrierTextController, ConfigurationController configurationController, SystemStatusAnimationScheduler animationScheduler, BatteryController batteryController, UserInfoController userInfoController, StatusBarIconController statusBarIconController, TintedIconManager.Factory tintedIconManagerFactory, BatteryMeterViewController batteryMeterViewController, BatteryViewModel.Factory batteryViewModelFactory, ShadeViewStateProvider shadeViewStateProvider, KeyguardStateController keyguardStateController, KeyguardBypassController bypassController, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardStatusBarViewModel keyguardStatusBarViewModel, BiometricUnlockController biometricUnlockController, SysuiStatusBarStateController statusBarStateController, StatusBarContentInsetsProviderStore statusBarContentInsetsProviderStore, UserManager userManager, StatusBarUserChipViewModel userChipViewModel, SecureSettings secureSettings, CommandQueue commandQueue, @Main Executor mainExecutor, @Background Executor backgroundExecutor, KeyguardLogger logger, StatusOverlayHoverListenerFactory statusOverlayHoverListenerFactory, CommunalSceneInteractor communalSceneInteractor, GlanceableHubToLockscreenTransitionViewModel glanceableHubToLockscreenTransitionViewModel, LockscreenToGlanceableHubTransitionViewModel lockscreenToGlanceableHubTransitionViewModel )326     public KeyguardStatusBarViewController(
327             @Main CoroutineDispatcher dispatcher,
328             @ShadeDisplayAware Context context,
329             KeyguardStatusBarView view,
330             CarrierTextController carrierTextController,
331             ConfigurationController configurationController,
332             SystemStatusAnimationScheduler animationScheduler,
333             BatteryController batteryController,
334             UserInfoController userInfoController,
335             StatusBarIconController statusBarIconController,
336             TintedIconManager.Factory tintedIconManagerFactory,
337             BatteryMeterViewController batteryMeterViewController,
338             BatteryViewModel.Factory batteryViewModelFactory,
339             ShadeViewStateProvider shadeViewStateProvider,
340             KeyguardStateController keyguardStateController,
341             KeyguardBypassController bypassController,
342             KeyguardUpdateMonitor keyguardUpdateMonitor,
343             KeyguardStatusBarViewModel keyguardStatusBarViewModel,
344             BiometricUnlockController biometricUnlockController,
345             SysuiStatusBarStateController statusBarStateController,
346             StatusBarContentInsetsProviderStore statusBarContentInsetsProviderStore,
347             UserManager userManager,
348             StatusBarUserChipViewModel userChipViewModel,
349             SecureSettings secureSettings,
350             CommandQueue commandQueue,
351             @Main Executor mainExecutor,
352             @Background Executor backgroundExecutor,
353             KeyguardLogger logger,
354             StatusOverlayHoverListenerFactory statusOverlayHoverListenerFactory,
355             CommunalSceneInteractor communalSceneInteractor,
356             GlanceableHubToLockscreenTransitionViewModel
357                     glanceableHubToLockscreenTransitionViewModel,
358             LockscreenToGlanceableHubTransitionViewModel
359                     lockscreenToGlanceableHubTransitionViewModel
360     ) {
361         super(view);
362         mCoroutineDispatcher = dispatcher;
363         mContext = context;
364         mCarrierTextController = carrierTextController;
365         mConfigurationController = configurationController;
366         mAnimationScheduler = animationScheduler;
367         mBatteryController = batteryController;
368         mUserInfoController = userInfoController;
369         mStatusBarIconController = statusBarIconController;
370         mTintedIconManagerFactory = tintedIconManagerFactory;
371         mBatteryMeterViewController = batteryMeterViewController;
372         mBatteryViewModelFactory = batteryViewModelFactory;
373         mShadeViewStateProvider = shadeViewStateProvider;
374         mKeyguardStateController = keyguardStateController;
375         mKeyguardBypassController = bypassController;
376         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
377         mKeyguardStatusBarViewModel = keyguardStatusBarViewModel;
378         mBiometricUnlockController = biometricUnlockController;
379         mStatusBarStateController = statusBarStateController;
380         mInsetsProviderStore = statusBarContentInsetsProviderStore;
381         mUserManager = userManager;
382         mStatusBarUserChipViewModel = userChipViewModel;
383         mSecureSettings = secureSettings;
384         mCommandQueue = commandQueue;
385         mMainExecutor = mainExecutor;
386         mBackgroundExecutor = backgroundExecutor;
387         mLogger = logger;
388         mCommunalSceneInteractor = communalSceneInteractor;
389         mHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel;
390         mLockscreenToHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel;
391 
392         mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
393         mKeyguardStateController.addCallback(
394                 new KeyguardStateController.Callback() {
395                     @Override
396                     public void onKeyguardFadingAwayChanged() {
397                         if (!mKeyguardStateController.isKeyguardFadingAway()) {
398                             mFirstBypassAttempt = false;
399                             mDelayShowingKeyguardStatusBar = false;
400                         }
401                     }
402                 }
403         );
404 
405         Resources r = getResources();
406         updateBlockedIcons();
407         mNotificationsHeaderCollideDistance = r.getDimensionPixelSize(
408                 R.dimen.header_notifications_collide_distance);
409 
410         mView.setKeyguardUserAvatarEnabled(
411                 !mStatusBarUserChipViewModel.getChipEnabled());
412         mSystemEventAnimator = getSystemEventAnimator(/* isAnimationRunning */ false);
413 
414         mDisableStateTracker = new DisableStateTracker(
415                 /* mask1= */ DISABLE_SYSTEM_INFO,
416                 /* mask2= */ DISABLE2_SYSTEM_ICONS,
417                 this::updateViewState
418         );
419         mStatusOverlayHoverListenerFactory = statusOverlayHoverListenerFactory;
420     }
421 
insetsProvider()422     private StatusBarContentInsetsProvider insetsProvider() {
423         return mInsetsProviderStore.forDisplay(mContext.getDisplayId());
424     }
425 
426     @Override
onInit()427     protected void onInit() {
428         super.onInit();
429         mCarrierTextController.init();
430         if (!NewStatusBarIcons.isEnabled()) {
431             mBatteryMeterViewController.init();
432         }
433         if (isMigrationEnabled()) {
434             KeyguardStatusBarViewBinder.bind(mView, mKeyguardStatusBarViewModel);
435         }
436     }
437 
438     @Override
onViewAttached()439     protected void onViewAttached() {
440         mView.init(mStatusBarUserChipViewModel);
441         mConfigurationController.addCallback(mConfigurationListener);
442         mAnimationScheduler.addCallback(mAnimationCallback);
443         mUserInfoController.addCallback(mOnUserInfoChangedListener);
444         mStatusBarStateController.addCallback(mStatusBarStateListener);
445         mStatusBarState = mStatusBarStateController.getState();
446         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
447         mDisableStateTracker.startTracking(mCommandQueue, mView.getDisplay().getDisplayId());
448         if (mTintedIconManager == null) {
449             mTintedIconManager = mTintedIconManagerFactory.create(
450                     mView.findViewById(R.id.statusIcons), StatusBarLocation.KEYGUARD);
451             mTintedIconManager.setBlockList(getBlockedIcons());
452             mStatusBarIconController.addIconGroup(mTintedIconManager);
453         } else {
454             // In the old implementation, the keyguard status bar view is never detached and
455             // re-attached, so only calling #addIconGroup when the IconManager is first created was
456             // safe and correct.
457             // In the new scene framework implementation, the keyguard status bar view *is* detached
458             // whenever the shade is opened on top of lockscreen, and then re-attached when the
459             // shade is closed. So, we need to re-add the IconManager each time we're re-attached to
460             // get icon updates.
461             if (isMigrationEnabled()) {
462                 mStatusBarIconController.addIconGroup(mTintedIconManager);
463             }
464         }
465 
466         mSystemIconsContainer = mView.findViewById(R.id.system_icons);
467         StatusOverlayHoverListener hoverListener = mStatusOverlayHoverListenerFactory
468                 .createDarkAwareListener(mSystemIconsContainer, mView.darkChangeFlow());
469         mSystemIconsContainer.setOnHoverListener(hoverListener);
470         mView.setOnApplyWindowInsetsListener(
471                 (view, windowInsets) -> mView.updateWindowInsets(windowInsets, insetsProvider()));
472         mSecureSettings.registerContentObserverForUserSync(
473                 Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON,
474                 false,
475                 mVolumeSettingObserver,
476                 UserHandle.USER_ALL);
477         updateUserSwitcher();
478         onThemeChanged();
479         if (!Flags.glanceableHubV2()) {
480             collectFlow(mView, mCommunalSceneInteractor.isCommunalVisible(), mCommunalConsumer,
481                     mCoroutineDispatcher);
482             collectFlow(mView, mLockscreenToHubTransitionViewModel.getStatusBarAlpha(),
483                     mToGlanceableHubStatusBarAlphaConsumer, mCoroutineDispatcher);
484             collectFlow(mView, mHubToLockscreenTransitionViewModel.getStatusBarAlpha(),
485                     mFromGlanceableHubStatusBarAlphaConsumer, mCoroutineDispatcher);
486         }
487         if (NewStatusBarIcons.isEnabled()) {
488             ComposeView batteryComposeView = new ComposeView(mContext);
489             UnifiedBatteryViewBinder.bind(
490                     batteryComposeView,
491                     mBatteryViewModelFactory,
492                     DarkIconInteractor.toIsAreaDark(mView.darkChangeFlow()));
493 
494             mSystemIconsContainer.addView(batteryComposeView, -1);
495         }
496     }
497 
498     @Override
onViewDetached()499     protected void onViewDetached() {
500         mSystemIconsContainer.setOnHoverListener(null);
501         mConfigurationController.removeCallback(mConfigurationListener);
502         mAnimationScheduler.removeCallback(mAnimationCallback);
503         mUserInfoController.removeCallback(mOnUserInfoChangedListener);
504         mStatusBarStateController.removeCallback(mStatusBarStateListener);
505         mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
506         mDisableStateTracker.stopTracking(mCommandQueue);
507         mSecureSettings.unregisterContentObserverSync(mVolumeSettingObserver);
508         if (mTintedIconManager != null) {
509             mStatusBarIconController.removeIconGroup(mTintedIconManager);
510         }
511     }
512 
513     /** Should be called when the theme changes. */
onThemeChanged()514     public void onThemeChanged() {
515         mView.onThemeChanged(mTintedIconManager);
516     }
517 
518     /** Sets whether user switcher is enabled. */
setKeyguardUserSwitcherEnabled(boolean enabled)519     public void setKeyguardUserSwitcherEnabled(boolean enabled) {
520         if (isMigrationEnabled()) {
521             return;
522         }
523         mView.setKeyguardUserSwitcherEnabled(enabled);
524     }
525 
526     /** Sets whether this controller should listen to battery updates. */
setBatteryListening(boolean listening)527     public void setBatteryListening(boolean listening) {
528         if (isMigrationEnabled()) {
529             return;
530         }
531 
532         if (listening == mBatteryListening) {
533             return;
534         }
535         mBatteryListening = listening;
536         if (mBatteryListening) {
537             mBatteryController.addCallback(mBatteryStateChangeCallback);
538         } else {
539             mBatteryController.removeCallback(mBatteryStateChangeCallback);
540         }
541     }
542 
543     /** Set the view to have no top clipping. */
setNoTopClipping()544     public void setNoTopClipping() {
545         mView.setTopClipping(0);
546     }
547 
548     /**
549      * Update the view's top clipping based on the value of notificationPanelTop and the view's
550      * current top.
551      *
552      * @param notificationPanelTop the current top of the notification panel view.
553      */
updateTopClipping(int notificationPanelTop)554     public void updateTopClipping(int notificationPanelTop) {
555         mView.setTopClipping(notificationPanelTop - mView.getTop());
556     }
557 
558     /** Sets the dozing state. */
setDozing(boolean dozing)559     public void setDozing(boolean dozing) {
560         if (isMigrationEnabled()) {
561             // [KeyguardStatusBarViewModel] will automatically handle dozing.
562             return;
563         }
564         mDozing = dozing;
565         updateViewState();
566     }
567 
568     /** Animate the keyguard status bar in. */
animateKeyguardStatusBarIn()569     public void animateKeyguardStatusBarIn() {
570         if (isMigrationEnabled()) {
571             return;
572         }
573 
574         mLogger.log(TAG, LogLevel.DEBUG, "animating status bar in");
575         if (mDisableStateTracker.isDisabled()) {
576             // If our view is disabled, don't allow us to animate in.
577             return;
578         }
579         mView.setVisibility(View.VISIBLE);
580         mView.setAlpha(0f);
581         ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
582         anim.addUpdateListener(mAnimatorUpdateListener);
583         anim.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
584         anim.setInterpolator(InterpolatorsAndroidX.LINEAR_OUT_SLOW_IN);
585         anim.start();
586     }
587 
588     /** Animate the keyguard status bar out. */
animateKeyguardStatusBarOut(long startDelay, long duration)589     public void animateKeyguardStatusBarOut(long startDelay, long duration) {
590         if (isMigrationEnabled()) {
591             return;
592         }
593 
594         mLogger.log(TAG, LogLevel.DEBUG, "animating status bar out");
595         ValueAnimator anim = ValueAnimator.ofFloat(mView.getAlpha(), 0f);
596         anim.addUpdateListener(mAnimatorUpdateListener);
597         anim.setStartDelay(startDelay);
598         anim.setDuration(duration);
599         anim.setInterpolator(InterpolatorsAndroidX.LINEAR_OUT_SLOW_IN);
600         anim.addListener(new AnimatorListenerAdapter() {
601             @Override
602             public void onAnimationEnd(Animator animation) {
603                 mView.setVisibility(View.INVISIBLE);
604                 mView.setAlpha(1f);
605                 mKeyguardStatusBarAnimateAlpha = 1f;
606             }
607         });
608         anim.start();
609     }
610 
611     /**
612      * Updates the {@link KeyguardStatusBarView} state based on what the
613      * {@link ShadeViewController.NotificationPanelViewStateProvider} and other
614      * controllers provide.
615      */
updateViewState()616     public void updateViewState() {
617         if (!isKeyguardShowing()) {
618             return;
619         }
620         if (isMigrationEnabled()) {
621             // [KeyguardStatusBarViewBinder] will handle view state updates.
622             return;
623         }
624 
625         float alphaQsExpansion = 1 - Math.min(
626                 1, mShadeViewStateProvider.getLockscreenShadeDragProgress() * 2);
627 
628         float newAlpha;
629         if (mExplicitAlpha != -1) {
630             newAlpha = mExplicitAlpha;
631         } else {
632             newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
633                     * mKeyguardStatusBarAnimateAlpha
634                     * (1.0f - mKeyguardHeadsUpShowingAmount);
635         }
636 
637         if (mSystemEventAnimator.isAnimationRunning()) {
638             newAlpha = Math.min(newAlpha, mSystemEventAnimatorAlpha);
639         } else {
640             mView.setTranslationX(0);
641         }
642 
643         boolean hideForBypass =
644                 mFirstBypassAttempt && mKeyguardUpdateMonitor.shouldListenForFace()
645                         || mDelayShowingKeyguardStatusBar;
646         int newVisibility =
647                 newAlpha != 0f
648                         && !mDozing
649                         && !hideForBypass
650                         && !mDisableStateTracker.isDisabled()
651                         && (Flags.glanceableHubV2() || (!mCommunalShowing || mExplicitAlpha != -1))
652                         ? View.VISIBLE : View.INVISIBLE;
653 
654         updateViewState(newAlpha, newVisibility);
655     }
656 
657     /**
658      * Updates the {@link KeyguardStatusBarView} state based on the provided values.
659      */
updateViewState(float alpha, int visibility)660     public void updateViewState(float alpha, int visibility) {
661         if (isMigrationEnabled()) {
662             // [KeyguardStatusBarViewBinder] will handle view state updates.
663             return;
664         }
665 
666         if (mDisableStateTracker.isDisabled()) {
667             visibility = View.INVISIBLE;
668         }
669         mView.setAlpha(alpha);
670         mView.setVisibility(visibility);
671     }
672 
673     /**
674      * Passes the given {@link DisplayCutout} to the view.
675      *
676      * <p>This isn't needed when the view is part of a real view hierarchy. Only call this when the
677      * view is added to a Compose hierarchy where it doesn't actually receive any callback to its
678      * {@code OnApplyWindowInsetsListener}s.
679      */
setDisplayCutout(@ullable DisplayCutout displayCutout)680     public void setDisplayCutout(@Nullable DisplayCutout displayCutout) {
681         mView.setDisplayCutout(displayCutout, insetsProvider());
682     }
683 
684     /**
685      * @return the alpha to be used to fade out the contents on Keyguard (status bar, bottom area)
686      * during swiping up.
687      */
getKeyguardContentsAlpha()688     private float getKeyguardContentsAlpha() {
689         float alpha;
690         if (isKeyguardShowing()) {
691             // When on Keyguard, we hide the header as soon as we expanded close enough to the
692             // header
693             alpha = mShadeViewStateProvider.getPanelViewExpandedHeight()
694                     / (mView.getHeight() + mNotificationsHeaderCollideDistance);
695         } else {
696             // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
697             // soon as we start translating the stack.
698             alpha = mShadeViewStateProvider.getPanelViewExpandedHeight()
699                     / mView.getHeight();
700         }
701         alpha = MathUtils.saturate(alpha);
702         alpha = (float) Math.pow(alpha, 0.75);
703         return alpha;
704     }
705 
706     /**
707      * Updates visibility of the user switcher button based on {@link android.os.UserManager} state.
708      */
updateUserSwitcher()709     private void updateUserSwitcher() {
710         if (updateUserSwitcherBackground()) {
711             mBackgroundExecutor.execute(() -> {
712                 final boolean isUserSwitcherEnabled = mUserManager.isUserSwitcherEnabled(
713                         getResources().getBoolean(R.bool.qs_show_user_switcher_for_single_user));
714                 mMainExecutor.execute(() -> {
715                     mView.setUserSwitcherEnabled(isUserSwitcherEnabled);
716                 });
717             });
718         } else {
719             mView.setUserSwitcherEnabled(mUserManager.isUserSwitcherEnabled(
720                     getResources().getBoolean(R.bool.qs_show_user_switcher_for_single_user)));
721         }
722     }
723 
724     @VisibleForTesting
updateBlockedIcons()725     void updateBlockedIcons() {
726         List<String> newBlockList = StatusBarIconBlocklistKt
727                 .getStatusBarIconBlocklist(getResources(), mSecureSettings);
728 
729         synchronized (mLock) {
730             mBlockedIcons.clear();
731             mBlockedIcons.addAll(newBlockList);
732         }
733 
734         mMainExecutor.execute(() -> {
735             if (mTintedIconManager != null) {
736                 mTintedIconManager.setBlockList(getBlockedIcons());
737             }
738         });
739     }
740 
741     @VisibleForTesting
getBlockedIcons()742     List<String> getBlockedIcons() {
743         synchronized (mLock) {
744             return new ArrayList<>(mBlockedIcons);
745         }
746     }
747 
748     /**
749       Update {@link KeyguardStatusBarView}'s visibility based on whether keyguard is showing and
750      * whether heads up is visible.
751      */
updateForHeadsUp()752     public void updateForHeadsUp() {
753         // [KeyguardStatusBarViewBinder] handles visibility when SceneContainerFlag is on.
754         SceneContainerFlag.assertInLegacyMode();
755         updateForHeadsUp(true);
756     }
757 
758     @VisibleForTesting
updateForHeadsUp(boolean animate)759     void updateForHeadsUp(boolean animate) {
760         boolean showingKeyguardHeadsUp =
761                 isKeyguardShowing() && mShadeViewStateProvider.shouldHeadsUpBeVisible();
762         if (mShowingKeyguardHeadsUp != showingKeyguardHeadsUp) {
763             mShowingKeyguardHeadsUp = showingKeyguardHeadsUp;
764             if (isKeyguardShowing()) {
765                 PropertyAnimator.setProperty(
766                         mView,
767                         mHeadsUpShowingAmountAnimation,
768                         showingKeyguardHeadsUp ? 1.0f : 0.0f,
769                         KEYGUARD_HUN_PROPERTIES,
770                         animate);
771             } else {
772                 PropertyAnimator.applyImmediately(mView, mHeadsUpShowingAmountAnimation, 0.0f);
773             }
774         }
775     }
776 
isKeyguardShowing()777     private boolean isKeyguardShowing() {
778         return mStatusBarState == KEYGUARD;
779     }
780 
781     /** */
dump(PrintWriter pw, String[] args)782     public void dump(PrintWriter pw, String[] args) {
783         pw.println("KeyguardStatusBarView:");
784         pw.println("  mBatteryListening: " + mBatteryListening);
785         pw.println("  mExplicitAlpha: " + mExplicitAlpha);
786         pw.println("  alpha: " + mView.getAlpha());
787         pw.println("  visibility: " + mView.getVisibility());
788         mView.dump(pw, args);
789     }
790 
791     /**
792      * Sets the alpha to be set on the view.
793      *
794      * @param alpha a value between 0 and 1. -1 if the value is to be reset/ignored.
795      */
setAlpha(float alpha)796     public void setAlpha(float alpha) {
797         if (isMigrationEnabled()) {
798             // [KeyguardStatusBarViewBinder] will handle view state updates.
799             return;
800         }
801 
802         mExplicitAlpha = alpha;
803         updateViewState();
804     }
805 
isMigrationEnabled()806     private boolean isMigrationEnabled() {
807         return SceneContainerFlag.isEnabled();
808     }
809 
810     private final ContentObserver mVolumeSettingObserver = new ContentObserver(null) {
811         @Override
812         public void onChange(boolean selfChange) {
813             updateBlockedIcons();
814         }
815     };
816 
getSystemEventAnimator(boolean isAnimationRunning)817     private StatusBarSystemEventDefaultAnimator getSystemEventAnimator(boolean isAnimationRunning) {
818         return new StatusBarSystemEventDefaultAnimator(getResources(), (alpha) -> {
819             mSystemEventAnimatorAlpha = alpha;
820             updateViewState();
821             return Unit.INSTANCE;
822         }, (translationX) -> {
823             mView.setTranslationX(translationX);
824             return Unit.INSTANCE;
825         }, isAnimationRunning);
826     }
827 }
828