1  package com.android.systemui.statusbar.phone
2  
3  import android.app.StatusBarManager
4  import com.android.systemui.Dumpable
5  import com.android.systemui.dagger.SysUISingleton
6  import com.android.systemui.dagger.qualifiers.Main
7  import com.android.systemui.dump.DumpManager
8  import com.android.systemui.shade.ShadeExpansionStateManager
9  import com.android.systemui.statusbar.CommandQueue
10  import com.android.systemui.statusbar.window.StatusBarWindowStateController
11  import com.android.systemui.util.concurrency.DelayableExecutor
12  import java.io.PrintWriter
13  import javax.inject.Inject
14  
15  /**
16   * A class that manages if the status bar (clock + notifications + signal cluster) should be visible
17   * or not when showing the bouncer.
18   *
19   * We want to hide it when:
20   * • User swipes up on the keyguard
21   * • Locked activity that doesn't show a status bar requests the bouncer.
22   *
23   * [getShouldHideStatusBarIconsForBouncer] is the main exported method for this class. The other
24   * methods set state variables that are used in the calculation or manually trigger an update.
25   */
26  @SysUISingleton
27  class StatusBarHideIconsForBouncerManager @Inject constructor(
28          private val commandQueue: CommandQueue,
29          @Main private val mainExecutor: DelayableExecutor,
30          statusBarWindowStateController: StatusBarWindowStateController,
31          shadeExpansionStateManager: ShadeExpansionStateManager,
32          dumpManager: DumpManager
33  ) : Dumpable {
34      // State variables set by external classes.
35      private var panelExpanded: Boolean = false
36      private var isOccluded: Boolean = false
37      private var bouncerShowing: Boolean = false
38      private var topAppHidesStatusBar: Boolean = false
39      private var statusBarWindowHidden: Boolean = false
40      private var displayId: Int = 0
41  
42      // State variables calculated internally.
43      private var hideIconsForBouncer: Boolean = false
44      private var bouncerWasShowingWhenHidden: Boolean = false
45      private var wereIconsJustHidden: Boolean = false
46  
47      init {
48          dumpManager.registerDumpable(this)
49          statusBarWindowStateController.addListener {
50                  state -> setStatusBarStateAndTriggerUpdate(state)
51          }
52          shadeExpansionStateManager.addFullExpansionListener { isExpanded ->
53              if (panelExpanded != isExpanded) {
54                  panelExpanded = isExpanded
55                  updateHideIconsForBouncer(animate = false)
56              }
57          }
58      }
59  
60      /** Returns true if the status bar icons should be hidden in the bouncer. */
61      fun getShouldHideStatusBarIconsForBouncer(): Boolean {
62          return hideIconsForBouncer || wereIconsJustHidden
63      }
64  
65      private fun setStatusBarStateAndTriggerUpdate(@StatusBarManager.WindowVisibleState state: Int) {
66          statusBarWindowHidden = state == StatusBarManager.WINDOW_STATE_HIDDEN
67          updateHideIconsForBouncer(animate = false)
68      }
69  
70      fun setDisplayId(displayId: Int) {
71          this.displayId = displayId
72      }
73  
74      fun setIsOccludedAndTriggerUpdate(isOccluded: Boolean) {
75          this.isOccluded = isOccluded
76          updateHideIconsForBouncer(animate = false)
77      }
78  
79      fun setBouncerShowingAndTriggerUpdate(bouncerShowing: Boolean) {
80          this.bouncerShowing = bouncerShowing
81          updateHideIconsForBouncer(animate = true)
82      }
83  
84      fun setTopAppHidesStatusBarAndTriggerUpdate(topAppHidesStatusBar: Boolean) {
85          this.topAppHidesStatusBar = topAppHidesStatusBar
86          if (!topAppHidesStatusBar && wereIconsJustHidden) {
87              // Immediately update the icon hidden state, since that should only apply if we're
88              // staying fullscreen.
89              wereIconsJustHidden = false
90              commandQueue.recomputeDisableFlags(displayId, /* animate= */ true)
91          }
92          updateHideIconsForBouncer(animate = true)
93      }
94  
95      /**
96       * Updates whether the status bar icons should be hidden in the bouncer. May trigger
97       * [commandQueue.recomputeDisableFlags] if the icon visibility status changes.
98       */
99      private fun updateHideIconsForBouncer(animate: Boolean) {
100          val hideBecauseApp =
101              topAppHidesStatusBar &&
102                      isOccluded &&
103                      (statusBarWindowHidden || bouncerShowing)
104          val hideBecauseKeyguard = !panelExpanded && !isOccluded && bouncerShowing
105          val shouldHideIconsForBouncer = hideBecauseApp || hideBecauseKeyguard
106          if (hideIconsForBouncer != shouldHideIconsForBouncer) {
107              hideIconsForBouncer = shouldHideIconsForBouncer
108              if (!shouldHideIconsForBouncer && bouncerWasShowingWhenHidden) {
109                  // We're delaying the showing, since most of the time the fullscreen app will
110                  // hide the icons again and we don't want them to fade in and out immediately again.
111                  wereIconsJustHidden = true
112                  mainExecutor.executeDelayed(
113                      {
114                          wereIconsJustHidden = false
115                          commandQueue.recomputeDisableFlags(displayId, true)
116                      },
117                      500
118                  )
119              } else {
120                  commandQueue.recomputeDisableFlags(displayId, animate)
121              }
122          }
123          if (shouldHideIconsForBouncer) {
124              bouncerWasShowingWhenHidden = bouncerShowing
125          }
126      }
127  
128      override fun dump(pw: PrintWriter, args: Array<out String>) {
129          pw.println("---- State variables set externally ----")
130          pw.println("panelExpanded=$panelExpanded")
131          pw.println("isOccluded=$isOccluded")
132          pw.println("bouncerShowing=$bouncerShowing")
133          pw.println("topAppHideStatusBar=$topAppHidesStatusBar")
134          pw.println("statusBarWindowHidden=$statusBarWindowHidden")
135          pw.println("displayId=$displayId")
136  
137          pw.println("---- State variables calculated internally ----")
138          pw.println("hideIconsForBouncer=$hideIconsForBouncer")
139          pw.println("bouncerWasShowingWhenHidden=$bouncerWasShowingWhenHidden")
140          pw.println("wereIconsJustHidden=$wereIconsJustHidden")
141      }
142  }
143