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