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