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