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