• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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