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 /** 20 * Create a new component identifier. 21 * 22 * This is a version of Android's ComponentName class for flicker. This is necessary because 23 * flicker codebase it also compiled into KotlinJS for use into Winscope 24 * 25 * @param packageName The name of the package that the component exists in. Can 26 * not be null. 27 * @param className The name of the class inside of <var>pkg</var> that 28 * implements the component. Can not be null. 29 */ 30 data class FlickerComponentName( 31 val packageName: String, 32 val className: String 33 ) { 34 /** 35 * Obtains the activity name from the component name. 36 * 37 * See [ComponentName.toWindowName] for additional information 38 */ toActivityNamenull39 fun toActivityName(): String { 40 return when { 41 packageName.isNotEmpty() && className.isNotEmpty() -> { 42 val sb = StringBuilder(packageName.length + className.length) 43 appendShortString(sb, packageName, className) 44 return sb.toString() 45 } 46 packageName.isNotEmpty() -> packageName 47 className.isNotEmpty() -> className 48 else -> error("Component name should have an activity of class name") 49 } 50 } 51 52 /** 53 * Obtains the window name from the component name. 54 * 55 * [ComponentName] builds the string representation as PKG/CLASS, however this doesn't 56 * work for system components such as IME, NavBar and StatusBar, Toast. 57 * 58 * If the component doesn't have a package name, assume it's a system component and return only 59 * the class name 60 */ toWindowNamenull61 fun toWindowName(): String { 62 return when { 63 packageName.isNotEmpty() && className.isNotEmpty() -> "$packageName/$className" 64 packageName.isNotEmpty() -> packageName 65 className.isNotEmpty() -> className 66 else -> error("Component name should have an activity of class name") 67 } 68 } 69 70 /** 71 * Obtains the layer name from the component name. 72 * 73 * See [toWindowName] for additional information 74 */ toLayerNamenull75 fun toLayerName(): String { 76 var result = this.toWindowName() 77 if (result.contains("/") && !result.contains("#")) { 78 result = "$result#" 79 } 80 81 return result 82 } 83 appendShortStringnull84 private fun appendShortString(sb: StringBuilder, packageName: String, className: String) { 85 sb.append(packageName).append('/') 86 appendShortClassName(sb, packageName, className) 87 } 88 appendShortClassNamenull89 private fun appendShortClassName(sb: StringBuilder, packageName: String, className: String) { 90 if (className.startsWith(packageName)) { 91 val packageNameLength = packageName.length 92 val classNameLength = className.length 93 if (classNameLength > packageNameLength && className[packageNameLength] == '.') { 94 sb.append(className, packageNameLength, classNameLength) 95 return 96 } 97 } 98 sb.append(className) 99 } 100 101 companion object { 102 val NAV_BAR = FlickerComponentName("", "NavigationBar0") 103 val STATUS_BAR = FlickerComponentName("", "StatusBar") 104 val ROTATION = FlickerComponentName("", "RotationLayer") 105 val BACK_SURFACE = FlickerComponentName("", "BackColorSurface") 106 val IME = FlickerComponentName("", "InputMethod") 107 val SPLASH_SCREEN = FlickerComponentName("", "Splash Screen") 108 val SNAPSHOT = FlickerComponentName("", "SnapshotStartingWindow") 109 val WALLPAPER_BBQ_WRAPPER = 110 FlickerComponentName("", "Wallpaper BBQ wrapper") 111 unflattenFromStringnull112 fun unflattenFromString(str: String): FlickerComponentName { 113 val sep = str.indexOf('/') 114 if (sep < 0 || sep + 1 >= str.length) { 115 error("Missing package/class separator") 116 } 117 val pkg = str.substring(0, sep) 118 var cls = str.substring(sep + 1) 119 if (cls.isNotEmpty() && cls[0] == '.') { 120 cls = pkg + cls 121 } 122 return FlickerComponentName(pkg, cls) 123 } 124 } 125 }