package com.android.systemui.statusbar.phone import android.app.StatusBarManager import com.android.systemui.Dumpable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.window.StatusBarWindowStateController import com.android.systemui.util.concurrency.DelayableExecutor import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import java.io.PrintWriter import javax.inject.Inject /** * A class that manages if the status bar (clock + notifications + signal cluster) should be visible * or not when showing the bouncer. * * We want to hide it when: * • User swipes up on the keyguard * • Locked activity that doesn't show a status bar requests the bouncer. * * [getShouldHideStatusBarIconsForBouncer] is the main exported method for this class. The other * methods set state variables that are used in the calculation or manually trigger an update. */ @SysUISingleton class StatusBarHideIconsForBouncerManager @Inject constructor( @Application private val scope: CoroutineScope, private val commandQueue: CommandQueue, @Main private val mainExecutor: DelayableExecutor, statusBarWindowStateController: StatusBarWindowStateController, val shadeInteractor: ShadeInteractor, dumpManager: DumpManager ) : Dumpable { // State variables set by external classes. private var isOccluded: Boolean = false private var bouncerShowing: Boolean = false private var topAppHidesStatusBar: Boolean = false private var statusBarWindowHidden: Boolean = false private var displayId: Int = 0 // State variables calculated internally. private var hideIconsForBouncer: Boolean = false private var bouncerWasShowingWhenHidden: Boolean = false private var wereIconsJustHidden: Boolean = false init { dumpManager.registerDumpable(this) statusBarWindowStateController.addListener { state -> setStatusBarStateAndTriggerUpdate(state) } scope.launch { shadeInteractor.isAnyExpanded.collect { updateHideIconsForBouncer(false) } } } /** Returns true if the status bar icons should be hidden in the bouncer. */ fun getShouldHideStatusBarIconsForBouncer(): Boolean { return hideIconsForBouncer || wereIconsJustHidden } private fun setStatusBarStateAndTriggerUpdate(@StatusBarManager.WindowVisibleState state: Int) { statusBarWindowHidden = state == StatusBarManager.WINDOW_STATE_HIDDEN updateHideIconsForBouncer(animate = false) } fun setDisplayId(displayId: Int) { this.displayId = displayId } fun setIsOccludedAndTriggerUpdate(isOccluded: Boolean) { this.isOccluded = isOccluded updateHideIconsForBouncer(animate = false) } fun setBouncerShowingAndTriggerUpdate(bouncerShowing: Boolean) { this.bouncerShowing = bouncerShowing updateHideIconsForBouncer(animate = true) } fun setTopAppHidesStatusBarAndTriggerUpdate(topAppHidesStatusBar: Boolean) { this.topAppHidesStatusBar = topAppHidesStatusBar if (!topAppHidesStatusBar && wereIconsJustHidden) { // Immediately update the icon hidden state, since that should only apply if we're // staying fullscreen. wereIconsJustHidden = false commandQueue.recomputeDisableFlags(displayId, /* animate= */ true) } updateHideIconsForBouncer(animate = true) } /** * Updates whether the status bar icons should be hidden in the bouncer. May trigger * [commandQueue.recomputeDisableFlags] if the icon visibility status changes. */ private fun updateHideIconsForBouncer(animate: Boolean) { val hideBecauseApp = topAppHidesStatusBar && isOccluded && (statusBarWindowHidden || bouncerShowing) val hideBecauseKeyguard = !isShadeOrQsExpanded() && !isOccluded && bouncerShowing val shouldHideIconsForBouncer = hideBecauseApp || hideBecauseKeyguard if (hideIconsForBouncer != shouldHideIconsForBouncer) { hideIconsForBouncer = shouldHideIconsForBouncer if (!shouldHideIconsForBouncer && bouncerWasShowingWhenHidden) { // We're delaying the showing, since most of the time the fullscreen app will // hide the icons again and we don't want them to fade in and out immediately again. wereIconsJustHidden = true mainExecutor.executeDelayed( { wereIconsJustHidden = false commandQueue.recomputeDisableFlags(displayId, true) }, 500 ) } else { commandQueue.recomputeDisableFlags(displayId, animate) } } if (shouldHideIconsForBouncer) { bouncerWasShowingWhenHidden = bouncerShowing } } private fun isShadeOrQsExpanded(): Boolean { return shadeInteractor.isAnyExpanded.value } override fun dump(pw: PrintWriter, args: Array) { pw.println("---- State variables set externally ----") pw.println("isShadeOrQsExpanded=${isShadeOrQsExpanded()}") pw.println("isOccluded=$isOccluded") pw.println("bouncerShowing=$bouncerShowing") pw.println("topAppHideStatusBar=$topAppHidesStatusBar") pw.println("statusBarWindowHidden=$statusBarWindowHidden") pw.println("displayId=$displayId") pw.println("---- State variables calculated internally ----") pw.println("hideIconsForBouncer=$hideIconsForBouncer") pw.println("bouncerWasShowingWhenHidden=$bouncerWasShowingWhenHidden") pw.println("wereIconsJustHidden=$wereIconsJustHidden") } }