<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