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