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

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

Do not show unavailable tiles in edit mode.

Filter out tiles that are unavailable (cannot be added). For new tiles
we use QSTileAvailabilityInteractor (part of the QSTileDataInteractor),
but if the flag is off or the tile has not been migrated yet, we default
to constructing the tile, checking its availability and then destroying
it (similar to TileQueryHelper).

Test: atest com.android.systemui.qs.panels
Fixes: 339262140
Flag: com.android.systemui.qs_new_tiles
Flag: com.android.systemui.qs_ui_refactor

Change-Id: I1e91a6c1ab0185d201bfe853af223363280f8ec4
parent 0692fa9e
Loading
Loading
Loading
Loading
+98 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.panels.domain.interactor

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tiles.base.interactor.QSTileAvailabilityInteractor
import com.android.systemui.statusbar.connectivity.ConnectivityModule.Companion.AIRPLANE_MODE_TILE_SPEC
import com.android.systemui.statusbar.connectivity.ConnectivityModule.Companion.HOTSPOT_TILE_SPEC
import com.android.systemui.statusbar.policy.PolicyModule.Companion.WORK_MODE_TILE_SPEC
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
@SmallTest
class NewTilesAvailabilityInteractorTest : SysuiTestCase() {
    private val kosmos = testKosmos().apply {
        tileAvailabilityInteractorsMap = buildMap {
            put(AIRPLANE_MODE_TILE_SPEC, QSTileAvailabilityInteractor.AlwaysAvailableInteractor)
            put(WORK_MODE_TILE_SPEC, FakeTileAvailabilityInteractor(
                    mapOf(
                       fakeUserRepository.getSelectedUserInfo().id to flowOf(true),
                    ).withDefault { flowOf(false) }
            ))
            put(HOTSPOT_TILE_SPEC, FakeTileAvailabilityInteractor(
                    emptyMap<Int, Flow<Boolean>>().withDefault { flowOf(false) }
            ))
        }
    }

    private val underTest by lazy { kosmos.newTilesAvailabilityInteractor }

    @Test
    fun defaultUser_getAvailabilityFlow() = with(kosmos) {
        testScope.runTest {
            val availability by collectLastValue(underTest.newTilesAvailable)

            assertThat(availability).isEqualTo(
                    mapOf(
                            TileSpec.create(AIRPLANE_MODE_TILE_SPEC) to true,
                            TileSpec.create(WORK_MODE_TILE_SPEC) to true,
                            TileSpec.create(HOTSPOT_TILE_SPEC) to false,
                    )
            )
        }
    }

    @Test
    fun getAvailabilityFlow_userChange() = with(kosmos) {
        testScope.runTest {
            val availability by collectLastValue(underTest.newTilesAvailable)
            fakeUserRepository.asMainUser()

            assertThat(availability).isEqualTo(
                    mapOf(
                            TileSpec.create(AIRPLANE_MODE_TILE_SPEC) to true,
                            TileSpec.create(WORK_MODE_TILE_SPEC) to false,
                            TileSpec.create(HOTSPOT_TILE_SPEC) to false,
                    )
            )
        }
    }

    @Test
    fun noAvailabilityInteractor_emptyMap() = with(kosmos) {
        testScope.runTest {
            tileAvailabilityInteractorsMap = emptyMap()

            val availability by collectLastValue(underTest.newTilesAvailable)

            assertThat(availability).isEmpty()
        }
    }
}
+228 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.panels.domain.interactor

import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_QS_NEW_TILES
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.qs.QSFactory
import com.android.systemui.qs.FakeQSFactory
import com.android.systemui.qs.FakeQSTile
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.qsTileFactory
import com.android.systemui.qs.tiles.base.interactor.QSTileAvailabilityInteractor
import com.android.systemui.statusbar.connectivity.ConnectivityModule.Companion.AIRPLANE_MODE_TILE_SPEC
import com.android.systemui.statusbar.connectivity.ConnectivityModule.Companion.HOTSPOT_TILE_SPEC
import com.android.systemui.statusbar.connectivity.ConnectivityModule.Companion.INTERNET_TILE_SPEC
import com.android.systemui.statusbar.policy.PolicyModule.Companion.FLASHLIGHT_TILE_SPEC
import com.android.systemui.statusbar.policy.PolicyModule.Companion.WORK_MODE_TILE_SPEC
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.user.data.repository.userRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters

@RunWith(ParameterizedAndroidJunit4::class)
@SmallTest
class TilesAvailabilityInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {

    init {
        mSetFlagsRule.setFlagsParameterization(flags)
    }

    private val createdTiles = mutableListOf<FakeQSTile>()

    private val kosmos = testKosmos().apply {
        tileAvailabilityInteractorsMap = buildMap {
            put(AIRPLANE_MODE_TILE_SPEC, QSTileAvailabilityInteractor.AlwaysAvailableInteractor)
            put(WORK_MODE_TILE_SPEC, FakeTileAvailabilityInteractor(
                    mapOf(
                            fakeUserRepository.getSelectedUserInfo().id to flowOf(true),
                    ).withDefault { flowOf(false) }
            ))
            put(HOTSPOT_TILE_SPEC, FakeTileAvailabilityInteractor(
                    emptyMap<Int, Flow<Boolean>>().withDefault { flowOf(false) }
            ))
        }

        qsTileFactory = constantFactory(
                tilesForCreator(
                        userRepository.getSelectedUserInfo().id,
                        mapOf(
                                AIRPLANE_MODE_TILE_SPEC to false,
                                WORK_MODE_TILE_SPEC to false,
                                HOTSPOT_TILE_SPEC to true,
                                INTERNET_TILE_SPEC to true,
                                FLASHLIGHT_TILE_SPEC to false,
                        )
                )
        )
    }

    private val underTest by lazy { kosmos.tilesAvailabilityInteractor }

    @Test
    @DisableFlags(FLAG_QS_NEW_TILES)
    fun flagOff_usesAvailabilityFromFactoryTiles() = with(kosmos) {
        testScope.runTest {
            val unavailableTiles = underTest.getUnavailableTiles(
                    setOf(
                            AIRPLANE_MODE_TILE_SPEC,
                            WORK_MODE_TILE_SPEC,
                            HOTSPOT_TILE_SPEC,
                            INTERNET_TILE_SPEC,
                            FLASHLIGHT_TILE_SPEC,
                    ).map(TileSpec::create)
            )
            assertThat(unavailableTiles).isEqualTo(setOf(
                    AIRPLANE_MODE_TILE_SPEC,
                    WORK_MODE_TILE_SPEC,
                    FLASHLIGHT_TILE_SPEC,
            ).mapTo(mutableSetOf(), TileSpec::create))
        }
    }

    @Test
    fun tileCannotBeCreated_isUnavailable() = with(kosmos) {
        testScope.runTest {
            val badSpec = TileSpec.create("unknown")
            val unavailableTiles = underTest.getUnavailableTiles(
                    setOf(
                        badSpec
                    )
            )
            assertThat(unavailableTiles).contains(badSpec)
        }
    }

    @Test
    @EnableFlags(FLAG_QS_NEW_TILES)
    fun flagOn_defaultsToInteractorTiles_usesFactoryForOthers() = with(kosmos) {
        testScope.runTest {
            val unavailableTiles = underTest.getUnavailableTiles(
                    setOf(
                            AIRPLANE_MODE_TILE_SPEC,
                            WORK_MODE_TILE_SPEC,
                            HOTSPOT_TILE_SPEC,
                            INTERNET_TILE_SPEC,
                            FLASHLIGHT_TILE_SPEC,
                    ).map(TileSpec::create)
            )
            assertThat(unavailableTiles).isEqualTo(setOf(
                    HOTSPOT_TILE_SPEC,
                    FLASHLIGHT_TILE_SPEC,
            ).mapTo(mutableSetOf(), TileSpec::create))
        }
    }

    @Test
    @EnableFlags(FLAG_QS_NEW_TILES)
    fun flagOn_defaultsToInteractorTiles_usesFactoryForOthers_userChange() = with(kosmos) {
        testScope.runTest {
            fakeUserRepository.asMainUser()
            val unavailableTiles = underTest.getUnavailableTiles(
                    setOf(
                            AIRPLANE_MODE_TILE_SPEC,
                            WORK_MODE_TILE_SPEC,
                            HOTSPOT_TILE_SPEC,
                            INTERNET_TILE_SPEC,
                            FLASHLIGHT_TILE_SPEC,
                    ).map(TileSpec::create)
            )
            assertThat(unavailableTiles).isEqualTo(setOf(
                    WORK_MODE_TILE_SPEC,
                    HOTSPOT_TILE_SPEC,
                    FLASHLIGHT_TILE_SPEC,
            ).mapTo(mutableSetOf(), TileSpec::create))
        }
    }

    @Test
    @EnableFlags(FLAG_QS_NEW_TILES)
    fun flagOn_onlyNeededTilesAreCreated_andThenDestroyed() = with(kosmos) {
        testScope.runTest {
            underTest.getUnavailableTiles(
                    setOf(
                            AIRPLANE_MODE_TILE_SPEC,
                            WORK_MODE_TILE_SPEC,
                            HOTSPOT_TILE_SPEC,
                            INTERNET_TILE_SPEC,
                            FLASHLIGHT_TILE_SPEC,
                    ).map(TileSpec::create)
            )
            assertThat(createdTiles.map { it.tileSpec })
                    .containsExactly(INTERNET_TILE_SPEC, FLASHLIGHT_TILE_SPEC)
            assertThat(createdTiles.all { it.destroyed }).isTrue()
        }
    }

    @Test
    @DisableFlags(FLAG_QS_NEW_TILES)
    fun flagOn_TilesAreCreatedAndThenDestroyed() = with(kosmos) {
        testScope.runTest {
            val allTiles = setOf(
                    AIRPLANE_MODE_TILE_SPEC,
                    WORK_MODE_TILE_SPEC,
                    HOTSPOT_TILE_SPEC,
                    INTERNET_TILE_SPEC,
                    FLASHLIGHT_TILE_SPEC,
                )
            underTest.getUnavailableTiles(allTiles.map(TileSpec::create))
            assertThat(createdTiles.map { it.tileSpec })
                    .containsExactlyElementsIn(allTiles)
            assertThat(createdTiles.all { it.destroyed }).isTrue()
        }
    }


    private fun constantFactory(creatorTiles: Set<FakeQSTile>): QSFactory {
        return FakeQSFactory { spec ->
            creatorTiles.firstOrNull { it.tileSpec == spec }?.also {
                createdTiles.add(it)
            }
        }
    }

    companion object {
        private fun tilesForCreator(
                user: Int,
                specAvailabilities: Map<String, Boolean>
        ): Set<FakeQSTile> {
            return specAvailabilities.mapTo(mutableSetOf()) {
                FakeQSTile(user, it.value).apply {
                    tileSpec = it.key
                }
            }
        }

        @JvmStatic
        @Parameters(name = "{0}")
        fun getParams(): List<FlagsParameterization> {
            return FlagsParameterization.allCombinationsOf(FLAG_QS_NEW_TILES)
        }
    }
}
+62 −33
Original line number Diff line number Diff line
@@ -19,30 +19,27 @@ package com.android.systemui.qs.panels.ui.viewmodel
import android.R
import android.content.ComponentName
import android.graphics.drawable.TestStubDrawable
import androidx.test.ext.junit.runners.AndroidJUnit4
import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
import com.android.systemui.qs.FakeQSFactory
import com.android.systemui.qs.FakeQSTile
import com.android.systemui.qs.panels.data.repository.stockTilesRepository
import com.android.systemui.qs.panels.domain.interactor.editTilesListInteractor
import com.android.systemui.qs.panels.domain.interactor.gridLayoutMap
import com.android.systemui.qs.panels.domain.interactor.gridLayoutTypeInteractor
import com.android.systemui.qs.panels.domain.interactor.infiniteGridLayout
import com.android.systemui.qs.panels.domain.interactor.FakeTileAvailabilityInteractor
import com.android.systemui.qs.panels.domain.interactor.tileAvailabilityInteractorsMap
import com.android.systemui.qs.panels.shared.model.EditTileData
import com.android.systemui.qs.pipeline.data.repository.FakeInstalledTilesComponentRepository
import com.android.systemui.qs.pipeline.data.repository.MinimumTilesFixedRepository
import com.android.systemui.qs.pipeline.data.repository.fakeInstalledTilesRepository
import com.android.systemui.qs.pipeline.data.repository.fakeMinimumTilesRepository
import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
import com.android.systemui.qs.pipeline.domain.interactor.minimumTilesInteractor
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.qsTileFactory
import com.android.systemui.qs.tiles.impl.alarm.qsAlarmTileConfig
@@ -57,14 +54,23 @@ import com.android.systemui.qs.tiles.viewmodel.qSTileConfigProvider
import com.android.systemui.settings.userTracker
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters

@RunWith(AndroidJUnit4::class)
@RunWith(ParameterizedAndroidJunit4::class)
@SmallTest
class EditModeViewModelTest : SysuiTestCase() {
class EditModeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {

    init {
        mSetFlagsRule.setFlagsParameterization(flags)
    }

    private val kosmos = testKosmos()

    // Only have some configurations so we can test the effect of missing configurations.
@@ -98,17 +104,7 @@ class EditModeViewModelTest : SysuiTestCase() {
        )

    private val underTest: EditModeViewModel by lazy {
        with(kosmos) {
            EditModeViewModel(
                editTilesListInteractor,
                currentTilesInteractor,
                minimumTilesInteractor,
                infiniteGridLayout,
                applicationCoroutineScope,
                gridLayoutTypeInteractor,
                gridLayoutMap,
            )
        }
        kosmos.editModeViewModel
    }

    @Before
@@ -464,18 +460,45 @@ class EditModeViewModelTest : SysuiTestCase() {
            }
        }

    private companion object {
        val drawable1 = TestStubDrawable("drawable1")
        val appName1 = "App1"
        val tileService1 = "Tile Service 1"
        val component1 = ComponentName("pkg1", "srv1")
    @Test
    fun tileNotAvailable_notShowing() = with(kosmos) {
        testScope.runTest {
            val unavailableTile = "work"
            qsTileFactory = FakeQSFactory { spec ->
                FakeQSTile(userTracker.userId, spec != unavailableTile)
            }
            tileAvailabilityInteractorsMap = mapOf(
                    unavailableTile to FakeTileAvailabilityInteractor(
                            emptyMap<Int, Flow<Boolean>>().withDefault { flowOf(false) }
                    )
            )
            val tiles by collectLastValue(underTest.tiles)
            val currentTiles =
                    mutableListOf(
                            TileSpec.create("flashlight"),
                            TileSpec.create("airplane"),
                            TileSpec.create("alarm"),
                    )
            currentTilesInteractor.setTiles(currentTiles)

        val drawable2 = TestStubDrawable("drawable2")
        val appName2 = "App2"
        val tileService2 = "Tile Service 2"
        val component2 = ComponentName("pkg2", "srv2")
            underTest.startEditing()

        fun TileSpec.missingConfigEditTileData(): EditTileData {
            assertThat(tiles!!.none { it.tileSpec == TileSpec.create(unavailableTile) }).isTrue()
        }
    }

    companion object {
        private val drawable1 = TestStubDrawable("drawable1")
        private val appName1 = "App1"
        private val tileService1 = "Tile Service 1"
        private val component1 = ComponentName("pkg1", "srv1")

        private val drawable2 = TestStubDrawable("drawable2")
        private val appName2 = "App2"
        private val tileService2 = "Tile Service 2"
        private val component2 = ComponentName("pkg2", "srv2")

        private fun TileSpec.missingConfigEditTileData(): EditTileData {
            return EditTileData(
                tileSpec = this,
                icon = Icon.Resource(R.drawable.star_on, ContentDescription.Loaded(spec)),
@@ -484,7 +507,7 @@ class EditModeViewModelTest : SysuiTestCase() {
            )
        }

        fun QSTileConfig.toEditTileData(): EditTileData {
        private fun QSTileConfig.toEditTileData(): EditTileData {
            return EditTileData(
                tileSpec = tileSpec,
                icon =
@@ -494,7 +517,7 @@ class EditModeViewModelTest : SysuiTestCase() {
            )
        }

        fun Kosmos.getEditTileData(tileSpec: TileSpec): EditTileData {
        private fun Kosmos.getEditTileData(tileSpec: TileSpec): EditTileData {
            return if (qSTileConfigProvider.hasConfig(tileSpec.spec)) {
                qSTileConfigProvider.getConfig(tileSpec.spec).toEditTileData()
            } else {
@@ -502,6 +525,12 @@ class EditModeViewModelTest : SysuiTestCase() {
            }
        }

        val minNumberOfTiles = 3
        private val minNumberOfTiles = 3

        @JvmStatic
        @Parameters(name = "{0}")
        fun getParams(): List<FlagsParameterization> {
            return FlagsParameterization.allCombinationsOf(Flags.FLAG_QS_NEW_TILES)
        }
    }
}
+43 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import com.android.systemui.qs.tiles.HearingDevicesTile
import com.android.systemui.qs.tiles.NightDisplayTile
import com.android.systemui.qs.tiles.OneHandedModeTile
import com.android.systemui.qs.tiles.ReduceBrightColorsTile
import com.android.systemui.qs.tiles.base.interactor.QSTileAvailabilityInteractor
import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory
import com.android.systemui.qs.tiles.impl.colorcorrection.domain.ColorCorrectionTileMapper
import com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor.ColorCorrectionTileDataInteractor
@@ -115,6 +116,48 @@ interface QSAccessibilityModule {
    @StringKey(HearingDevicesTile.TILE_SPEC)
    fun bindHearingDevicesTile(hearingDevicesTile: HearingDevicesTile): QSTileImpl<*>

    @Binds
    @IntoMap
    @StringKey(COLOR_CORRECTION_TILE_SPEC)
    fun provideColorCorrectionAvailabilityInteractor(
            impl: ColorCorrectionTileDataInteractor
    ): QSTileAvailabilityInteractor

    @Binds
    @IntoMap
    @StringKey(COLOR_INVERSION_TILE_SPEC)
    fun provideColorInversionAvailabilityInteractor(
            impl: ColorCorrectionTileDataInteractor
    ): QSTileAvailabilityInteractor

    @Binds
    @IntoMap
    @StringKey(FONT_SCALING_TILE_SPEC)
    fun provideFontScalingAvailabilityInteractor(
            impl: FontScalingTileDataInteractor
    ): QSTileAvailabilityInteractor

    @Binds
    @IntoMap
    @StringKey(REDUCE_BRIGHTNESS_TILE_SPEC)
    fun provideReduceBrightnessAvailabilityInteractor(
            impl: ReduceBrightColorsTileDataInteractor
    ): QSTileAvailabilityInteractor

    @Binds
    @IntoMap
    @StringKey(ONE_HANDED_TILE_SPEC)
    fun provideOneHandedAvailabilityInteractor(
            impl: OneHandedModeTileDataInteractor
    ): QSTileAvailabilityInteractor

    @Binds
    @IntoMap
    @StringKey(NIGHT_DISPLAY_TILE_SPEC)
    fun provideNightDisplayAvailabilityInteractor(
            impl: NightDisplayTileDataInteractor
    ): QSTileAvailabilityInteractor

    companion object {
        const val COLOR_CORRECTION_TILE_SPEC = "color_correction"
        const val COLOR_INVERSION_TILE_SPEC = "inversion"
+8 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.qs.tiles.BatterySaverTile
import com.android.systemui.qs.tiles.base.interactor.QSTileAvailabilityInteractor
import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory
import com.android.systemui.qs.tiles.impl.battery.domain.interactor.BatterySaverTileDataInteractor
import com.android.systemui.qs.tiles.impl.battery.domain.interactor.BatterySaverTileUserActionInteractor
@@ -28,6 +29,13 @@ interface BatterySaverModule {
    @StringKey(BatterySaverTile.TILE_SPEC)
    fun bindBatterySaverTile(batterySaverTile: BatterySaverTile): QSTileImpl<*>

    @Binds
    @IntoMap
    @StringKey(BATTERY_SAVER_TILE_SPEC)
    fun provideBatterySaverAvailabilityInteractor(
            impl: BatterySaverTileDataInteractor
    ): QSTileAvailabilityInteractor

    companion object {
        private const val BATTERY_SAVER_TILE_SPEC = "battery"

Loading