• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.common.traces.component
18 
19 import android.tools.common.traces.surfaceflinger.Layer
20 import android.tools.common.traces.wm.Activity
21 import android.tools.common.traces.wm.IWindowContainer
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: Array<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: Array<IWindowContainer>): Boolean =
49         windows.any { windowNameFilter.invoke(it.title) }
50 
51     /** {@inheritDoc} */
activityMatchesAnyOfnull52     override fun activityMatchesAnyOf(activities: Array<Activity>): Boolean =
53         activities.any { activityNameFilter.invoke(it.name) }
54 
55     /** {@inheritDoc} */
layerMatchesAnyOfnull56     override fun layerMatchesAnyOf(layers: Array<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 EDGE_BACK_GESTURE_HANDLER = ComponentNameMatcher("", "EdgeBackGestureHandler")
116 
117         val COLOR_FADE = ComponentNameMatcher("", "ColorFade")
118 
119         val WALLPAPER_WINDOW_TOKEN = ComponentNameMatcher("", "WallpaperWindowToken")
120 
121         val NOTIFICATION_SHADE = ComponentNameMatcher("", "NotificationShade")
122 
123         val VOLUME_DIALOG = ComponentNameMatcher("", "VolumeDialog")
124 
125         val LAUNCHER =
126             ComponentNameMatcher(
127                 "com.google.android.apps.nexuslauncher",
128                 "com.google.android.apps.nexuslauncher.NexusLauncherActivity"
129             )
130 
131         val AOSP_LAUNCHER =
132             ComponentNameMatcher(
133                 "com.android.launcher3",
134                 "com.android.launcher3.uioverrides.QuickstepLauncher"
135             )
136 
137         val SPLIT_DIVIDER = ComponentNameMatcher("", "StageCoordinatorSplitDivider")
138 
139         val DEFAULT_TASK_DISPLAY_AREA = ComponentNameMatcher("", "DefaultTaskDisplayArea")
140 
141         /**
142          * Creates a component matcher from a window or layer name.
143          *
144          * Requires the [str] to contain both the package and class name (with a / separator)
145          *
146          * @param str Value to parse
147          */
unflattenFromStringnull148         fun unflattenFromString(str: String): ComponentNameMatcher {
149             val sep = str.indexOf('/')
150             if (sep < 0 || sep + 1 >= str.length) {
151                 error("Missing package/class separator")
152             }
153             val pkg = str.substring(0, sep)
154             var cls = str.substring(sep + 1)
155             if (cls.isNotEmpty() && cls[0] == '.') {
156                 cls = pkg + cls
157             }
158             return ComponentNameMatcher(pkg, cls)
159         }
160 
161         /**
162          * Creates a component matcher from a window or layer name. The name might contain junk,
163          * which will be removed to only extract package and class name (e.g. other words before
164          * package name, separated by spaces, #id in the end after the class name)
165          *
166          * Requires the [str] to contain both the package and class name (with a / separator)
167          *
168          * @param str Value to parse
169          */
unflattenFromStringWithJunknull170         fun unflattenFromStringWithJunk(str: String): ComponentNameMatcher {
171             val sep = str.indexOf('/')
172             if (sep < 0 || sep + 1 >= str.length) {
173                 error("Missing package/class separator")
174             }
175 
176             var pkg = str.substring(0, sep)
177             var pkgSep: Int = -1
178             val pkgCharArr = pkg.toCharArray()
179             for (index in (0..pkgCharArr.lastIndex).reversed()) {
180                 val currentChar = pkgCharArr[index]
181                 if (currentChar !in 'A'..'Z' && currentChar !in 'a'..'z' && currentChar != '.') {
182                     pkgSep = index
183                     break
184                 }
185             }
186             if (!(pkgSep < 0 || pkgSep + 1 >= pkg.length)) {
187                 pkg = pkg.substring(pkgSep, pkg.length)
188             }
189 
190             var cls = str.substring(sep + 1)
191             var clsSep = -1 // cls.indexOf('#')
192             val clsCharArr = cls.toCharArray()
193             for (index in (0..clsCharArr.lastIndex)) {
194                 val currentChar = clsCharArr[index]
195                 if (currentChar !in 'A'..'Z' && currentChar !in 'a'..'z' && currentChar != '.') {
196                     clsSep = index
197                     break
198                 }
199             }
200             if (!(clsSep < 0 || clsSep + 1 >= cls.length)) {
201                 cls = cls.substring(0, clsSep)
202             }
203 
204             if (cls.isNotEmpty() && cls[0] == '.') {
205                 cls = pkg + cls
206             }
207             return ComponentNameMatcher(pkg, cls)
208         }
209     }
210 }
211