• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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.tiles
18 
19 import android.content.Intent
20 import android.os.Handler
21 import android.os.Looper
22 import androidx.annotation.DrawableRes
23 import androidx.annotation.VisibleForTesting
24 import androidx.lifecycle.Lifecycle
25 import androidx.lifecycle.coroutineScope
26 import androidx.lifecycle.repeatOnLifecycle
27 import com.android.app.tracing.coroutines.launchTraced as launch
28 import com.android.internal.logging.MetricsLogger
29 import com.android.systemui.animation.Expandable
30 import com.android.systemui.dagger.qualifiers.Background
31 import com.android.systemui.dagger.qualifiers.Main
32 import com.android.systemui.modes.shared.ModesUi
33 import com.android.systemui.plugins.ActivityStarter
34 import com.android.systemui.plugins.FalsingManager
35 import com.android.systemui.plugins.qs.QSTile.BooleanState
36 import com.android.systemui.plugins.statusbar.StatusBarStateController
37 import com.android.systemui.qs.QSHost
38 import com.android.systemui.qs.QsEventLogger
39 import com.android.systemui.qs.asQSTileIcon
40 import com.android.systemui.qs.flags.QsInCompose
41 import com.android.systemui.qs.logging.QSLogger
42 import com.android.systemui.qs.tileimpl.QSTileImpl
43 import com.android.systemui.qs.tiles.base.shared.model.QSTileConfigProvider
44 import com.android.systemui.qs.tiles.base.shared.model.QSTileState
45 import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesDndTileDataInteractor
46 import com.android.systemui.qs.tiles.impl.modes.domain.interactor.ModesDndTileUserActionInteractor
47 import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesDndTileModel
48 import com.android.systemui.qs.tiles.impl.modes.ui.ModesDndTileMapper
49 import com.android.systemui.res.R
50 import javax.inject.Inject
51 import kotlinx.coroutines.runBlocking
52 
53 /**
54  * Standalone tile used to control the DND Mode. Contrast to [ModesTile] (the tile that opens a
55  * dialog showing the list of all modes) and [DndTile] (the tile used to toggle interruption
56  * filtering in the pre-MODES_UI world).
57  */
58 class ModesDndTile
59 @Inject
60 constructor(
61     host: QSHost,
62     uiEventLogger: QsEventLogger,
63     @Background backgroundLooper: Looper,
64     @Main mainHandler: Handler,
65     falsingManager: FalsingManager,
66     metricsLogger: MetricsLogger,
67     statusBarStateController: StatusBarStateController,
68     activityStarter: ActivityStarter,
69     qsLogger: QSLogger,
70     qsTileConfigProvider: QSTileConfigProvider,
71     private val dataInteractor: ModesDndTileDataInteractor,
72     private val tileMapper: ModesDndTileMapper,
73     private val userActionInteractor: ModesDndTileUserActionInteractor,
74 ) :
75     QSTileImpl<BooleanState>(
76         host,
77         uiEventLogger,
78         backgroundLooper,
79         mainHandler,
80         falsingManager,
81         metricsLogger,
82         statusBarStateController,
83         activityStarter,
84         qsLogger,
85     ) {
86 
87     private lateinit var tileState: QSTileState
88     private val config = qsTileConfigProvider.getConfig(TILE_SPEC)
89 
90     init {
<lambda>null91         lifecycle.coroutineScope.launch {
92             lifecycle.repeatOnLifecycle(
93                 // TODO: b/403434908 - Workaround for "not listening to tile updates". Can be reset
94                 //   to RESUMED if either b/403434908 is fixed or QsInCompose is inlined.
95                 if (QsInCompose.isEnabled) Lifecycle.State.RESUMED else Lifecycle.State.CREATED
96             ) {
97                 dataInteractor.tileData().collect { refreshState(it) }
98             }
99         }
100     }
101 
isAvailablenull102     override fun isAvailable(): Boolean = ModesUi.isEnabled && android.app.Flags.modesUiDndTile()
103 
104     override fun getTileLabel(): CharSequence =
105         mContext.getString(R.string.quick_settings_dnd_label)
106 
107     override fun newTileState(): BooleanState = BooleanState()
108 
109     override fun handleClick(expandable: Expandable?) = runBlocking {
110         userActionInteractor.handleClick()
111     }
112 
getLongClickIntentnull113     override fun getLongClickIntent(): Intent? = userActionInteractor.getSettingsIntent()
114 
115     @VisibleForTesting
116     public override fun handleUpdateState(state: BooleanState?, arg: Any?) {
117         val model = arg as? ModesDndTileModel ?: dataInteractor.getCurrentTileModel()
118 
119         tileState = tileMapper.map(config, model)
120         state?.apply {
121             value = model.isActivated
122             this.state = tileState.activationState.legacyState
123             icon =
124                 tileState.icon?.asQSTileIcon()
125                     ?: maybeLoadResourceIcon(iconResId(model.isActivated))
126             label = tileLabel
127             secondaryLabel = tileState.secondaryLabel
128             contentDescription = tileState.contentDescription
129             stateDescription = tileState.stateDescription
130             expandedAccessibilityClassName = tileState.expandedAccessibilityClassName
131         }
132     }
133 
134     @DrawableRes
iconResIdnull135     private fun iconResId(activated: Boolean): Int =
136         if (activated) R.drawable.qs_dnd_icon_on else R.drawable.qs_dnd_icon_off
137 
138     companion object {
139         const val TILE_SPEC = "modes_dnd"
140     }
141 }
142