1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.phone 18 19 import android.view.InsetsFlags 20 import android.view.ViewDebug 21 import android.view.WindowInsets.Type.InsetsType 22 import android.view.WindowInsetsController.Appearance 23 import android.view.WindowInsetsController.Behavior 24 import com.android.internal.statusbar.LetterboxDetails 25 import com.android.internal.view.AppearanceRegion 26 import com.android.systemui.Dumpable 27 import com.android.systemui.dagger.SysUISingleton 28 import com.android.systemui.dump.DumpManager 29 import com.android.systemui.statusbar.SysuiStatusBarStateController 30 import java.io.PrintWriter 31 import javax.inject.Inject 32 33 /** 34 * Top-level listener of system attributes changed. This class is __always the first__ one to be 35 * notified about changes. 36 * 37 * It is responsible for modifying any attributes if necessary, and then notifying the other 38 * downstream listeners. 39 */ 40 @SysUISingleton 41 class SystemBarAttributesListener 42 @Inject 43 internal constructor( 44 private val centralSurfaces: CentralSurfaces, 45 private val letterboxAppearanceCalculator: LetterboxAppearanceCalculator, 46 private val statusBarStateController: SysuiStatusBarStateController, 47 private val lightBarController: LightBarController, 48 dumpManager: DumpManager, 49 ) : Dumpable, StatusBarBoundsProvider.BoundsChangeListener { 50 51 private var lastLetterboxAppearance: LetterboxAppearance? = null 52 private var lastSystemBarAttributesParams: SystemBarAttributesParams? = null 53 54 init { 55 dumpManager.registerCriticalDumpable(this) 56 } 57 58 override fun onStatusBarBoundsChanged() { 59 val params = lastSystemBarAttributesParams 60 if (params != null && shouldUseLetterboxAppearance(params.letterboxesArray)) { 61 onSystemBarAttributesChanged( 62 params.displayId, 63 params.appearance, 64 params.appearanceRegionsArray, 65 params.navbarColorManagedByIme, 66 params.behavior, 67 params.requestedVisibleTypes, 68 params.packageName, 69 params.letterboxesArray) 70 } 71 } 72 73 fun onSystemBarAttributesChanged( 74 displayId: Int, 75 @Appearance originalAppearance: Int, 76 originalAppearanceRegions: Array<AppearanceRegion>, 77 navbarColorManagedByIme: Boolean, 78 @Behavior behavior: Int, 79 @InsetsType requestedVisibleTypes: Int, 80 packageName: String, 81 letterboxDetails: Array<LetterboxDetails> 82 ) { 83 lastSystemBarAttributesParams = 84 SystemBarAttributesParams( 85 displayId, 86 originalAppearance, 87 originalAppearanceRegions.toList(), 88 navbarColorManagedByIme, 89 behavior, 90 requestedVisibleTypes, 91 packageName, 92 letterboxDetails.toList()) 93 94 val (appearance, appearanceRegions) = 95 modifyAppearanceIfNeeded( 96 originalAppearance, originalAppearanceRegions, letterboxDetails) 97 98 val barModeChanged = centralSurfaces.setAppearance(appearance) 99 100 lightBarController.onStatusBarAppearanceChanged( 101 appearanceRegions, barModeChanged, centralSurfaces.barMode, navbarColorManagedByIme) 102 103 centralSurfaces.updateBubblesVisibility() 104 statusBarStateController.setSystemBarAttributes( 105 appearance, behavior, requestedVisibleTypes, packageName) 106 } 107 108 private fun modifyAppearanceIfNeeded( 109 appearance: Int, 110 appearanceRegions: Array<AppearanceRegion>, 111 letterboxDetails: Array<LetterboxDetails> 112 ): Pair<Int, Array<AppearanceRegion>> = 113 if (shouldUseLetterboxAppearance(letterboxDetails)) { 114 val letterboxAppearance = 115 letterboxAppearanceCalculator.getLetterboxAppearance( 116 appearance, appearanceRegions, letterboxDetails) 117 lastLetterboxAppearance = letterboxAppearance 118 Pair(letterboxAppearance.appearance, letterboxAppearance.appearanceRegions) 119 } else { 120 lastLetterboxAppearance = null 121 Pair(appearance, appearanceRegions) 122 } 123 124 private fun shouldUseLetterboxAppearance(letterboxDetails: Array<LetterboxDetails>) = 125 letterboxDetails.isNotEmpty() 126 127 override fun dump(printWriter: PrintWriter, strings: Array<String>) { 128 printWriter.println("lastSystemBarAttributesParams: $lastSystemBarAttributesParams") 129 printWriter.println("lastLetterboxAppearance: $lastLetterboxAppearance") 130 } 131 } 132 133 /** 134 * Keeps track of the parameters passed in 135 * [SystemBarAttributesListener.onSystemBarAttributesChanged]. 136 */ 137 private data class SystemBarAttributesParams( 138 val displayId: Int, 139 @Appearance val appearance: Int, 140 val appearanceRegions: List<AppearanceRegion>, 141 val navbarColorManagedByIme: Boolean, 142 @Behavior val behavior: Int, 143 @InsetsType val requestedVisibleTypes: Int, 144 val packageName: String, 145 val letterboxes: List<LetterboxDetails>, 146 ) { 147 val letterboxesArray = letterboxes.toTypedArray() 148 val appearanceRegionsArray = appearanceRegions.toTypedArray() 149 override fun toString(): String { 150 val appearanceToString = 151 ViewDebug.flagsToString(InsetsFlags::class.java, "appearance", appearance) 152 return """SystemBarAttributesParams( 153 displayId=$displayId, 154 appearance=$appearanceToString, 155 appearanceRegions=$appearanceRegions, 156 navbarColorManagedByIme=$navbarColorManagedByIme, 157 behavior=$behavior, 158 requestedVisibleTypes=$requestedVisibleTypes, 159 packageName='$packageName', 160 letterboxes=$letterboxes, 161 letterboxesArray=${letterboxesArray.contentToString()}, 162 appearanceRegionsArray=${appearanceRegionsArray.contentToString()} 163 )""".trimMargin() 164 } 165 } 166