Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt 0 → 100644 +49 −0 Original line number Original line 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.tiles.impl.modes.domain.interactor import android.platform.test.annotations.EnableFlags import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel import com.google.common.truth.Truth import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) @EnableFlags(android.app.Flags.FLAG_MODES_UI) class ModesTileUserActionInteractorTest : SysuiTestCase() { private val inputHandler = FakeQSTileIntentUserInputHandler() val underTest = ModesTileUserActionInteractor(inputHandler) @Test fun handleLongClick() = runTest { underTest.handleInput(QSTileInputTestKtx.longClick(ModesTileModel(false))) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { Truth.assertThat(it.intent.action).isEqualTo(Settings.ACTION_ZEN_MODE_SETTINGS) } } } packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt 0 → 100644 +117 −0 Original line number Original line 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.tiles import android.app.Flags import android.content.Intent import android.os.Handler import android.os.Looper import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope import androidx.lifecycle.repeatOnLifecycle import com.android.internal.logging.MetricsLogger import com.android.systemui.animation.Expandable import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.qs.QSTile.BooleanState import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesTileDataInteractor import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesTileUserActionInteractor import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel import com.android.systemui.qs.tiles.impl.modes.ui.ModesTileMapper import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider import com.android.systemui.qs.tiles.viewmodel.QSTileState import com.android.systemui.res.R import javax.inject.Inject import kotlinx.coroutines.launch class ModesTile @Inject constructor( host: QSHost, uiEventLogger: QsEventLogger, @Background backgroundLooper: Looper, @Main mainHandler: Handler, falsingManager: FalsingManager, metricsLogger: MetricsLogger, statusBarStateController: StatusBarStateController, activityStarter: ActivityStarter, qsLogger: QSLogger, qsTileConfigProvider: QSTileConfigProvider, dataInteractor: ModesTileDataInteractor, private val tileMapper: ModesTileMapper, private val userActionInteractor: ModesTileUserActionInteractor, ) : QSTileImpl<BooleanState>( host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger ) { private lateinit var tileState: QSTileState private val config = qsTileConfigProvider.getConfig(TILE_SPEC) init { lifecycle.coroutineScope.launch { lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) { dataInteractor.tileData().collect { refreshState(it) } } } } override fun isAvailable(): Boolean = Flags.modesUi() override fun getTileLabel(): CharSequence = tileState.label override fun newTileState() = BooleanState() override fun handleClick(expandable: Expandable?) { // TODO(b/346519570) open dialog } override fun getLongClickIntent(): Intent = userActionInteractor.longClickIntent override fun handleUpdateState(booleanState: BooleanState?, arg: Any?) { if (arg is ModesTileModel) { tileState = tileMapper.map(config, arg) booleanState?.apply { state = tileState.activationState.legacyState icon = ResourceIcon.get(tileState.iconRes ?: R.drawable.qs_dnd_icon_off) label = tileLabel secondaryLabel = tileState.secondaryLabel contentDescription = tileState.contentDescription } } } companion object { const val TILE_SPEC = "modes" } } packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt +8 −3 Original line number Original line Diff line number Diff line Loading @@ -38,9 +38,14 @@ class ModesTileDataInteractor @Inject constructor(val zenModeRepository: ZenMode override fun tileData( override fun tileData( user: UserHandle, user: UserHandle, triggers: Flow<DataUpdateTrigger> triggers: Flow<DataUpdateTrigger> ): Flow<ModesTileModel> { ): Flow<ModesTileModel> = tileData() return zenModeActive.map { ModesTileModel(isActivated = it) } } /** * An adapted version of the base class' [tileData] method for use in an old-style tile. * * TODO(b/299909989): Remove after the transition. */ fun tileData() = zenModeActive.map { ModesTileModel(isActivated = it) } override fun availability(user: UserHandle): Flow<Boolean> = flowOf(Flags.modesUi()) override fun availability(user: UserHandle): Flow<Boolean> = flowOf(Flags.modesUi()) } } packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt +11 −3 Original line number Original line Diff line number Diff line Loading @@ -16,14 +16,22 @@ package com.android.systemui.qs.tiles.impl.modes.domain.interactor package com.android.systemui.qs.tiles.impl.modes.domain.interactor import android.content.Intent import android.provider.Settings import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction import javax.inject.Inject import javax.inject.Inject class ModesTileUserActionInteractor @Inject constructor() : class ModesTileUserActionInteractor QSTileUserActionInteractor<ModesTileModel> { @Inject constructor( private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler, ) : QSTileUserActionInteractor<ModesTileModel> { val longClickIntent = Intent(Settings.ACTION_ZEN_MODE_SETTINGS) override suspend fun handleInput(input: QSTileInput<ModesTileModel>) { override suspend fun handleInput(input: QSTileInput<ModesTileModel>) { with(input) { with(input) { when (action) { when (action) { Loading @@ -31,7 +39,7 @@ class ModesTileUserActionInteractor @Inject constructor() : // TODO(b/346519570) open dialog // TODO(b/346519570) open dialog } } is QSTileUserAction.LongClick -> { is QSTileUserAction.LongClick -> { // TODO(b/346519570) open settings qsTileIntentUserActionHandler.handle(action.expandable, longClickIntent) } } } } } } Loading packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt +6 −2 Original line number Original line Diff line number Diff line Loading @@ -34,13 +34,17 @@ constructor( ) : QSTileDataToStateMapper<ModesTileModel> { ) : QSTileDataToStateMapper<ModesTileModel> { override fun map(config: QSTileConfig, data: ModesTileModel): QSTileState = override fun map(config: QSTileConfig, data: ModesTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { QSTileState.build(resources, theme, config.uiConfig) { val iconRes = iconRes = if (data.isActivated) { if (data.isActivated) { R.drawable.qs_dnd_icon_on R.drawable.qs_dnd_icon_on } else { } else { R.drawable.qs_dnd_icon_off R.drawable.qs_dnd_icon_off } } val icon = Icon.Loaded(resources.getDrawable(iconRes, theme), contentDescription = null) val icon = Icon.Loaded( resources.getDrawable(iconRes!!, theme), contentDescription = null, ) this.icon = { icon } this.icon = { icon } if (data.isActivated) { if (data.isActivated) { activationState = QSTileState.ActivationState.ACTIVE activationState = QSTileState.ActivationState.ACTIVE Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt 0 → 100644 +49 −0 Original line number Original line 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.tiles.impl.modes.domain.interactor import android.platform.test.annotations.EnableFlags import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel import com.google.common.truth.Truth import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) @EnableFlags(android.app.Flags.FLAG_MODES_UI) class ModesTileUserActionInteractorTest : SysuiTestCase() { private val inputHandler = FakeQSTileIntentUserInputHandler() val underTest = ModesTileUserActionInteractor(inputHandler) @Test fun handleLongClick() = runTest { underTest.handleInput(QSTileInputTestKtx.longClick(ModesTileModel(false))) QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { Truth.assertThat(it.intent.action).isEqualTo(Settings.ACTION_ZEN_MODE_SETTINGS) } } }
packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt 0 → 100644 +117 −0 Original line number Original line 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.tiles import android.app.Flags import android.content.Intent import android.os.Handler import android.os.Looper import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope import androidx.lifecycle.repeatOnLifecycle import com.android.internal.logging.MetricsLogger import com.android.systemui.animation.Expandable import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.qs.QSTile.BooleanState import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesTileDataInteractor import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesTileUserActionInteractor import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel import com.android.systemui.qs.tiles.impl.modes.ui.ModesTileMapper import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider import com.android.systemui.qs.tiles.viewmodel.QSTileState import com.android.systemui.res.R import javax.inject.Inject import kotlinx.coroutines.launch class ModesTile @Inject constructor( host: QSHost, uiEventLogger: QsEventLogger, @Background backgroundLooper: Looper, @Main mainHandler: Handler, falsingManager: FalsingManager, metricsLogger: MetricsLogger, statusBarStateController: StatusBarStateController, activityStarter: ActivityStarter, qsLogger: QSLogger, qsTileConfigProvider: QSTileConfigProvider, dataInteractor: ModesTileDataInteractor, private val tileMapper: ModesTileMapper, private val userActionInteractor: ModesTileUserActionInteractor, ) : QSTileImpl<BooleanState>( host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger ) { private lateinit var tileState: QSTileState private val config = qsTileConfigProvider.getConfig(TILE_SPEC) init { lifecycle.coroutineScope.launch { lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) { dataInteractor.tileData().collect { refreshState(it) } } } } override fun isAvailable(): Boolean = Flags.modesUi() override fun getTileLabel(): CharSequence = tileState.label override fun newTileState() = BooleanState() override fun handleClick(expandable: Expandable?) { // TODO(b/346519570) open dialog } override fun getLongClickIntent(): Intent = userActionInteractor.longClickIntent override fun handleUpdateState(booleanState: BooleanState?, arg: Any?) { if (arg is ModesTileModel) { tileState = tileMapper.map(config, arg) booleanState?.apply { state = tileState.activationState.legacyState icon = ResourceIcon.get(tileState.iconRes ?: R.drawable.qs_dnd_icon_off) label = tileLabel secondaryLabel = tileState.secondaryLabel contentDescription = tileState.contentDescription } } } companion object { const val TILE_SPEC = "modes" } }
packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt +8 −3 Original line number Original line Diff line number Diff line Loading @@ -38,9 +38,14 @@ class ModesTileDataInteractor @Inject constructor(val zenModeRepository: ZenMode override fun tileData( override fun tileData( user: UserHandle, user: UserHandle, triggers: Flow<DataUpdateTrigger> triggers: Flow<DataUpdateTrigger> ): Flow<ModesTileModel> { ): Flow<ModesTileModel> = tileData() return zenModeActive.map { ModesTileModel(isActivated = it) } } /** * An adapted version of the base class' [tileData] method for use in an old-style tile. * * TODO(b/299909989): Remove after the transition. */ fun tileData() = zenModeActive.map { ModesTileModel(isActivated = it) } override fun availability(user: UserHandle): Flow<Boolean> = flowOf(Flags.modesUi()) override fun availability(user: UserHandle): Flow<Boolean> = flowOf(Flags.modesUi()) } }
packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt +11 −3 Original line number Original line Diff line number Diff line Loading @@ -16,14 +16,22 @@ package com.android.systemui.qs.tiles.impl.modes.domain.interactor package com.android.systemui.qs.tiles.impl.modes.domain.interactor import android.content.Intent import android.provider.Settings import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction import javax.inject.Inject import javax.inject.Inject class ModesTileUserActionInteractor @Inject constructor() : class ModesTileUserActionInteractor QSTileUserActionInteractor<ModesTileModel> { @Inject constructor( private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler, ) : QSTileUserActionInteractor<ModesTileModel> { val longClickIntent = Intent(Settings.ACTION_ZEN_MODE_SETTINGS) override suspend fun handleInput(input: QSTileInput<ModesTileModel>) { override suspend fun handleInput(input: QSTileInput<ModesTileModel>) { with(input) { with(input) { when (action) { when (action) { Loading @@ -31,7 +39,7 @@ class ModesTileUserActionInteractor @Inject constructor() : // TODO(b/346519570) open dialog // TODO(b/346519570) open dialog } } is QSTileUserAction.LongClick -> { is QSTileUserAction.LongClick -> { // TODO(b/346519570) open settings qsTileIntentUserActionHandler.handle(action.expandable, longClickIntent) } } } } } } Loading
packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt +6 −2 Original line number Original line Diff line number Diff line Loading @@ -34,13 +34,17 @@ constructor( ) : QSTileDataToStateMapper<ModesTileModel> { ) : QSTileDataToStateMapper<ModesTileModel> { override fun map(config: QSTileConfig, data: ModesTileModel): QSTileState = override fun map(config: QSTileConfig, data: ModesTileModel): QSTileState = QSTileState.build(resources, theme, config.uiConfig) { QSTileState.build(resources, theme, config.uiConfig) { val iconRes = iconRes = if (data.isActivated) { if (data.isActivated) { R.drawable.qs_dnd_icon_on R.drawable.qs_dnd_icon_on } else { } else { R.drawable.qs_dnd_icon_off R.drawable.qs_dnd_icon_off } } val icon = Icon.Loaded(resources.getDrawable(iconRes, theme), contentDescription = null) val icon = Icon.Loaded( resources.getDrawable(iconRes!!, theme), contentDescription = null, ) this.icon = { icon } this.icon = { icon } if (data.isActivated) { if (data.isActivated) { activationState = QSTileState.ActivationState.ACTIVE activationState = QSTileState.ActivationState.ACTIVE Loading