1 /* 2 * 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.views 18 19 import android.graphics.Bitmap 20 import android.view.View 21 import com.android.launcher3.Flags.enableRefactorTaskThumbnail 22 import com.android.launcher3.model.data.TaskViewItemInfo 23 import com.android.launcher3.util.SplitConfigurationOptions 24 import com.android.launcher3.util.TransformingTouchDelegate 25 import com.android.quickstep.TaskOverlayFactory 26 import com.android.quickstep.ViewUtils.addAccessibleChildToList 27 import com.android.quickstep.recents.di.RecentsDependencies 28 import com.android.quickstep.recents.di.get 29 import com.android.quickstep.recents.di.getScope 30 import com.android.quickstep.recents.di.inject 31 import com.android.quickstep.recents.viewmodel.TaskContainerViewModel 32 import com.android.quickstep.task.thumbnail.TaskThumbnailView 33 import com.android.quickstep.task.viewmodel.TaskContainerData 34 import com.android.quickstep.task.viewmodel.TaskThumbnailViewModel 35 import com.android.systemui.shared.recents.model.Task 36 37 /** Holder for all Task dependent information. */ 38 class TaskContainer( 39 val taskView: TaskView, 40 val task: Task, 41 val snapshotView: View, 42 val iconView: TaskViewIcon, 43 /** 44 * This technically can be a vanilla [android.view.TouchDelegate] class, however that class 45 * requires setting the touch bounds at construction, so we'd repeatedly be created many 46 * instances unnecessarily as scrolling occurs, whereas [TransformingTouchDelegate] allows touch 47 * delegated bounds only to be updated. 48 */ 49 val iconTouchDelegate: TransformingTouchDelegate, 50 /** Defaults to STAGE_POSITION_UNDEFINED if in not a split screen task view */ 51 @SplitConfigurationOptions.StagePosition val stagePosition: Int, 52 val digitalWellBeingToast: DigitalWellBeingToast?, 53 val showWindowsView: View?, 54 taskOverlayFactory: TaskOverlayFactory, 55 ) { 56 val overlay: TaskOverlayFactory.TaskOverlay<*> = taskOverlayFactory.createOverlay(this) 57 lateinit var taskContainerData: TaskContainerData 58 59 private val taskThumbnailViewModel: TaskThumbnailViewModel by 60 RecentsDependencies.inject(snapshotView) 61 62 // TODO(b/335649589): Ideally create and obtain this from DI. <lambda>null63 private val taskContainerViewModel: TaskContainerViewModel by lazy { 64 TaskContainerViewModel( 65 sysUiStatusNavFlagsUseCase = RecentsDependencies.get(), 66 getThumbnailUseCase = RecentsDependencies.get(), 67 splashAlphaUseCase = RecentsDependencies.get(), 68 ) 69 } 70 71 init { 72 if (enableRefactorTaskThumbnail()) { 73 require(snapshotView is TaskThumbnailView) 74 taskContainerData = RecentsDependencies.get(this) <lambda>null75 RecentsDependencies.getScope(snapshotView).apply { 76 val taskViewScope = RecentsDependencies.getScope(taskView) 77 linkTo(taskViewScope) 78 79 val taskContainerScope = RecentsDependencies.getScope(this@TaskContainer) 80 linkTo(taskContainerScope) 81 } 82 } else { 83 require(snapshotView is TaskThumbnailViewDeprecated) 84 } 85 } 86 87 val splitAnimationThumbnail: Bitmap? 88 get() = 89 if (enableRefactorTaskThumbnail()) { 90 taskContainerViewModel.getThumbnail(task.key.id) 91 } else { 92 thumbnailViewDeprecated.thumbnail 93 } 94 95 val thumbnailView: TaskThumbnailView 96 get() { 97 require(enableRefactorTaskThumbnail()) 98 return snapshotView as TaskThumbnailView 99 } 100 101 val thumbnailViewDeprecated: TaskThumbnailViewDeprecated 102 get() { 103 require(!enableRefactorTaskThumbnail()) 104 return snapshotView as TaskThumbnailViewDeprecated 105 } 106 107 val shouldShowSplashView: Boolean 108 get() = 109 if (enableRefactorTaskThumbnail()) 110 taskContainerViewModel.shouldShowThumbnailSplash(task.key.id) 111 else thumbnailViewDeprecated.shouldShowSplashView() 112 113 val sysUiStatusNavFlags: Int 114 get() = 115 if (enableRefactorTaskThumbnail()) 116 taskContainerViewModel.getSysUiStatusNavFlags(task.key.id) 117 else thumbnailViewDeprecated.sysUiStatusNavFlags 118 119 /** Builds proto for logging */ 120 val itemInfo: TaskViewItemInfo 121 get() = TaskViewItemInfo(this) 122 bindnull123 fun bind() { 124 digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition) 125 if (enableRefactorTaskThumbnail()) { 126 bindThumbnailView() 127 } else { 128 thumbnailViewDeprecated.bind(task, overlay, taskView) 129 } 130 overlay.init() 131 } 132 destroynull133 fun destroy() { 134 digitalWellBeingToast?.destroy() 135 snapshotView.scaleX = 1f 136 snapshotView.scaleY = 1f 137 overlay.destroy() 138 if (enableRefactorTaskThumbnail()) { 139 RecentsDependencies.getInstance().removeScope(snapshotView) 140 RecentsDependencies.getInstance().removeScope(this) 141 } 142 } 143 bindThumbnailViewnull144 fun bindThumbnailView() { 145 taskThumbnailViewModel.bind(task.key.id) 146 } 147 setOverlayEnablednull148 fun setOverlayEnabled(enabled: Boolean) { 149 if (!enableRefactorTaskThumbnail()) { 150 thumbnailViewDeprecated.setOverlayEnabled(enabled) 151 } 152 } 153 addChildForAccessibilitynull154 fun addChildForAccessibility(outChildren: ArrayList<View>) { 155 addAccessibleChildToList(iconView.asView(), outChildren) 156 addAccessibleChildToList(snapshotView, outChildren) 157 showWindowsView?.let { addAccessibleChildToList(it, outChildren) } 158 digitalWellBeingToast?.let { addAccessibleChildToList(it, outChildren) } 159 overlay.addChildForAccessibility(outChildren) 160 } 161 } 162