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 package com.android.systemui.decor 17 18 import android.annotation.IdRes 19 import android.annotation.NonNull 20 import android.content.Context 21 import android.view.Surface 22 import android.view.View 23 import android.view.ViewGroup 24 import com.android.systemui.RegionInterceptingFrameLayout 25 import java.io.PrintWriter 26 27 class OverlayWindow(private val context: Context) { 28 29 val rootView = RegionInterceptingFrameLayout(context) as ViewGroup 30 private val viewProviderMap = mutableMapOf<Int, Pair<View, DecorProvider>>() 31 32 val viewIds: List<Int> 33 get() = viewProviderMap.keys.toList() 34 35 fun addDecorProvider( 36 decorProvider: DecorProvider, 37 @Surface.Rotation rotation: Int, 38 tintColor: Int 39 ) { 40 val view = decorProvider.inflateView(context, rootView, rotation, tintColor) 41 viewProviderMap[decorProvider.viewId] = Pair(view, decorProvider) 42 } 43 44 fun getView(@IdRes id: Int): View? { 45 val pair = viewProviderMap[id] 46 return pair?.first 47 } 48 49 fun removeView(@IdRes id: Int) { 50 val view = getView(id) 51 if (view != null) { 52 rootView.removeView(view) 53 viewProviderMap.remove(id) 54 } 55 } 56 57 /** 58 * Remove views which does not been found in expectExistViewIds 59 */ 60 fun removeRedundantViews(expectExistViewIds: IntArray?) { 61 viewIds.forEach { 62 if (expectExistViewIds == null || !(expectExistViewIds.contains(it))) { 63 removeView(it) 64 } 65 } 66 } 67 68 /** 69 * Check that newProviders is the same list with viewProviderMap. 70 */ 71 fun hasSameProviders(newProviders: List<DecorProvider>): Boolean { 72 return (newProviders.size == viewProviderMap.size) && 73 newProviders.all { getView(it.viewId) != null } 74 } 75 76 /** 77 * Apply new configuration info into views. 78 * @param filterIds target view ids. Apply to all if null. 79 * @param rotation current or new rotation direction. 80 * @param displayUniqueId new displayUniqueId if any. 81 */ 82 fun onReloadResAndMeasure( 83 filterIds: Array<Int>? = null, 84 reloadToken: Int, 85 @Surface.Rotation rotation: Int, 86 tintColor: Int, 87 displayUniqueId: String? = null 88 ) { 89 filterIds?.forEach { id -> 90 viewProviderMap[id]?.let { 91 it.second.onReloadResAndMeasure( 92 view = it.first, 93 reloadToken = reloadToken, 94 rotation = rotation, 95 tintColor = tintColor, 96 displayUniqueId = displayUniqueId 97 ) 98 } 99 } ?: run { 100 viewProviderMap.values.forEach { 101 it.second.onReloadResAndMeasure( 102 view = it.first, 103 reloadToken = reloadToken, 104 rotation = rotation, 105 tintColor = tintColor, 106 displayUniqueId = displayUniqueId 107 ) 108 } 109 } 110 } 111 112 fun dump(@NonNull pw: PrintWriter, name: String) { 113 pw.println(" $name=") 114 pw.println(" rootView=$rootView") 115 for (i in 0 until rootView.childCount) { 116 val child = rootView.getChildAt(i) 117 val provider = viewProviderMap[child.id]?.second 118 pw.println(" child[$i]=$child $provider") 119 } 120 } 121 } 122