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 com.android.systemui.qs.pipeline.shared 18 19 import android.content.ComponentName 20 import android.text.TextUtils 21 import androidx.compose.runtime.Stable 22 import com.android.systemui.qs.external.CustomTile 23 24 /** 25 * Container for the spec that identifies a tile. 26 * 27 * A tile's [spec] is one of two options: 28 * * `custom(<componentName>)`: A [ComponentName] surrounded by [CustomTile.PREFIX] and terminated 29 * by `)`, represents a tile provided by an app, corresponding to a `TileService`. 30 * * a string not starting with [CustomTile.PREFIX], representing a tile provided by SystemUI. 31 */ 32 sealed class TileSpec private constructor(open val spec: String) { 33 34 /** Represents a spec that couldn't be parsed into a valid type of tile. */ 35 data object Invalid : TileSpec("") 36 37 /** Container for the spec of a tile provided by SystemUI. */ 38 @Stable 39 data class PlatformTileSpec internal constructor(override val spec: String) : TileSpec(spec) { toStringnull40 override fun toString(): String { 41 return "P($spec)" 42 } 43 } 44 45 /** 46 * Container for the spec of a tile provided by an app. 47 * 48 * [componentName] indicates the associated `TileService`. 49 */ 50 @Stable 51 data class CustomTileSpec 52 internal constructor(override val spec: String, val componentName: ComponentName) : 53 TileSpec(spec) { toStringnull54 override fun toString(): String { 55 return "C(${componentName.flattenToShortString()})" 56 } 57 } 58 59 companion object { 60 /** Create a [TileSpec] from the string [spec]. */ 61 @JvmStatic createnull62 fun create(spec: String): TileSpec { 63 return if (TextUtils.isEmpty(spec)) { 64 Invalid 65 } else if (!spec.isCustomTileSpec) { 66 PlatformTileSpec(spec) 67 } else { 68 spec.componentName?.let { CustomTileSpec(spec, it) } ?: Invalid 69 } 70 } 71 createnull72 fun create(component: ComponentName): CustomTileSpec { 73 return CustomTileSpec(CustomTile.toSpec(component), component) 74 } 75 76 private val String.isCustomTileSpec: Boolean 77 get() = startsWith(CustomTile.PREFIX) 78 79 private val String.componentName: ComponentName? 80 get() = 81 if (!isCustomTileSpec) { 82 null 83 } else { 84 if (endsWith(")")) { 85 val extracted = substring(CustomTile.PREFIX.length, length - 1) 86 ComponentName.unflattenFromString(extracted) 87 } else { 88 null 89 } 90 } 91 } 92 } 93 94 val TileSpec.metricSpec 95 get() = 96 when (this) { 97 is TileSpec.Invalid -> "" 98 is TileSpec.PlatformTileSpec -> spec 99 is TileSpec.CustomTileSpec -> componentName.packageName 100 } 101