1 /* <lambda>null2 * Copyright (C) 2022 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.systemui.mediaprojection.appselector.view 18 19 import android.app.ActivityOptions 20 import android.app.IActivityTaskManager 21 import android.graphics.Rect 22 import android.os.Binder 23 import android.view.LayoutInflater 24 import android.view.View 25 import android.view.ViewGroup 26 import androidx.recyclerview.widget.LinearLayoutManager 27 import androidx.recyclerview.widget.RecyclerView 28 import com.android.systemui.R 29 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorResultHandler 30 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorScope 31 import com.android.systemui.mediaprojection.appselector.data.RecentTask 32 import com.android.systemui.mediaprojection.appselector.view.RecentTasksAdapter.RecentTaskClickListener 33 import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener 34 import com.android.systemui.util.recycler.HorizontalSpacerItemDecoration 35 import javax.inject.Inject 36 37 /** 38 * Controller that handles view of the recent apps selector in the media projection activity. 39 * It is responsible for creating and updating recent apps view. 40 */ 41 @MediaProjectionAppSelectorScope 42 class MediaProjectionRecentsViewController 43 @Inject 44 constructor( 45 private val recentTasksAdapterFactory: RecentTasksAdapter.Factory, 46 private val taskViewSizeProvider: TaskPreviewSizeProvider, 47 private val activityTaskManager: IActivityTaskManager, 48 private val resultHandler: MediaProjectionAppSelectorResultHandler, 49 ) : RecentTaskClickListener, TaskPreviewSizeListener { 50 51 private var views: Views? = null 52 private var lastBoundData: List<RecentTask>? = null 53 54 init { 55 taskViewSizeProvider.addCallback(this) 56 } 57 58 fun createView(parent: ViewGroup): ViewGroup = 59 views?.root ?: createRecentViews(parent).also { 60 views = it 61 lastBoundData?.let { recents -> bind(recents) } 62 }.root 63 64 fun bind(recentTasks: List<RecentTask>) { 65 views?.apply { 66 if (recentTasks.isEmpty()) { 67 root.visibility = View.GONE 68 return 69 } 70 71 progress.visibility = View.GONE 72 recycler.visibility = View.VISIBLE 73 root.visibility = View.VISIBLE 74 75 recycler.adapter = 76 recentTasksAdapterFactory.create( 77 recentTasks, 78 this@MediaProjectionRecentsViewController 79 ) 80 } 81 82 lastBoundData = recentTasks 83 } 84 85 private fun createRecentViews(parent: ViewGroup): Views { 86 val recentsRoot = 87 LayoutInflater.from(parent.context) 88 .inflate(R.layout.media_projection_recent_tasks, parent, /* attachToRoot= */ false) 89 as ViewGroup 90 91 val container = recentsRoot.findViewById<View>(R.id.media_projection_recent_tasks_container) 92 container.setTaskHeightSize() 93 94 val progress = recentsRoot.requireViewById<View>(R.id.media_projection_recent_tasks_loader) 95 val recycler = 96 recentsRoot.requireViewById<RecyclerView>(R.id.media_projection_recent_tasks_recycler) 97 recycler.layoutManager = 98 LinearLayoutManager( 99 parent.context, 100 LinearLayoutManager.HORIZONTAL, 101 /* reverseLayout= */ false 102 ) 103 104 val itemDecoration = 105 HorizontalSpacerItemDecoration( 106 parent.resources.getDimensionPixelOffset( 107 R.dimen.media_projection_app_selector_recents_padding 108 ) 109 ) 110 recycler.addItemDecoration(itemDecoration) 111 112 return Views(recentsRoot, container, progress, recycler) 113 } 114 115 override fun onRecentAppClicked(task: RecentTask, view: View) { 116 val launchCookie = Binder() 117 val activityOptions = 118 ActivityOptions.makeScaleUpAnimation( 119 view, 120 /* startX= */ 0, 121 /* startY= */ 0, 122 view.width, 123 view.height 124 ) 125 activityOptions.launchCookie = launchCookie 126 127 activityTaskManager.startActivityFromRecents(task.taskId, activityOptions.toBundle()) 128 resultHandler.returnSelectedApp(launchCookie) 129 } 130 131 override fun onTaskSizeChanged(size: Rect) { 132 views?.recentsContainer?.setTaskHeightSize() 133 } 134 135 private fun View.setTaskHeightSize() { 136 val thumbnailHeight = taskViewSizeProvider.size.height() 137 val itemHeight = 138 thumbnailHeight + 139 context.resources.getDimensionPixelSize( 140 R.dimen.media_projection_app_selector_task_icon_size 141 ) + 142 context.resources.getDimensionPixelSize( 143 R.dimen.media_projection_app_selector_task_icon_margin 144 ) * 2 145 146 layoutParams = layoutParams.apply { height = itemHeight } 147 } 148 149 private class Views( 150 val root: ViewGroup, 151 val recentsContainer: View, 152 val progress: View, 153 val recycler: RecyclerView 154 ) 155 } 156