1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.systemui.statusbar.phone.fragment; 16 17 import android.annotation.Nullable; 18 import android.annotation.SuppressLint; 19 import android.app.Fragment; 20 import android.database.ContentObserver; 21 import android.os.Bundle; 22 import android.os.Parcelable; 23 import android.os.UserHandle; 24 import android.provider.Settings; 25 import android.telephony.SubscriptionManager; 26 import android.util.ArrayMap; 27 import android.util.IndentingPrintWriter; 28 import android.util.SparseArray; 29 import android.view.LayoutInflater; 30 import android.view.View; 31 import android.view.ViewGroup; 32 import android.view.ViewStub; 33 import android.widget.LinearLayout; 34 35 import androidx.annotation.VisibleForTesting; 36 import androidx.core.animation.Animator; 37 38 import com.android.app.animation.Interpolators; 39 import com.android.app.animation.InterpolatorsAndroidX; 40 import com.android.keyguard.KeyguardUpdateMonitor; 41 import com.android.systemui.Dumpable; 42 import com.android.systemui.R; 43 import com.android.systemui.dagger.qualifiers.Main; 44 import com.android.systemui.dump.DumpManager; 45 import com.android.systemui.flags.FeatureFlags; 46 import com.android.systemui.plugins.statusbar.StatusBarStateController; 47 import com.android.systemui.shade.ShadeExpansionStateManager; 48 import com.android.systemui.shade.ShadeViewController; 49 import com.android.systemui.statusbar.CommandQueue; 50 import com.android.systemui.statusbar.OperatorNameView; 51 import com.android.systemui.statusbar.OperatorNameViewController; 52 import com.android.systemui.statusbar.StatusBarState; 53 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState; 54 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback; 55 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; 56 import com.android.systemui.statusbar.phone.NotificationIconAreaController; 57 import com.android.systemui.statusbar.phone.PhoneStatusBarView; 58 import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager; 59 import com.android.systemui.statusbar.phone.StatusBarIconController; 60 import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager; 61 import com.android.systemui.statusbar.phone.StatusBarLocation; 62 import com.android.systemui.statusbar.phone.StatusBarLocationPublisher; 63 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent; 64 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent.Startable; 65 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; 66 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener; 67 import com.android.systemui.statusbar.pipeline.shared.ui.binder.CollapsedStatusBarViewBinder; 68 import com.android.systemui.statusbar.pipeline.shared.ui.binder.StatusBarVisibilityChangeListener; 69 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel; 70 import com.android.systemui.statusbar.policy.KeyguardStateController; 71 import com.android.systemui.statusbar.window.StatusBarWindowStateController; 72 import com.android.systemui.statusbar.window.StatusBarWindowStateListener; 73 import com.android.systemui.util.CarrierConfigTracker; 74 import com.android.systemui.util.CarrierConfigTracker.CarrierConfigChangedListener; 75 import com.android.systemui.util.CarrierConfigTracker.DefaultDataSubscriptionChangedListener; 76 import com.android.systemui.util.settings.SecureSettings; 77 78 import kotlin.Unit; 79 80 import java.io.PrintWriter; 81 import java.util.ArrayList; 82 import java.util.Arrays; 83 import java.util.List; 84 import java.util.Map; 85 import java.util.Set; 86 import java.util.concurrent.Executor; 87 88 /** 89 * Contains the collapsed status bar and handles hiding/showing based on disable flags 90 * and keyguard state. Also manages lifecycle to make sure the views it contains are being 91 * updated by the StatusBarIconController and DarkIconManager while it is attached. 92 */ 93 @SuppressLint("ValidFragment") 94 public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks, 95 StatusBarStateController.StateListener, 96 SystemStatusAnimationCallback, Dumpable { 97 98 public static final String TAG = "CollapsedStatusBarFragment"; 99 private static final String EXTRA_PANEL_STATE = "panel_state"; 100 public static final String STATUS_BAR_ICON_MANAGER_TAG = "status_bar_icon_manager"; 101 public static final int FADE_IN_DURATION = 320; 102 public static final int FADE_OUT_DURATION = 160; 103 public static final int FADE_IN_DELAY = 50; 104 private static final int SOURCE_SYSTEM_EVENT_ANIMATOR = 1; 105 private static final int SOURCE_OTHER = 2; 106 private StatusBarFragmentComponent mStatusBarFragmentComponent; 107 private PhoneStatusBarView mStatusBar; 108 private final StatusBarStateController mStatusBarStateController; 109 private final KeyguardStateController mKeyguardStateController; 110 private final ShadeViewController mShadeViewController; 111 private MultiSourceMinAlphaController mEndSideAlphaController; 112 private LinearLayout mEndSideContent; 113 private View mClockView; 114 private View mOngoingCallChip; 115 private View mNotificationIconAreaInner; 116 // Visibilities come in from external system callers via disable flags, but we also sometimes 117 // modify the visibilities internally. We need to store both so that we don't accidentally 118 // propagate our internally modified flags for too long. 119 private StatusBarVisibilityModel mLastSystemVisibility = 120 StatusBarVisibilityModel.createDefaultModel(); 121 private StatusBarVisibilityModel mLastModifiedVisibility = 122 StatusBarVisibilityModel.createDefaultModel(); 123 private DarkIconManager mDarkIconManager; 124 private final StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory; 125 private final CommandQueue mCommandQueue; 126 private final CollapsedStatusBarFragmentLogger mCollapsedStatusBarFragmentLogger; 127 private final OperatorNameViewController.Factory mOperatorNameViewControllerFactory; 128 private final OngoingCallController mOngoingCallController; 129 private final SystemStatusAnimationScheduler mAnimationScheduler; 130 private final StatusBarLocationPublisher mLocationPublisher; 131 private final FeatureFlags mFeatureFlags; 132 private final NotificationIconAreaController mNotificationIconAreaController; 133 private final ShadeExpansionStateManager mShadeExpansionStateManager; 134 private final StatusBarIconController mStatusBarIconController; 135 private final CarrierConfigTracker mCarrierConfigTracker; 136 private final CollapsedStatusBarViewModel mCollapsedStatusBarViewModel; 137 private final CollapsedStatusBarViewBinder mCollapsedStatusBarViewBinder; 138 private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; 139 private final StatusBarIconController.DarkIconManager.Factory mDarkIconManagerFactory; 140 private final SecureSettings mSecureSettings; 141 private final Executor mMainExecutor; 142 private final DumpManager mDumpManager; 143 private final StatusBarWindowStateController mStatusBarWindowStateController; 144 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; 145 146 private List<String> mBlockedIcons = new ArrayList<>(); 147 private Map<Startable, Startable.State> mStartableStates = new ArrayMap<>(); 148 149 private final OngoingCallListener mOngoingCallListener = new OngoingCallListener() { 150 @Override 151 public void onOngoingCallStateChanged(boolean animate) { 152 updateStatusBarVisibilities(animate); 153 } 154 }; 155 private OperatorNameViewController mOperatorNameViewController; 156 private StatusBarSystemEventDefaultAnimator mSystemEventAnimator; 157 158 private final CarrierConfigChangedListener mCarrierConfigCallback = 159 new CarrierConfigChangedListener() { 160 @Override 161 public void onCarrierConfigChanged() { 162 if (mOperatorNameViewController == null) { 163 initOperatorName(); 164 } else { 165 // Already initialized, KeyguardUpdateMonitorCallback will handle the update 166 } 167 } 168 }; 169 170 private final DefaultDataSubscriptionChangedListener mDefaultDataListener = 171 new DefaultDataSubscriptionChangedListener() { 172 @Override 173 public void onDefaultSubscriptionChanged(int subId) { 174 if (mOperatorNameViewController == null) { 175 initOperatorName(); 176 } 177 } 178 }; 179 180 /** 181 * Whether we've launched the secure camera over the lockscreen, but haven't yet received a 182 * status bar window state change afterward. 183 * 184 * We wait for this state change (which will tell us whether to show/hide the status bar icons) 185 * so that there is no flickering/jump cutting during the camera launch. 186 */ 187 private boolean mWaitingForWindowStateChangeAfterCameraLaunch = false; 188 189 /** 190 * True when a transition from lockscreen to dream has started, but haven't yet received a 191 * status bar window state change afterward. 192 * 193 * Similar to [mWaitingForWindowStateChangeAfterCameraLaunch]. 194 */ 195 private boolean mTransitionFromLockscreenToDreamStarted = false; 196 197 /** 198 * Listener that updates {@link #mWaitingForWindowStateChangeAfterCameraLaunch} when it receives 199 * a new status bar window state. 200 */ 201 private final StatusBarWindowStateListener mStatusBarWindowStateListener = state -> { 202 mWaitingForWindowStateChangeAfterCameraLaunch = false; 203 mTransitionFromLockscreenToDreamStarted = false; 204 }; 205 206 @SuppressLint("ValidFragment") CollapsedStatusBarFragment( StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory, OngoingCallController ongoingCallController, SystemStatusAnimationScheduler animationScheduler, StatusBarLocationPublisher locationPublisher, NotificationIconAreaController notificationIconAreaController, ShadeExpansionStateManager shadeExpansionStateManager, FeatureFlags featureFlags, StatusBarIconController statusBarIconController, StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory, CollapsedStatusBarViewModel collapsedStatusBarViewModel, CollapsedStatusBarViewBinder collapsedStatusBarViewBinder, StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager, KeyguardStateController keyguardStateController, ShadeViewController shadeViewController, StatusBarStateController statusBarStateController, CommandQueue commandQueue, CarrierConfigTracker carrierConfigTracker, CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, OperatorNameViewController.Factory operatorNameViewControllerFactory, SecureSettings secureSettings, @Main Executor mainExecutor, DumpManager dumpManager, StatusBarWindowStateController statusBarWindowStateController, KeyguardUpdateMonitor keyguardUpdateMonitor )207 public CollapsedStatusBarFragment( 208 StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory, 209 OngoingCallController ongoingCallController, 210 SystemStatusAnimationScheduler animationScheduler, 211 StatusBarLocationPublisher locationPublisher, 212 NotificationIconAreaController notificationIconAreaController, 213 ShadeExpansionStateManager shadeExpansionStateManager, 214 FeatureFlags featureFlags, 215 StatusBarIconController statusBarIconController, 216 StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory, 217 CollapsedStatusBarViewModel collapsedStatusBarViewModel, 218 CollapsedStatusBarViewBinder collapsedStatusBarViewBinder, 219 StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager, 220 KeyguardStateController keyguardStateController, 221 ShadeViewController shadeViewController, 222 StatusBarStateController statusBarStateController, 223 CommandQueue commandQueue, 224 CarrierConfigTracker carrierConfigTracker, 225 CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger, 226 OperatorNameViewController.Factory operatorNameViewControllerFactory, 227 SecureSettings secureSettings, 228 @Main Executor mainExecutor, 229 DumpManager dumpManager, 230 StatusBarWindowStateController statusBarWindowStateController, 231 KeyguardUpdateMonitor keyguardUpdateMonitor 232 ) { 233 mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory; 234 mOngoingCallController = ongoingCallController; 235 mAnimationScheduler = animationScheduler; 236 mLocationPublisher = locationPublisher; 237 mNotificationIconAreaController = notificationIconAreaController; 238 mShadeExpansionStateManager = shadeExpansionStateManager; 239 mFeatureFlags = featureFlags; 240 mStatusBarIconController = statusBarIconController; 241 mCollapsedStatusBarViewModel = collapsedStatusBarViewModel; 242 mCollapsedStatusBarViewBinder = collapsedStatusBarViewBinder; 243 mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager; 244 mDarkIconManagerFactory = darkIconManagerFactory; 245 mKeyguardStateController = keyguardStateController; 246 mShadeViewController = shadeViewController; 247 mStatusBarStateController = statusBarStateController; 248 mCommandQueue = commandQueue; 249 mCarrierConfigTracker = carrierConfigTracker; 250 mCollapsedStatusBarFragmentLogger = collapsedStatusBarFragmentLogger; 251 mOperatorNameViewControllerFactory = operatorNameViewControllerFactory; 252 mSecureSettings = secureSettings; 253 mMainExecutor = mainExecutor; 254 mDumpManager = dumpManager; 255 mStatusBarWindowStateController = statusBarWindowStateController; 256 mKeyguardUpdateMonitor = keyguardUpdateMonitor; 257 } 258 259 @Override onCreate(Bundle savedInstanceState)260 public void onCreate(Bundle savedInstanceState) { 261 super.onCreate(savedInstanceState); 262 mStatusBarWindowStateController.addListener(mStatusBarWindowStateListener); 263 } 264 265 @Override onDestroy()266 public void onDestroy() { 267 super.onDestroy(); 268 mStatusBarWindowStateController.removeListener(mStatusBarWindowStateListener); 269 } 270 271 @Override onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState)272 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 273 Bundle savedInstanceState) { 274 return inflater.inflate(R.layout.status_bar, container, false); 275 } 276 277 @Override onViewCreated(View view, @Nullable Bundle savedInstanceState)278 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 279 super.onViewCreated(view, savedInstanceState); 280 mDumpManager.registerDumpable(getClass().getSimpleName(), this); 281 mStatusBarFragmentComponent = mStatusBarFragmentComponentFactory.create(this); 282 mStatusBarFragmentComponent.init(); 283 mStartableStates.clear(); 284 for (Startable startable : mStatusBarFragmentComponent.getStartables()) { 285 mStartableStates.put(startable, Startable.State.STARTING); 286 startable.start(); 287 mStartableStates.put(startable, Startable.State.STARTED); 288 } 289 290 mStatusBar = (PhoneStatusBarView) view; 291 View contents = mStatusBar.findViewById(R.id.status_bar_contents); 292 contents.addOnLayoutChangeListener(mStatusBarLayoutListener); 293 updateStatusBarLocation(contents.getLeft(), contents.getRight()); 294 if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) { 295 mStatusBar.restoreHierarchyState( 296 savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE)); 297 } 298 mDarkIconManager = mDarkIconManagerFactory.create( 299 view.findViewById(R.id.statusIcons), StatusBarLocation.HOME); 300 mDarkIconManager.setShouldLog(true); 301 updateBlockedIcons(); 302 mStatusBarIconController.addIconGroup(mDarkIconManager); 303 mEndSideContent = mStatusBar.findViewById(R.id.status_bar_end_side_content); 304 mEndSideAlphaController = new MultiSourceMinAlphaController(mEndSideContent); 305 mClockView = mStatusBar.findViewById(R.id.clock); 306 mOngoingCallChip = mStatusBar.findViewById(R.id.ongoing_call_chip); 307 showEndSideContent(false); 308 showClock(false); 309 initOperatorName(); 310 initNotificationIconArea(); 311 mSystemEventAnimator = getSystemEventAnimator(); 312 mCarrierConfigTracker.addCallback(mCarrierConfigCallback); 313 mCarrierConfigTracker.addDefaultDataSubscriptionChangedListener(mDefaultDataListener); 314 315 mCollapsedStatusBarViewBinder.bind( 316 mStatusBar, mCollapsedStatusBarViewModel, mStatusBarVisibilityChangeListener); 317 } 318 319 @Override onCameraLaunchGestureDetected(int source)320 public void onCameraLaunchGestureDetected(int source) { 321 mWaitingForWindowStateChangeAfterCameraLaunch = true; 322 } 323 324 @VisibleForTesting updateBlockedIcons()325 void updateBlockedIcons() { 326 mBlockedIcons.clear(); 327 328 // Reload the blocklist from res 329 List<String> blockList = Arrays.asList(getResources().getStringArray( 330 R.array.config_collapsed_statusbar_icon_blocklist)); 331 String vibrateIconSlot = getString(com.android.internal.R.string.status_bar_volume); 332 boolean showVibrateIcon = 333 mSecureSettings.getIntForUser( 334 Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 335 0, 336 UserHandle.USER_CURRENT) == 0; 337 338 // Filter out vibrate icon from the blocklist if the setting is on 339 for (int i = 0; i < blockList.size(); i++) { 340 if (blockList.get(i).equals(vibrateIconSlot)) { 341 if (showVibrateIcon) { 342 mBlockedIcons.add(blockList.get(i)); 343 } 344 } else { 345 mBlockedIcons.add(blockList.get(i)); 346 } 347 } 348 349 mMainExecutor.execute(() -> mDarkIconManager.setBlockList(mBlockedIcons)); 350 } 351 352 @VisibleForTesting getBlockedIcons()353 List<String> getBlockedIcons() { 354 return mBlockedIcons; 355 } 356 357 @Override onSaveInstanceState(Bundle outState)358 public void onSaveInstanceState(Bundle outState) { 359 super.onSaveInstanceState(outState); 360 SparseArray<Parcelable> states = new SparseArray<>(); 361 mStatusBar.saveHierarchyState(states); 362 outState.putSparseParcelableArray(EXTRA_PANEL_STATE, states); 363 } 364 365 @Override onResume()366 public void onResume() { 367 super.onResume(); 368 mCommandQueue.addCallback(this); 369 mStatusBarStateController.addCallback(this); 370 initOngoingCallChip(); 371 mAnimationScheduler.addCallback(this); 372 373 mSecureSettings.registerContentObserverForUser( 374 Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 375 false, 376 mVolumeSettingObserver, 377 UserHandle.USER_ALL); 378 } 379 380 @Override onPause()381 public void onPause() { 382 super.onPause(); 383 mCommandQueue.removeCallback(this); 384 mStatusBarStateController.removeCallback(this); 385 mOngoingCallController.removeCallback(mOngoingCallListener); 386 mAnimationScheduler.removeCallback(this); 387 mSecureSettings.unregisterContentObserver(mVolumeSettingObserver); 388 } 389 390 @Override onDestroyView()391 public void onDestroyView() { 392 super.onDestroyView(); 393 mStatusBarIconController.removeIconGroup(mDarkIconManager); 394 mCarrierConfigTracker.removeCallback(mCarrierConfigCallback); 395 mCarrierConfigTracker.removeDataSubscriptionChangedListener(mDefaultDataListener); 396 397 for (Startable startable : mStatusBarFragmentComponent.getStartables()) { 398 mStartableStates.put(startable, Startable.State.STOPPING); 399 startable.stop(); 400 mStartableStates.put(startable, Startable.State.STOPPED); 401 } 402 mDumpManager.unregisterDumpable(getClass().getSimpleName()); 403 } 404 405 /** Initializes views related to the notification icon area. */ initNotificationIconArea()406 public void initNotificationIconArea() { 407 ViewGroup notificationIconArea = mStatusBar.findViewById(R.id.notification_icon_area); 408 mNotificationIconAreaInner = 409 mNotificationIconAreaController.getNotificationInnerAreaView(); 410 if (mNotificationIconAreaInner.getParent() != null) { 411 ((ViewGroup) mNotificationIconAreaInner.getParent()) 412 .removeView(mNotificationIconAreaInner); 413 } 414 notificationIconArea.addView(mNotificationIconAreaInner); 415 416 updateNotificationIconAreaAndCallChip(/* animate= */ false); 417 } 418 419 /** 420 * Returns the dagger component for this fragment. 421 * 422 * TODO(b/205609837): Eventually, the dagger component should encapsulate all status bar 423 * fragment functionality and we won't need to expose it here anymore. 424 */ 425 @Nullable getStatusBarFragmentComponent()426 public StatusBarFragmentComponent getStatusBarFragmentComponent() { 427 return mStatusBarFragmentComponent; 428 } 429 430 private StatusBarVisibilityChangeListener mStatusBarVisibilityChangeListener = 431 new StatusBarVisibilityChangeListener() { 432 @Override 433 public void onStatusBarVisibilityMaybeChanged() { 434 updateStatusBarVisibilities(/* animate= */ true); 435 } 436 437 @Override 438 public void onTransitionFromLockscreenToDreamStarted() { 439 mTransitionFromLockscreenToDreamStarted = true; 440 } 441 }; 442 443 @Override disable(int displayId, int state1, int state2, boolean animate)444 public void disable(int displayId, int state1, int state2, boolean animate) { 445 if (displayId != getContext().getDisplayId()) { 446 return; 447 } 448 mCollapsedStatusBarFragmentLogger 449 .logDisableFlagChange(new DisableState(state1, state2)); 450 mLastSystemVisibility = 451 StatusBarVisibilityModel.createModelFromFlags(state1, state2); 452 updateStatusBarVisibilities(animate); 453 } 454 updateStatusBarVisibilities(boolean animate)455 private void updateStatusBarVisibilities(boolean animate) { 456 StatusBarVisibilityModel previousModel = mLastModifiedVisibility; 457 StatusBarVisibilityModel newModel = calculateInternalModel(mLastSystemVisibility); 458 mCollapsedStatusBarFragmentLogger.logVisibilityModel(newModel); 459 mLastModifiedVisibility = newModel; 460 461 if (newModel.getShowSystemInfo() != previousModel.getShowSystemInfo()) { 462 if (newModel.getShowSystemInfo()) { 463 showEndSideContent(animate); 464 showOperatorName(animate); 465 } else { 466 hideEndSideContent(animate); 467 hideOperatorName(animate); 468 } 469 } 470 471 // The ongoing call chip and notification icon visibilities are intertwined, so update both 472 // if either change. 473 if (newModel.getShowNotificationIcons() != previousModel.getShowNotificationIcons() 474 || newModel.getShowOngoingCallChip() != previousModel.getShowOngoingCallChip()) { 475 updateNotificationIconAreaAndCallChip(animate); 476 } 477 478 // The clock may have already been hidden, but we might want to shift its 479 // visibility to GONE from INVISIBLE or vice versa 480 if (newModel.getShowClock() != previousModel.getShowClock() 481 || mClockView.getVisibility() != clockHiddenMode()) { 482 if (newModel.getShowClock()) { 483 showClock(animate); 484 } else { 485 hideClock(animate); 486 } 487 } 488 } 489 calculateInternalModel( StatusBarVisibilityModel externalModel)490 private StatusBarVisibilityModel calculateInternalModel( 491 StatusBarVisibilityModel externalModel) { 492 boolean headsUpVisible = 493 mStatusBarFragmentComponent.getHeadsUpAppearanceController().shouldBeVisible(); 494 495 if (!mKeyguardStateController.isLaunchTransitionFadingAway() 496 && !mKeyguardStateController.isKeyguardFadingAway() 497 && shouldHideStatusBar() 498 && !(mStatusBarStateController.getState() == StatusBarState.KEYGUARD 499 && headsUpVisible)) { 500 // Hide everything 501 return new StatusBarVisibilityModel( 502 /* showClock= */ false, 503 /* showNotificationIcons= */ false, 504 /* showOngoingCallChip= */ false, 505 /* showSystemInfo= */ false); 506 } 507 508 boolean showClock = externalModel.getShowClock() && !headsUpVisible; 509 boolean showOngoingCallChip = mOngoingCallController.hasOngoingCall() && !headsUpVisible; 510 return new StatusBarVisibilityModel( 511 showClock, 512 externalModel.getShowNotificationIcons(), 513 showOngoingCallChip, 514 externalModel.getShowSystemInfo()); 515 } 516 517 /** 518 * Updates the visibility of the notification icon area and ongoing call chip based on disabled1 519 * state. 520 */ updateNotificationIconAreaAndCallChip(boolean animate)521 private void updateNotificationIconAreaAndCallChip(boolean animate) { 522 StatusBarVisibilityModel visibilityModel = mLastModifiedVisibility; 523 boolean disableNotifications = !visibilityModel.getShowNotificationIcons(); 524 boolean hasOngoingCall = visibilityModel.getShowOngoingCallChip(); 525 526 // Hide notifications if the disable flag is set or we have an ongoing call. 527 if (disableNotifications || hasOngoingCall) { 528 hideNotificationIconArea(animate); 529 } else { 530 showNotificationIconArea(animate); 531 } 532 533 // Show the ongoing call chip only if there is an ongoing call *and* notification icons 534 // are allowed. (The ongoing call chip occupies the same area as the notification icons, 535 // so if the icons are disabled then the call chip should be, too.) 536 boolean showOngoingCallChip = hasOngoingCall && !disableNotifications; 537 if (showOngoingCallChip) { 538 showOngoingCallChip(animate); 539 } else { 540 hideOngoingCallChip(animate); 541 } 542 mOngoingCallController.notifyChipVisibilityChanged(showOngoingCallChip); 543 } 544 shouldHideStatusBar()545 private boolean shouldHideStatusBar() { 546 if (!mShadeExpansionStateManager.isClosed() 547 && mShadeViewController.shouldHideStatusBarIconsWhenExpanded()) { 548 return true; 549 } 550 551 // When launching the camera over the lockscreen, the icons become visible momentarily 552 // before animating out, since we're not yet aware that the launching camera activity is 553 // fullscreen. Even once the activity finishes launching, it takes a short time before WM 554 // decides that the top app wants to hide the icons and tells us to hide them. To ensure 555 // that this high-visibility animation is smooth, keep the icons hidden during a camera 556 // launch until we receive a window state change which indicates that the activity is done 557 // launching and WM has decided to show/hide the icons. For extra safety (to ensure the 558 // icons don't remain hidden somehow) we double check that the camera is still showing, the 559 // status bar window isn't hidden, and we're still occluded as well, though these checks 560 // are typically unnecessary. 561 // 562 // TODO(b/273314977): Can this be deleted now that we have the 563 // [isTransitioningFromLockscreenToOccluded] check below? 564 final boolean hideIconsForSecureCamera = 565 (mWaitingForWindowStateChangeAfterCameraLaunch || 566 !mStatusBarWindowStateController.windowIsShowing()) && 567 mKeyguardUpdateMonitor.isSecureCameraLaunchedOverKeyguard() && 568 mKeyguardStateController.isOccluded(); 569 570 if (hideIconsForSecureCamera) { 571 return true; 572 } 573 574 // Similar to [hideIconsForSecureCamera]: When dream is launched over lockscreen, the icons 575 // are momentarily visible because the dream animation has finished, but SysUI has not been 576 // informed that the dream is full-screen. For extra safety, we double-check that we're 577 // still dreaming. 578 final boolean hideIconsForDream = 579 mTransitionFromLockscreenToDreamStarted 580 && mKeyguardUpdateMonitor.isDreaming() 581 && mKeyguardStateController.isOccluded(); 582 if (hideIconsForDream) { 583 return true; 584 } 585 586 // While the status bar is transitioning from lockscreen to an occluded, we don't yet know 587 // if the occluding activity is fullscreen or not. If it *is* fullscreen, we don't want to 588 // briefly show the status bar just to immediately hide it again. So, we wait for the 589 // transition to occluding to finish before allowing us to potentially show the status bar 590 // again. (This status bar is always hidden on keyguard, so it's safe to continue hiding it 591 // during this transition.) See b/273314977. 592 if (mCollapsedStatusBarViewModel.isTransitioningFromLockscreenToOccluded().getValue()) { 593 return true; 594 } 595 596 return mStatusBarHideIconsForBouncerManager.getShouldHideStatusBarIconsForBouncer(); 597 } 598 hideEndSideContent(boolean animate)599 private void hideEndSideContent(boolean animate) { 600 if (!animate) { 601 mEndSideAlphaController.setAlpha(/*alpha*/ 0f, SOURCE_OTHER); 602 } else { 603 mEndSideAlphaController.animateToAlpha(/*alpha*/ 0f, SOURCE_OTHER, FADE_OUT_DURATION, 604 InterpolatorsAndroidX.ALPHA_OUT, /*startDelay*/ 0); 605 } 606 } 607 showEndSideContent(boolean animate)608 private void showEndSideContent(boolean animate) { 609 if (!animate) { 610 mEndSideAlphaController.setAlpha(1f, SOURCE_OTHER); 611 return; 612 } 613 if (mKeyguardStateController.isKeyguardFadingAway()) { 614 mEndSideAlphaController.animateToAlpha(/*alpha*/ 1f, SOURCE_OTHER, 615 mKeyguardStateController.getKeyguardFadingAwayDuration(), 616 InterpolatorsAndroidX.LINEAR_OUT_SLOW_IN, 617 mKeyguardStateController.getKeyguardFadingAwayDelay()); 618 } else { 619 mEndSideAlphaController.animateToAlpha(/*alpha*/ 1f, SOURCE_OTHER, FADE_IN_DURATION, 620 InterpolatorsAndroidX.ALPHA_IN, FADE_IN_DELAY); 621 } 622 } 623 hideClock(boolean animate)624 private void hideClock(boolean animate) { 625 animateHiddenState(mClockView, clockHiddenMode(), animate); 626 } 627 showClock(boolean animate)628 private void showClock(boolean animate) { 629 animateShow(mClockView, animate); 630 } 631 632 /** Hides the ongoing call chip. */ hideOngoingCallChip(boolean animate)633 public void hideOngoingCallChip(boolean animate) { 634 animateHiddenState(mOngoingCallChip, View.GONE, animate); 635 } 636 637 /** Displays the ongoing call chip. */ showOngoingCallChip(boolean animate)638 public void showOngoingCallChip(boolean animate) { 639 animateShow(mOngoingCallChip, animate); 640 } 641 642 /** 643 * If panel is expanded/expanding it usually means QS shade is opening, so 644 * don't set the clock GONE otherwise it'll mess up the animation. 645 */ clockHiddenMode()646 private int clockHiddenMode() { 647 if (!mShadeExpansionStateManager.isClosed() && !mKeyguardStateController.isShowing() 648 && !mStatusBarStateController.isDozing()) { 649 return View.INVISIBLE; 650 } 651 return View.GONE; 652 } 653 hideNotificationIconArea(boolean animate)654 public void hideNotificationIconArea(boolean animate) { 655 animateHide(mNotificationIconAreaInner, animate); 656 } 657 showNotificationIconArea(boolean animate)658 public void showNotificationIconArea(boolean animate) { 659 animateShow(mNotificationIconAreaInner, animate); 660 } 661 hideOperatorName(boolean animate)662 public void hideOperatorName(boolean animate) { 663 if (mOperatorNameViewController != null) { 664 animateHide(mOperatorNameViewController.getView(), animate); 665 } 666 } 667 showOperatorName(boolean animate)668 public void showOperatorName(boolean animate) { 669 if (mOperatorNameViewController != null) { 670 animateShow(mOperatorNameViewController.getView(), animate); 671 } 672 } 673 674 /** 675 * Animate a view to INVISIBLE or GONE 676 */ animateHiddenState(final View v, int state, boolean animate)677 private void animateHiddenState(final View v, int state, boolean animate) { 678 v.animate().cancel(); 679 if (!animate) { 680 v.setAlpha(0f); 681 v.setVisibility(state); 682 return; 683 } 684 685 v.animate() 686 .alpha(0f) 687 .setDuration(FADE_OUT_DURATION) 688 .setStartDelay(0) 689 .setInterpolator(Interpolators.ALPHA_OUT) 690 .withEndAction(() -> v.setVisibility(state)); 691 } 692 693 /** 694 * Hides a view. 695 */ animateHide(final View v, boolean animate)696 private void animateHide(final View v, boolean animate) { 697 animateHiddenState(v, View.INVISIBLE, animate); 698 } 699 700 /** 701 * Shows a view, and synchronizes the animation with Keyguard exit animations, if applicable. 702 */ animateShow(View v, boolean animate)703 private void animateShow(View v, boolean animate) { 704 v.animate().cancel(); 705 v.setVisibility(View.VISIBLE); 706 if (!animate) { 707 v.setAlpha(1f); 708 return; 709 } 710 v.animate() 711 .alpha(1f) 712 .setDuration(FADE_IN_DURATION) 713 .setInterpolator(Interpolators.ALPHA_IN) 714 .setStartDelay(FADE_IN_DELAY) 715 716 // We need to clean up any pending end action from animateHide if we call 717 // both hide and show in the same frame before the animation actually gets started. 718 // cancel() doesn't really remove the end action. 719 .withEndAction(null); 720 721 // Synchronize the motion with the Keyguard fading if necessary. 722 if (mKeyguardStateController.isKeyguardFadingAway()) { 723 v.animate() 724 .setDuration(mKeyguardStateController.getKeyguardFadingAwayDuration()) 725 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN) 726 .setStartDelay(mKeyguardStateController.getKeyguardFadingAwayDelay()) 727 .start(); 728 } 729 } 730 initOperatorName()731 private void initOperatorName() { 732 int subId = SubscriptionManager.getDefaultDataSubscriptionId(); 733 if (mCarrierConfigTracker.getShowOperatorNameInStatusBarConfig(subId)) { 734 ViewStub stub = mStatusBar.findViewById(R.id.operator_name); 735 mOperatorNameViewController = 736 mOperatorNameViewControllerFactory.create((OperatorNameView) stub.inflate()); 737 mOperatorNameViewController.init(); 738 // This view should not be visible on lock-screen 739 if (mKeyguardStateController.isShowing()) { 740 hideOperatorName(false); 741 } 742 } 743 } 744 initOngoingCallChip()745 private void initOngoingCallChip() { 746 mOngoingCallController.addCallback(mOngoingCallListener); 747 mOngoingCallController.setChipView(mOngoingCallChip); 748 } 749 750 @Override onStateChanged(int newState)751 public void onStateChanged(int newState) { } 752 753 @Override onDozingChanged(boolean isDozing)754 public void onDozingChanged(boolean isDozing) { 755 updateStatusBarVisibilities(/* animate= */ false); 756 } 757 758 @Nullable 759 @Override onSystemEventAnimationBegin()760 public Animator onSystemEventAnimationBegin() { 761 return mSystemEventAnimator.onSystemEventAnimationBegin(); 762 } 763 764 @Nullable 765 @Override onSystemEventAnimationFinish(boolean hasPersistentDot)766 public Animator onSystemEventAnimationFinish(boolean hasPersistentDot) { 767 return mSystemEventAnimator.onSystemEventAnimationFinish(hasPersistentDot); 768 } 769 getSystemEventAnimator()770 private StatusBarSystemEventDefaultAnimator getSystemEventAnimator() { 771 return new StatusBarSystemEventDefaultAnimator(getResources(), (alpha) -> { 772 mEndSideAlphaController.setAlpha(alpha, SOURCE_SYSTEM_EVENT_ANIMATOR); 773 return Unit.INSTANCE; 774 }, (translationX) -> { 775 mEndSideContent.setTranslationX(translationX); 776 return Unit.INSTANCE; 777 }, /*isAnimationRunning*/ false); 778 } 779 updateStatusBarLocation(int left, int right)780 private void updateStatusBarLocation(int left, int right) { 781 int leftMargin = left - mStatusBar.getLeft(); 782 int rightMargin = mStatusBar.getRight() - right; 783 784 mLocationPublisher.updateStatusBarMargin(leftMargin, rightMargin); 785 } 786 787 private final ContentObserver mVolumeSettingObserver = new ContentObserver(null) { 788 @Override 789 public void onChange(boolean selfChange) { 790 updateBlockedIcons(); 791 } 792 }; 793 794 // Listen for view end changes of PhoneStatusBarView and publish that to the privacy dot 795 private View.OnLayoutChangeListener mStatusBarLayoutListener = 796 (view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { 797 if (left != oldLeft || right != oldRight) { 798 updateStatusBarLocation(left, right); 799 } 800 }; 801 802 @Override dump(PrintWriter printWriter, String[] args)803 public void dump(PrintWriter printWriter, String[] args) { 804 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, /* singleIndent= */" "); 805 StatusBarFragmentComponent component = mStatusBarFragmentComponent; 806 if (component == null) { 807 pw.println("StatusBarFragmentComponent is null"); 808 } else { 809 Set<Startable> startables = component.getStartables(); 810 pw.println("Startables: " + startables.size()); 811 pw.increaseIndent(); 812 for (Startable startable : startables) { 813 Startable.State startableState = mStartableStates.getOrDefault(startable, 814 Startable.State.NONE); 815 pw.println(startable + ", state: " + startableState); 816 } 817 pw.decreaseIndent(); 818 } 819 } 820 } 821