• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.systemui.dreams.homecontrols.service
18 
19 import android.app.Activity
20 import android.app.WindowConfiguration
21 import android.content.Intent
22 import android.graphics.Rect
23 import android.os.Binder
24 import android.window.TaskFragmentCreationParams
25 import android.window.TaskFragmentInfo
26 import android.window.TaskFragmentOperation
27 import android.window.TaskFragmentOrganizer
28 import android.window.TaskFragmentTransaction
29 import android.window.WindowContainerTransaction
30 import com.android.systemui.dagger.qualifiers.Main
31 import com.android.systemui.util.concurrency.DelayableExecutor
32 import dagger.assisted.Assisted
33 import dagger.assisted.AssistedFactory
34 import dagger.assisted.AssistedInject
35 import java.lang.ref.WeakReference
36 import java.util.concurrent.Executor
37 
38 typealias FragmentInfoCallback = (TaskFragmentInfo) -> Unit
39 
40 /** Wrapper around TaskFragmentOrganizer for managing a task fragment within an activity */
41 class TaskFragmentComponent
42 @AssistedInject
43 constructor(
44     @Assisted private val activity: Activity,
45     @Assisted("onCreateCallback") private val onCreateCallback: FragmentInfoCallback,
46     @Assisted("onInfoChangedCallback") private val onInfoChangedCallback: FragmentInfoCallback,
47     @Assisted private val hide: () -> Unit,
48     @Main private val executor: DelayableExecutor,
49 ) {
50 
51     @AssistedFactory
52     fun interface Factory {
53         fun create(
54             activity: Activity,
55             @Assisted("onCreateCallback") onCreateCallback: FragmentInfoCallback,
56             @Assisted("onInfoChangedCallback") onInfoChangedCallback: FragmentInfoCallback,
57             hide: () -> Unit,
58         ): TaskFragmentComponent
59     }
60 
61     private val fragmentToken = Binder()
62 
63     class Organizer(val component: WeakReference<TaskFragmentComponent>, executor: Executor) :
64         TaskFragmentOrganizer(executor) {
65         override fun onTransactionReady(transaction: TaskFragmentTransaction) {
66             component.get()?.handleTransactionReady(transaction)
67         }
68     }
69 
70     private val organizer: TaskFragmentOrganizer =
71         Organizer(WeakReference(this), executor).apply {
72             registerOrganizer(true /* isSystemOrganizer */)
73         }
74 
75     private fun handleTransactionReady(transaction: TaskFragmentTransaction) {
76         val resultT = WindowContainerTransaction()
77 
78         for (change in transaction.changes) {
79             change.taskFragmentInfo?.let { taskFragmentInfo ->
80                 if (taskFragmentInfo.fragmentToken == fragmentToken) {
81                     when (change.type) {
82                         TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED -> {
83                             resultT.addTaskFragmentOperation(
84                                 fragmentToken,
85                                 TaskFragmentOperation.Builder(
86                                         TaskFragmentOperation
87                                             .OP_TYPE_PRIVILEGED_REORDER_TO_TOP_OF_TASK
88                                     )
89                                     .build(),
90                             )
91 
92                             onCreateCallback(taskFragmentInfo)
93                         }
94                         TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED -> {
95                             onInfoChangedCallback(taskFragmentInfo)
96                         }
97                         TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED -> {
98                             hide()
99                         }
100                         TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED -> {}
101                         TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR -> {
102                             hide()
103                         }
104                         TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK -> {}
105                         else ->
106                             throw IllegalArgumentException(
107                                 "Unknown TaskFragmentEvent=" + change.type
108                             )
109                     }
110                 }
111             }
112         }
113         organizer.onTransactionHandled(
114             transaction.transactionToken,
115             resultT,
116             TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE,
117             false,
118         )
119     }
120 
121     /** Creates the task fragment */
122     fun createTaskFragment() {
123         val fragmentOptions =
124             TaskFragmentCreationParams.Builder(
125                     organizer.organizerToken,
126                     fragmentToken,
127                     activity.activityToken!!,
128                 )
129                 .setInitialRelativeBounds(Rect())
130                 .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
131                 .build()
132         organizer.applyTransaction(
133             WindowContainerTransaction().createTaskFragment(fragmentOptions),
134             TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE,
135             false,
136         )
137     }
138 
139     private fun WindowContainerTransaction.startActivity(intent: Intent) =
140         this.startActivityInTaskFragment(fragmentToken, activity.activityToken!!, intent, null)
141 
142     /** Starts the provided activity in the fragment and move it to the background */
143     fun startActivityInTaskFragment(intent: Intent) {
144         organizer.applyTransaction(
145             WindowContainerTransaction().startActivity(intent),
146             TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_OPEN,
147             false,
148         )
149     }
150 
151     /** Destroys the task fragment */
152     fun destroy() {
153         organizer.applyTransaction(
154             WindowContainerTransaction()
155                 .addTaskFragmentOperation(
156                     fragmentToken,
157                     TaskFragmentOperation.Builder(
158                             TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT
159                         )
160                         .build(),
161                 ),
162             TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CLOSE,
163             false,
164         )
165         organizer.unregisterOrganizer()
166     }
167 }
168