blob: 203177acd7c8d8fe107e03060fc40a30840fd996 [file] [edit]
/*
* 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.quickstep.task.util
import android.util.Log
import android.view.View.OnLayoutChangeListener
import com.android.quickstep.TaskOverlayFactory
import com.android.quickstep.recents.di.RecentsDependencies
import com.android.quickstep.recents.di.get
import com.android.quickstep.task.thumbnail.TaskOverlayUiState
import com.android.quickstep.task.thumbnail.TaskOverlayUiState.Disabled
import com.android.quickstep.task.thumbnail.TaskOverlayUiState.Enabled
import com.android.quickstep.task.viewmodel.TaskOverlayViewModel
import com.android.systemui.shared.recents.model.Task
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
/**
* Helper for [TaskOverlayFactory.TaskOverlay] to interact with [TaskOverlayViewModel], this helper
* should merge with [TaskOverlayFactory.TaskOverlay] when it's migrated to MVVM.
*/
class TaskOverlayHelper(val task: Task, val overlay: TaskOverlayFactory.TaskOverlay<*>) {
private lateinit var overlayInitializedScope: CoroutineScope
private var uiState: TaskOverlayUiState = Disabled
private lateinit var viewModel: TaskOverlayViewModel
// TODO(b/331753115): TaskOverlay should listen for state changes and react.
val enabledState: Enabled
get() = uiState as Enabled
private val snapshotLayoutChangeListener = OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
(uiState as? Enabled)?.let { initOverlay(it) }
}
fun getThumbnailMatrix() = getThumbnailPositionState().matrix
private fun getThumbnailPositionState() =
viewModel.getThumbnailPositionState(
overlay.snapshotView.width,
overlay.snapshotView.height,
overlay.snapshotView.isLayoutRtl,
)
fun init() {
overlayInitializedScope =
CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("TaskOverlayHelper"))
viewModel =
TaskOverlayViewModel(
task = task,
recentsViewData = RecentsDependencies.get(),
getThumbnailPositionUseCase = RecentsDependencies.get(),
recentTasksRepository = RecentsDependencies.get(),
)
viewModel.overlayState
.onEach {
uiState = it
if (it is Enabled) {
initOverlay(it)
} else {
reset()
}
}
.launchIn(overlayInitializedScope)
overlay.snapshotView.addOnLayoutChangeListener(snapshotLayoutChangeListener)
}
private fun initOverlay(enabledState: Enabled) {
if (DEBUG) {
Log.d(TAG, "initOverlay - taskId: ${task.key.id}, thumbnail: ${enabledState.thumbnail}")
}
with(getThumbnailPositionState()) {
overlay.initOverlay(task, enabledState.thumbnail, matrix, isRotated)
}
}
private fun reset() {
if (DEBUG) {
Log.d(TAG, "reset - taskId: ${task.key.id}")
}
overlay.reset()
}
fun destroy() {
overlayInitializedScope.cancel()
uiState = Disabled
overlay.snapshotView.removeOnLayoutChangeListener(snapshotLayoutChangeListener)
reset()
}
companion object {
private const val TAG = "TaskOverlayHelper"
private const val DEBUG = false
}
}