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