diff options
9 files changed, 148 insertions, 0 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataInteractor.kt new file mode 100644 index 000000000000..1a03481b9fca --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataInteractor.kt @@ -0,0 +1,26 @@ +package com.android.systemui.qs.tiles.base.interactor + +import com.android.systemui.qs.tiles.viewmodel.QSTileState +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow + +/** + * Provides data and availability for the tile. In most cases it would delegate data retrieval to + * repository, manager, controller or a combination of those. Avoid doing long running operations in + * these methods because there is no background thread guarantee. Use [Flow.flowOn] (typically + * with @Background [CoroutineDispatcher]) instead to move the calculations to another thread. + */ +interface QSTileDataInteractor<DATA_TYPE> { + + /** + * Returns the data to be mapped to [QSTileState]. Make sure to start the flow [Flow.onStart] + * with the current state to update the tile as soon as possible. + */ + fun tileData(qsTileDataRequest: QSTileDataRequest): Flow<DATA_TYPE> + + /** + * Returns tile availability - whether this device currently supports this tile. Make sure to + * start the flow [Flow.onStart] with the current state to update the tile as soon as possible. + */ + fun availability(): Flow<Boolean> +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataRequest.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataRequest.kt new file mode 100644 index 000000000000..82897044f06c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataRequest.kt @@ -0,0 +1,6 @@ +package com.android.systemui.qs.tiles.base.interactor + +data class QSTileDataRequest( + val userId: Int, + val trigger: StateUpdateTrigger, +) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt new file mode 100644 index 000000000000..8569fc73adb4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt @@ -0,0 +1,13 @@ +package com.android.systemui.qs.tiles.base.interactor + +import android.annotation.WorkerThread +import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction + +interface QSTileUserActionInteractor<DATA_TYPE> { + + /** + * Processes user input based on [userAction] and [currentData]. It's safe to run long running + * computations inside this function in this. + */ + @WorkerThread suspend fun handleInput(userAction: QSTileUserAction, currentData: DATA_TYPE) +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/StateUpdateTrigger.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/StateUpdateTrigger.kt new file mode 100644 index 000000000000..ed7ec8e32de4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/StateUpdateTrigger.kt @@ -0,0 +1,11 @@ +package com.android.systemui.qs.tiles.base.interactor + +import com.android.systemui.qs.tiles.viewmodel.QSTileState +import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction + +sealed interface StateUpdateTrigger { + class UserAction<T>(val action: QSTileUserAction, val tileState: QSTileState, val tileData: T) : + StateUpdateTrigger + data object ForceUpdate : StateUpdateTrigger + data object InitialRequest : StateUpdateTrigger +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt new file mode 100644 index 000000000000..a5eaac154230 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt @@ -0,0 +1,14 @@ +package com.android.systemui.qs.tiles.viewmodel + +import android.graphics.drawable.Icon +import com.android.systemui.qs.pipeline.shared.TileSpec + +data class QSTileConfig( + val tileSpec: TileSpec, + val tileIcon: Icon, + val tileLabel: CharSequence, +// TODO(b/299908705): Fill necessary params +/* +val instanceId: InstanceId, + */ +) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileLifecycle.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileLifecycle.kt new file mode 100644 index 000000000000..39db7038bfa2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileLifecycle.kt @@ -0,0 +1,6 @@ +package com.android.systemui.qs.tiles.viewmodel + +enum class QSTileLifecycle { + ON_CREATE, + ON_DESTROY, +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt new file mode 100644 index 000000000000..53f9edfb954c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt @@ -0,0 +1,18 @@ +package com.android.systemui.qs.tiles.viewmodel + +import android.graphics.drawable.Icon + +data class QSTileState( + val icon: Icon, + val label: CharSequence, +// TODO(b/299908705): Fill necessary params +/* + val subtitle: CharSequence = "", + val activeState: ActivationState = Active, + val enabledState: Enabled = Enabled, + val loopIconAnimation: Boolean = false, + val secondaryIcon: Icon? = null, + val slashState: SlashState? = null, + val supportedActions: Collection<UserAction> = listOf(Click), clicks should be a default action +*/ +) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt new file mode 100644 index 000000000000..f1f8f0152c67 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt @@ -0,0 +1,13 @@ +package com.android.systemui.qs.tiles.viewmodel + +import android.content.Context +import android.view.View + +sealed interface QSTileUserAction { + + val context: Context + val view: View? + + class Click(override val context: Context, override val view: View?) : QSTileUserAction + class LongClick(override val context: Context, override val view: View?) : QSTileUserAction +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt new file mode 100644 index 000000000000..49077f3f310d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt @@ -0,0 +1,41 @@ +package com.android.systemui.qs.tiles.viewmodel + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow + +/** + * Represents tiles behaviour logic. This ViewModel is a connection between tile view and data + * layers. + */ +interface QSTileViewModel { + + /** + * State of the tile to be shown by the view. Favor reactive consumption over the + * [StateFlow.value], because there is no guarantee that current value would be available at any + * time. + */ + val state: StateFlow<QSTileState> + + val config: QSTileConfig + + val isAvailable: Flow<Boolean> + + /** + * Handles ViewModel lifecycle. Implementations should be inactive outside of + * [QSTileLifecycle.ON_CREATE] and [QSTileLifecycle.ON_DESTROY] bounds. + */ + fun onLifecycle(lifecycle: QSTileLifecycle) + + /** + * Notifies about the user change. Implementations should avoid using 3rd party userId sources + * and use this value instead. This is to maintain consistent and concurrency-free behaviour + * across different parts of QS. + */ + fun onUserIdChanged(userId: Int) + + /** Triggers emit of the new [QSTileState] in [state]. */ + fun forceUpdate() + + /** Notifies underlying logic about user input. */ + fun onActionPerformed(userAction: QSTileUserAction) +} |