Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a56d656b authored by Fabián Kozynski's avatar Fabián Kozynski
Browse files

Add a TileSpec data type

Test: atest TileSpecTest
Bug: 274108007
Change-Id: I8ddb7bdf89431cfedd6fb6d88a19f1cf3231eec7
parent 0bbf3f59
Loading
Loading
Loading
Loading
+85 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.pipeline.shared

import android.content.ComponentName
import android.text.TextUtils
import com.android.systemui.qs.external.CustomTile

/**
 * Container for the spec that identifies a tile.
 *
 * A tile's [spec] is one of two options:
 * * `custom(<componentName>)`: A [ComponentName] surrounded by [CustomTile.PREFIX] and terminated
 *   by `)`, represents a tile provided by an app, corresponding to a `TileService`.
 * * a string not starting with [CustomTile.PREFIX], representing a tile provided by SystemUI.
 */
sealed class TileSpec private constructor(open val spec: String) {

    /** Represents a spec that couldn't be parsed into a valid type of tile. */
    object Invalid : TileSpec("") {
        override fun toString(): String {
            return "TileSpec.INVALID"
        }
    }

    /** Container for the spec of a tile provided by SystemUI. */
    data class PlatformTileSpec
    internal constructor(
        override val spec: String,
    ) : TileSpec(spec)

    /**
     * Container for the spec of a tile provided by an app.
     *
     * [componentName] indicates the associated `TileService`.
     */
    data class CustomTileSpec
    internal constructor(
        override val spec: String,
        val componentName: ComponentName,
    ) : TileSpec(spec)

    companion object {
        /** Create a [TileSpec] from the string [spec]. */
        fun create(spec: String): TileSpec {
            return if (TextUtils.isEmpty(spec)) {
                Invalid
            } else if (!spec.isCustomTileSpec) {
                PlatformTileSpec(spec)
            } else {
                spec.componentName?.let { CustomTileSpec(spec, it) } ?: Invalid
            }
        }

        private val String.isCustomTileSpec: Boolean
            get() = startsWith(CustomTile.PREFIX)

        private val String.componentName: ComponentName?
            get() =
                if (!isCustomTileSpec) {
                    null
                } else {
                    if (endsWith(")")) {
                        val extracted = substring(CustomTile.PREFIX.length, length - 1)
                        ComponentName.unflattenFromString(extracted)
                    } else {
                        null
                    }
                }
    }
}
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.pipeline.shared

import android.content.ComponentName
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidTestingRunner::class)
class TileSpecTest : SysuiTestCase() {

    @Test
    fun platformTile() {
        val spec = "spec"

        val tileSpec = TileSpec.create(spec)

        assertThat(tileSpec is TileSpec.PlatformTileSpec).isTrue()
        assertThat(tileSpec.spec).isEqualTo(spec)
    }

    @Test
    fun customTile() {
        val componentName = ComponentName("test_pkg", "test_cls")
        val spec = CUSTOM_TILE_PREFIX + componentName.flattenToString() + ")"

        val tileSpec = TileSpec.create(spec)

        assertThat(tileSpec is TileSpec.CustomTileSpec).isTrue()
        assertThat(tileSpec.spec).isEqualTo(spec)
        assertThat((tileSpec as TileSpec.CustomTileSpec).componentName).isEqualTo(componentName)
    }

    @Test
    fun emptyCustomTile_invalid() {
        val spec = CUSTOM_TILE_PREFIX + ")"

        val tileSpec = TileSpec.create(spec)

        assertThat(tileSpec).isEqualTo(TileSpec.Invalid)
    }

    @Test
    fun invalidCustomTileSpec_invalid() {
        val spec = CUSTOM_TILE_PREFIX + "invalid)"

        val tileSpec = TileSpec.create(spec)

        assertThat(tileSpec).isEqualTo(TileSpec.Invalid)
    }

    @Test
    fun customTileNotEndsWithParenthesis_invalid() {
        val componentName = ComponentName("test_pkg", "test_cls")
        val spec = CUSTOM_TILE_PREFIX + componentName.flattenToString()

        val tileSpec = TileSpec.create(spec)

        assertThat(tileSpec).isEqualTo(TileSpec.Invalid)
    }

    @Test
    fun emptySpec_invalid() {
        assertThat(TileSpec.create("")).isEqualTo(TileSpec.Invalid)
    }

    companion object {
        private const val CUSTOM_TILE_PREFIX = "custom("
    }
}