• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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