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