From 82bb7707380cd80bbfb06e3659c29e6b0095417c Mon Sep 17 00:00:00 2001 From: vinayjoglekar Date: Tue, 16 Jul 2024 15:18:55 +0100 Subject: [PATCH] Support sysUiStatusNavFlags for refactored TTV Bug: 350743460 Test: SysUiStatusNavFlagsUseCaseTest Flag: com.android.launcher3.enable_refactor_task_thumbnail Change-Id: Id7576cb2eda14e6c72f34fe3fea3323a104a5164 --- .../recents/di/RecentsDependencies.kt | 3 + .../usecase/SysUiStatusNavFlagsUseCase.kt | 53 +++++++++ .../viewmodel/TaskContainerViewModel.kt | 31 +++++ .../android/quickstep/views/TaskContainer.kt | 18 ++- .../usecase/SysUiStatusNavFlagsUseCaseTest.kt | 110 ++++++++++++++++++ 5 files changed, 211 insertions(+), 4 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt create mode 100644 quickstep/src/com/android/quickstep/recents/viewmodel/TaskContainerViewModel.kt create mode 100644 quickstep/tests/multivalentTests/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCaseTest.kt diff --git a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt index 7a5a71481c..3a6d5c0e32 100644 --- a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt +++ b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt @@ -24,6 +24,7 @@ import com.android.quickstep.recents.data.RecentTasksRepository import com.android.quickstep.recents.data.TasksRepository import com.android.quickstep.recents.usecase.GetThumbnailPositionUseCase import com.android.quickstep.recents.usecase.GetThumbnailUseCase +import com.android.quickstep.recents.usecase.SysUiStatusNavFlagsUseCase import com.android.quickstep.recents.viewmodel.RecentsViewData import com.android.quickstep.task.viewmodel.TaskContainerData import com.android.quickstep.task.viewmodel.TaskOverlayViewModel @@ -162,6 +163,8 @@ class RecentsDependencies private constructor(private val appContext: Context) { ) } GetThumbnailUseCase::class.java -> GetThumbnailUseCase(taskRepository = inject()) + SysUiStatusNavFlagsUseCase::class.java -> + SysUiStatusNavFlagsUseCase(taskRepository = inject()) GetThumbnailPositionUseCase::class.java -> GetThumbnailPositionUseCase( deviceProfileRepository = inject(), diff --git a/quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt b/quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt new file mode 100644 index 0000000000..1d19c7d332 --- /dev/null +++ b/quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt @@ -0,0 +1,53 @@ +/* + * 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.recents.usecase + +import android.view.WindowInsetsController +import com.android.launcher3.util.SystemUiController.FLAG_DARK_NAV +import com.android.launcher3.util.SystemUiController.FLAG_DARK_STATUS +import com.android.launcher3.util.SystemUiController.FLAG_LIGHT_NAV +import com.android.launcher3.util.SystemUiController.FLAG_LIGHT_STATUS +import com.android.quickstep.recents.data.RecentTasksRepository +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.runBlocking + +/** UseCase to calculate flags for status bar and navigation bar */ +class SysUiStatusNavFlagsUseCase(private val taskRepository: RecentTasksRepository) { + fun getSysUiStatusNavFlags(taskId: Int): Int { + val thumbnailData = + runBlocking { taskRepository.getThumbnailById(taskId).firstOrNull() } ?: return 0 + + val thumbnailAppearance = thumbnailData.appearance + var flags = 0 + flags = + flags or + if ( + thumbnailAppearance and WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS != 0 + ) + FLAG_LIGHT_STATUS + else FLAG_DARK_STATUS + flags = + flags or + if ( + thumbnailAppearance and + WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS != 0 + ) + FLAG_LIGHT_NAV + else FLAG_DARK_NAV + return flags + } +} diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/TaskContainerViewModel.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/TaskContainerViewModel.kt new file mode 100644 index 0000000000..8b8bc3eaa4 --- /dev/null +++ b/quickstep/src/com/android/quickstep/recents/viewmodel/TaskContainerViewModel.kt @@ -0,0 +1,31 @@ +/* + * 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.recents.viewmodel + +import android.graphics.Bitmap +import com.android.quickstep.recents.usecase.GetThumbnailUseCase +import com.android.quickstep.recents.usecase.SysUiStatusNavFlagsUseCase + +class TaskContainerViewModel( + private val sysUiStatusNavFlagsUseCase: SysUiStatusNavFlagsUseCase, + private val getThumbnailUseCase: GetThumbnailUseCase +) { + fun getThumbnail(taskId: Int): Bitmap? = getThumbnailUseCase.run(taskId) + + fun getSysUiStatusNavFlags(taskId: Int) = + sysUiStatusNavFlagsUseCase.getSysUiStatusNavFlags(taskId) +} diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt index 79725c6d67..e7a87207e0 100644 --- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt +++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt @@ -33,7 +33,7 @@ import com.android.quickstep.recents.di.RecentsDependencies import com.android.quickstep.recents.di.get import com.android.quickstep.recents.di.getScope import com.android.quickstep.recents.di.inject -import com.android.quickstep.recents.usecase.GetThumbnailUseCase +import com.android.quickstep.recents.viewmodel.TaskContainerViewModel import com.android.quickstep.task.thumbnail.TaskThumbnail import com.android.quickstep.task.thumbnail.TaskThumbnailView import com.android.quickstep.task.viewmodel.TaskContainerData @@ -61,10 +61,18 @@ class TaskContainer( ) { val overlay: TaskOverlayFactory.TaskOverlay<*> = taskOverlayFactory.createOverlay(this) lateinit var taskContainerData: TaskContainerData - private val getThumbnailUseCase: GetThumbnailUseCase by RecentsDependencies.inject() + private val taskThumbnailViewModel: TaskThumbnailViewModel by RecentsDependencies.inject(snapshotView) + // TODO(b/335649589): Ideally create and obtain this from DI. + private val taskContainerViewModel: TaskContainerViewModel by lazy { + TaskContainerViewModel( + sysUiStatusNavFlagsUseCase = RecentsDependencies.get(), + getThumbnailUseCase = RecentsDependencies.get() + ) + } + init { if (enableRefactorTaskThumbnail()) { require(snapshotView is TaskThumbnailView) @@ -84,7 +92,7 @@ class TaskContainer( val splitAnimationThumbnail: Bitmap? get() = if (enableRefactorTaskThumbnail()) { - getThumbnailUseCase.run(task.key.id) + taskContainerViewModel.getThumbnail(task.key.id) } else { thumbnailViewDeprecated.thumbnail } @@ -110,7 +118,9 @@ class TaskContainer( // TODO(b/350743460) Support sysUiStatusNavFlags for new TTV. val sysUiStatusNavFlags: Int get() = - if (enableRefactorTaskThumbnail()) 0 else thumbnailViewDeprecated.sysUiStatusNavFlags + if (enableRefactorTaskThumbnail()) + taskContainerViewModel.getSysUiStatusNavFlags(task.key.id) + else thumbnailViewDeprecated.sysUiStatusNavFlags /** Builds proto for logging */ val itemInfo: WorkspaceItemInfo diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCaseTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCaseTest.kt new file mode 100644 index 0000000000..ba4e20692f --- /dev/null +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCaseTest.kt @@ -0,0 +1,110 @@ +/* + * 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.recents.usecase + +import android.content.ComponentName +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.Color +import com.android.quickstep.recents.data.FakeTasksRepository +import com.android.systemui.shared.recents.model.Task +import com.android.systemui.shared.recents.model.ThumbnailData +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + +/** Test for [SysUiStatusNavFlagsUseCase] */ +class SysUiStatusNavFlagsUseCaseTest { + private lateinit var tasksRepository: FakeTasksRepository + private lateinit var sysUiStatusNavFlagsUseCase: SysUiStatusNavFlagsUseCase + + @Before + fun setup() { + tasksRepository = FakeTasksRepository() + sysUiStatusNavFlagsUseCase = SysUiStatusNavFlagsUseCase(tasksRepository) + initTaskRepository() + } + + @Test + fun onLightAppearanceReturnExpectedFlags() { + assertThat(sysUiStatusNavFlagsUseCase.getSysUiStatusNavFlags(FIRST_TASK_ID)) + .isEqualTo(FLAGS_APPEARANCE_LIGHT_THEME) + } + + @Test + fun onDarkAppearanceReturnExpectedFlags() { + assertThat(sysUiStatusNavFlagsUseCase.getSysUiStatusNavFlags(SECOND_TASK_ID)) + .isEqualTo(FLAGS_APPEARANCE_DARK_THEME) + } + + @Test + fun whenThumbnailIsNullReturnDefault() { + assertThat(sysUiStatusNavFlagsUseCase.getSysUiStatusNavFlags(UNKNOWN_TASK_ID)) + .isEqualTo(FLAGS_DEFAULT) + } + + private fun initTaskRepository() { + val firstTask = + Task(Task.TaskKey(FIRST_TASK_ID, 0, Intent(), ComponentName("", ""), 0, 2000)).apply { + colorBackground = Color.BLACK + } + val firstThumbnailData = + ThumbnailData( + thumbnail = + mock().apply { + whenever(width).thenReturn(THUMBNAIL_WIDTH) + whenever(height).thenReturn(THUMBNAIL_HEIGHT) + }, + appearance = APPEARANCE_LIGHT_THEME + ) + + val secondTask = + Task(Task.TaskKey(SECOND_TASK_ID, 0, Intent(), ComponentName("", ""), 0, 2005)).apply { + colorBackground = Color.BLACK + } + val secondThumbnailData = + ThumbnailData( + thumbnail = + mock().apply { + whenever(width).thenReturn(THUMBNAIL_WIDTH) + whenever(height).thenReturn(THUMBNAIL_HEIGHT) + }, + appearance = APPEARANCE_DARK_THEME + ) + + tasksRepository.seedTasks(listOf(firstTask, secondTask)) + tasksRepository.seedThumbnailData( + mapOf(FIRST_TASK_ID to firstThumbnailData, SECOND_TASK_ID to secondThumbnailData) + ) + tasksRepository.setVisibleTasks(listOf(FIRST_TASK_ID, SECOND_TASK_ID)) + } + + companion object { + const val FIRST_TASK_ID = 0 + const val SECOND_TASK_ID = 100 + const val UNKNOWN_TASK_ID = 404 + const val THUMBNAIL_WIDTH = 100 + const val THUMBNAIL_HEIGHT = 200 + const val APPEARANCE_LIGHT_THEME = 24 + const val FLAGS_APPEARANCE_LIGHT_THEME = 5 + const val APPEARANCE_DARK_THEME = 0 + const val FLAGS_APPEARANCE_DARK_THEME = 10 + const val FLAGS_DEFAULT = 0 + } +}