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