1 /* 2 * Copyright (C) 2021 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.server.wm.traces.common 18 19 import kotlin.text.Regex.Companion.escape 20 21 /** 22 * Create a new component identifier. 23 * 24 * This is a version of Android's ComponentName class for flicker. This is necessary because 25 * flicker codebase it also compiled into KotlinJS for use into Winscope 26 * 27 * @param packageName The name of the package that the component exists in. Can 28 * not be null. 29 * @param className The name of the class inside of <var>pkg</var> that 30 * implements the component. Can not be null. 31 */ 32 data class FlickerComponentName( 33 val packageName: String, 34 val className: String 35 ) { 36 /** 37 * Obtains the activity name from the component name. 38 * 39 * See [ComponentName.toWindowName] for additional information 40 */ toActivityNamenull41 fun toActivityName(): String { 42 return when { 43 packageName.isNotEmpty() && className.isNotEmpty() -> { 44 val sb = StringBuilder(packageName.length + className.length) 45 appendShortString(sb, packageName, className) 46 return sb.toString() 47 } 48 packageName.isNotEmpty() -> packageName 49 className.isNotEmpty() -> className 50 else -> error("Component name should have an activity of class name") 51 } 52 } 53 54 /** 55 * Obtains the window name from the component name. 56 * 57 * [ComponentName] builds the string representation as PKG/CLASS, however this doesn't 58 * work for system components such as IME, NavBar and StatusBar, Toast. 59 * 60 * If the component doesn't have a package name, assume it's a system component and return only 61 * the class name 62 */ toWindowNamenull63 fun toWindowName(): String { 64 return when { 65 packageName.isNotEmpty() && className.isNotEmpty() -> "$packageName/$className" 66 packageName.isNotEmpty() -> packageName 67 className.isNotEmpty() -> className 68 else -> error("Component name should have an activity of class name") 69 } 70 } 71 toShortWindowNamenull72 fun toShortWindowName(): String { 73 return when { 74 packageName.isNotEmpty() && className.isNotEmpty() -> 75 "$packageName/${className.removePrefix(packageName)}" 76 packageName.isNotEmpty() -> packageName 77 className.isNotEmpty() -> className 78 else -> error("Component name should have an activity of class name") 79 } 80 } 81 82 /** 83 * Obtains the layer name from the component name. 84 * 85 * See [toWindowName] for additional information 86 */ toLayerNamenull87 fun toLayerName(): String { 88 var result = this.toWindowName() 89 if (result.contains("/") && !result.contains("#")) { 90 result = "$result#" 91 } 92 93 return result 94 } 95 toActivityRecordFilternull96 fun toActivityRecordFilter(): Regex { 97 return Regex("ActivityRecord\\{.*${escape(this.toShortWindowName())}") 98 } 99 appendShortStringnull100 private fun appendShortString(sb: StringBuilder, packageName: String, className: String) { 101 sb.append(packageName).append('/') 102 appendShortClassName(sb, packageName, className) 103 } 104 appendShortClassNamenull105 private fun appendShortClassName(sb: StringBuilder, packageName: String, className: String) { 106 if (className.startsWith(packageName)) { 107 val packageNameLength = packageName.length 108 val classNameLength = className.length 109 if (classNameLength > packageNameLength && className[packageNameLength] == '.') { 110 sb.append(className, packageNameLength, classNameLength) 111 return 112 } 113 } 114 sb.append(className) 115 } 116 117 companion object { 118 val NAV_BAR = FlickerComponentName("", "NavigationBar0") 119 val STATUS_BAR = FlickerComponentName("", "StatusBar") 120 val ROTATION = FlickerComponentName("", "RotationLayer") 121 val BACK_SURFACE = FlickerComponentName("", "BackColorSurface") 122 val IME = FlickerComponentName("", "InputMethod") 123 val IME_SNAPSHOT = FlickerComponentName("", "IME-snapshot-surface") 124 val SPLASH_SCREEN = FlickerComponentName("", "Splash Screen") 125 val SNAPSHOT = FlickerComponentName("", "SnapshotStartingWindow") 126 val LETTERBOX = FlickerComponentName("", "Letterbox") 127 val WALLPAPER_BBQ_WRAPPER = 128 FlickerComponentName("", "Wallpaper BBQ wrapper") 129 val PIP_CONTENT_OVERLAY = FlickerComponentName("", "PipContentOverlay") 130 unflattenFromStringnull131 fun unflattenFromString(str: String): FlickerComponentName { 132 val sep = str.indexOf('/') 133 if (sep < 0 || sep + 1 >= str.length) { 134 error("Missing package/class separator") 135 } 136 val pkg = str.substring(0, sep) 137 var cls = str.substring(sep + 1) 138 if (cls.isNotEmpty() && cls[0] == '.') { 139 cls = pkg + cls 140 } 141 return FlickerComponentName(pkg, cls) 142 } 143 } 144 }