1 /* 2 * Copyright (C) 2023 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 android.tools.traces.component 18 19 import android.tools.traces.surfaceflinger.Layer 20 import android.tools.traces.wm.Activity 21 import android.tools.traces.wm.WindowContainer 22 23 /** ComponentMatcher based on name */ 24 class ComponentNameMatcher(var component: ComponentName) : IComponentNameMatcher { 25 override val packageName: String 26 get() = component.packageName 27 override val className: String 28 get() = component.className toActivityNamenull29 override fun toActivityName(): String = component.toActivityName() 30 override fun toWindowName(): String = component.toWindowName() 31 override fun toLayerName(): String = component.toLayerName() 32 33 constructor( 34 packageName: String, 35 className: String 36 ) : this(ComponentName(packageName, className)) 37 38 constructor(className: String) : this("", className) 39 40 override fun activityRecordMatchesAnyOf(layers: Collection<Layer>): Boolean = 41 layers.any { activityRecordFilter.invoke(it.name) } 42 componentNameMatcherToStringnull43 override fun componentNameMatcherToString(): String { 44 return "ComponentNameMatcher(\"${this.packageName}\", " + "\"${this.className}\")" 45 } 46 47 /** {@inheritDoc} */ windowMatchesAnyOfnull48 override fun windowMatchesAnyOf(windows: Collection<WindowContainer>): Boolean = 49 windows.any { windowNameFilter.invoke(it.title) } 50 51 /** {@inheritDoc} */ activityMatchesAnyOfnull52 override fun activityMatchesAnyOf(activities: Collection<Activity>): Boolean = 53 activities.any { activityNameFilter.invoke(it.name) } 54 55 /** {@inheritDoc} */ layerMatchesAnyOfnull56 override fun layerMatchesAnyOf(layers: Collection<Layer>): Boolean = 57 layers.any { layerNameFilter.invoke(it.name) } 58 59 /** {@inheritDoc} */ checknull60 override fun check( 61 layers: Collection<Layer>, 62 condition: (Collection<Layer>) -> Boolean 63 ): Boolean = condition(layers.filter { layerMatchesAnyOf(it) }) 64 65 /** {@inheritDoc} */ toActivityIdentifiernull66 override fun toActivityIdentifier(): String = component.toActivityName() 67 68 /** {@inheritDoc} */ 69 override fun toWindowIdentifier(): String = component.toWindowName() 70 71 /** {@inheritDoc} */ 72 override fun toLayerIdentifier(): String = component.toLayerName() 73 74 override fun equals(other: Any?): Boolean { 75 if (this === other) return true 76 if (other !is ComponentNameMatcher) return false 77 return component == other.component 78 } 79 hashCodenull80 override fun hashCode(): Int = component.hashCode() 81 82 override fun toString(): String = component.toString() 83 84 private val activityRecordFilter: (String) -> Boolean 85 get() = { it.startsWith("ActivityRecord{") && it.contains(component.toShortWindowName()) } 86 87 private val activityNameFilter: (String) -> Boolean <lambda>null88 get() = { it.contains(component.toActivityName()) } 89 90 private val windowNameFilter: (String) -> Boolean <lambda>null91 get() = { it.contains(component.toWindowName()) } 92 93 private val layerNameFilter: (String) -> Boolean <lambda>null94 get() = { it.contains(component.toLayerName()) } 95 96 companion object { 97 val NAV_BAR = ComponentNameMatcher("", "NavigationBar0") 98 val TASK_BAR = ComponentNameMatcher("", "Taskbar") 99 val STATUS_BAR = ComponentNameMatcher("", "StatusBar") 100 val ROTATION = ComponentNameMatcher("", "RotationLayer") 101 val BACK_SURFACE = ComponentNameMatcher("", "BackColorSurface") 102 val IME = ComponentNameMatcher("", "InputMethod") 103 val IME_SNAPSHOT = ComponentNameMatcher("", "IME-snapshot-surface") 104 val SPLASH_SCREEN = ComponentNameMatcher("", "Splash Screen") 105 val SNAPSHOT = ComponentNameMatcher("", "SnapshotStartingWindow") 106 val SECONDARY_HOME_HANDLE = ComponentNameMatcher("", "SecondaryHomeHandle") 107 108 val TRANSITION_SNAPSHOT = ComponentNameMatcher("", "transition snapshot") 109 val LETTERBOX = ComponentNameMatcher("", "Letterbox") 110 111 val WALLPAPER_BBQ_WRAPPER = ComponentNameMatcher("", "Wallpaper BBQ wrapper") 112 113 val PIP_CONTENT_OVERLAY = ComponentNameMatcher("", "PipContentOverlay") 114 115 val PIP_MENU_OVERLAY = ComponentNameMatcher("", "PipMenuView") 116 117 val EDGE_BACK_GESTURE_HANDLER = ComponentNameMatcher("", "EdgeBackGestureHandler0") 118 119 val COLOR_FADE = ComponentNameMatcher("", "ColorFade") 120 121 val WALLPAPER_WINDOW_TOKEN = ComponentNameMatcher("", "WallpaperWindowToken") 122 123 val NOTIFICATION_SHADE = ComponentNameMatcher("", "NotificationShade") 124 125 val VOLUME_DIALOG = ComponentNameMatcher("", "VolumeDialog") 126 127 val FLOATING_ROTATION_BUTTON = ComponentNameMatcher("", "FloatingRotationButton") 128 129 val SCREEN_DECOR_OVERLAY = ComponentNameMatcher("", "ScreenDecorHwcOverlay#") 130 131 val POINTER_LOCATION = ComponentNameMatcher("", "PointerLocation") 132 133 val WIRED_CHARGING_ANIMATION = ComponentNameMatcher("", "Wired Charging Animation#") 134 135 val SCREEN_RECORDING_OVERLAYS = SCREEN_DECOR_OVERLAY.or(POINTER_LOCATION) 136 137 val LAUNCHER = 138 ComponentNameMatcher( 139 "com.google.android.apps.nexuslauncher", 140 "com.google.android.apps.nexuslauncher.NexusLauncherActivity" 141 ) 142 143 val AOSP_LAUNCHER = 144 ComponentNameMatcher( 145 "com.android.launcher3", 146 "com.android.launcher3.uioverrides.QuickstepLauncher" 147 ) 148 149 val SPLIT_DIVIDER = ComponentNameMatcher("", "StageCoordinatorSplitDivider") 150 151 val DEFAULT_TASK_DISPLAY_AREA = ComponentNameMatcher("", "DefaultTaskDisplayArea") 152 153 /** 154 * Creates a component matcher from a window or layer name. 155 * 156 * Requires the [str] to contain both the package and class name (with a / separator) 157 * 158 * @param str Value to parse 159 */ unflattenFromStringnull160 fun unflattenFromString(str: String): ComponentNameMatcher { 161 val sep = str.indexOf('/') 162 if (sep < 0 || sep + 1 >= str.length) { 163 error("Missing package/class separator") 164 } 165 val pkg = str.substring(0, sep) 166 var cls = str.substring(sep + 1) 167 if (cls.isNotEmpty() && cls[0] == '.') { 168 cls = pkg + cls 169 } 170 return ComponentNameMatcher(pkg, cls) 171 } 172 173 /** 174 * Creates a component matcher from a window or layer name. The name might contain junk, 175 * which will be removed to only extract package and class name (e.g. other words before 176 * package name, separated by spaces, #id in the end after the class name) 177 * 178 * Requires the [str] to contain both the package and class name (with a / separator) 179 * 180 * @param str Value to parse 181 */ unflattenFromStringWithJunknull182 fun unflattenFromStringWithJunk(str: String): ComponentNameMatcher { 183 val sep = str.indexOf('/') 184 if (sep < 0 || sep + 1 >= str.length) { 185 error("Missing package/class separator") 186 } 187 188 var pkg = str.substring(0, sep) 189 var pkgSep: Int = -1 190 val pkgCharArr = pkg.toCharArray() 191 for (index in (0..pkgCharArr.lastIndex).reversed()) { 192 val currentChar = pkgCharArr[index] 193 if (currentChar !in 'A'..'Z' && currentChar !in 'a'..'z' && currentChar != '.') { 194 pkgSep = index 195 break 196 } 197 } 198 if (!(pkgSep < 0 || pkgSep + 1 >= pkg.length)) { 199 pkg = pkg.substring(pkgSep, pkg.length) 200 } 201 202 var cls = str.substring(sep + 1) 203 var clsSep = -1 // cls.indexOf('#') 204 val clsCharArr = cls.toCharArray() 205 for (index in (0..clsCharArr.lastIndex)) { 206 val currentChar = clsCharArr[index] 207 if (currentChar !in 'A'..'Z' && currentChar !in 'a'..'z' && currentChar != '.') { 208 clsSep = index 209 break 210 } 211 } 212 if (!(clsSep < 0 || clsSep + 1 >= cls.length)) { 213 cls = cls.substring(0, clsSep) 214 } 215 216 if (cls.isNotEmpty() && cls[0] == '.') { 217 cls = pkg + cls 218 } 219 return ComponentNameMatcher(pkg, cls) 220 } 221 } 222 } 223