1 /* <lambda>null2 * Copyright (C) 2024 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.quickstep.task.thumbnail 18 19 import android.graphics.Bitmap 20 import android.view.Surface 21 import com.android.quickstep.recents.data.RecentTasksRepository 22 import com.android.quickstep.recents.data.RecentsRotationStateRepository 23 import com.android.quickstep.recents.viewmodel.RecentsViewData 24 import com.android.quickstep.task.viewmodel.TaskContainerData 25 import com.android.systemui.shared.recents.utilities.PreviewPositionHelper 26 import com.android.systemui.shared.recents.utilities.Utilities 27 import kotlinx.coroutines.flow.Flow 28 import kotlinx.coroutines.flow.combine 29 import kotlinx.coroutines.flow.distinctUntilChanged 30 31 class SplashAlphaUseCase( 32 private val recentsViewData: RecentsViewData, 33 private val taskContainerData: TaskContainerData, 34 private val taskThumbnailViewData: TaskThumbnailViewData, 35 private val tasksRepository: RecentTasksRepository, 36 private val rotationStateRepository: RecentsRotationStateRepository, 37 ) { 38 fun execute(taskId: Int): Flow<Float> = 39 combine( 40 taskThumbnailViewData.width, 41 taskThumbnailViewData.height, 42 tasksRepository.getThumbnailById(taskId), 43 taskContainerData.thumbnailSplashProgress, 44 recentsViewData.thumbnailSplashProgress 45 ) { width, height, thumbnailData, taskSplashProgress, globalSplashProgress -> 46 val thumbnail = thumbnailData?.thumbnail 47 when { 48 thumbnail == null -> 0f 49 taskSplashProgress > 0f -> taskSplashProgress 50 globalSplashProgress > 0f && 51 isInaccurateThumbnail(thumbnail, thumbnailData.rotation, width, height) -> 52 globalSplashProgress 53 else -> 0f 54 } 55 } 56 .distinctUntilChanged() 57 58 private fun isInaccurateThumbnail( 59 thumbnail: Bitmap, 60 thumbnailRotation: Int, 61 width: Int, 62 height: Int 63 ): Boolean { 64 return isThumbnailAspectRatioDifferentFromThumbnailData(thumbnail, width, height) || 65 isThumbnailRotationDifferentFromTask(thumbnailRotation) 66 } 67 68 private fun isThumbnailAspectRatioDifferentFromThumbnailData( 69 thumbnail: Bitmap, 70 viewWidth: Int, 71 viewHeight: Int 72 ): Boolean { 73 val viewAspect: Float = viewWidth / viewHeight.toFloat() 74 val thumbnailAspect: Float = thumbnail.width / thumbnail.height.toFloat() 75 return Utilities.isRelativePercentDifferenceGreaterThan( 76 viewAspect, 77 thumbnailAspect, 78 PreviewPositionHelper.MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT 79 ) 80 } 81 82 private fun isThumbnailRotationDifferentFromTask(thumbnailRotation: Int): Boolean { 83 val rotationState = rotationStateRepository.getRecentsRotationState() 84 return if (rotationState.orientationHandlerRotation == Surface.ROTATION_0) { 85 (rotationState.activityRotation - thumbnailRotation) % 2 != 0 86 } else { 87 rotationState.orientationHandlerRotation != thumbnailRotation 88 } 89 } 90 } 91