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