Loading quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt +3 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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(), Loading quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt 0 → 100644 +53 −0 Original line number 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.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 } } quickstep/src/com/android/quickstep/recents/viewmodel/TaskContainerViewModel.kt 0 → 100644 +31 −0 Original line number 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.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) } quickstep/src/com/android/quickstep/views/TaskContainer.kt +14 −4 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) Loading @@ -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 } Loading @@ -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 Loading quickstep/tests/multivalentTests/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCaseTest.kt 0 → 100644 +110 −0 Original line number 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.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<Bitmap>().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<Bitmap>().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 } } Loading
quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt +3 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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(), Loading
quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt 0 → 100644 +53 −0 Original line number 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.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 } }
quickstep/src/com/android/quickstep/recents/viewmodel/TaskContainerViewModel.kt 0 → 100644 +31 −0 Original line number 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.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) }
quickstep/src/com/android/quickstep/views/TaskContainer.kt +14 −4 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) Loading @@ -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 } Loading @@ -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 Loading
quickstep/tests/multivalentTests/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCaseTest.kt 0 → 100644 +110 −0 Original line number 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.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<Bitmap>().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<Bitmap>().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 } }