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