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.wm.shell.recents 18 19 import android.app.ActivityManager.RunningTaskInfo 20 import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM 21 import android.os.IBinder 22 import android.util.ArrayMap 23 import android.view.SurfaceControl 24 import android.view.WindowManager 25 import android.window.TransitionInfo 26 import com.android.window.flags.Flags.enableTaskStackObserverInShell 27 import com.android.wm.shell.shared.TransitionUtil 28 import com.android.wm.shell.sysui.ShellInit 29 import com.android.wm.shell.transition.Transitions 30 import dagger.Lazy 31 import java.util.concurrent.Executor 32 33 /** 34 * A [Transitions.TransitionObserver] that observes shell transitions and sends updates to listeners 35 * about task stack changes. 36 * 37 * TODO(346588978) Move split/pip signals here as well so that launcher don't need to handle it 38 */ 39 class TaskStackTransitionObserver( 40 private val transitions: Lazy<Transitions>, 41 shellInit: ShellInit 42 ) : Transitions.TransitionObserver { 43 44 private val transitionToTransitionChanges: MutableMap<IBinder, TransitionChanges> = 45 mutableMapOf() 46 private val taskStackTransitionObserverListeners = 47 ArrayMap<TaskStackTransitionObserverListener, Executor>() 48 49 init { 50 if (Transitions.ENABLE_SHELL_TRANSITIONS) { 51 shellInit.addInitCallback(::onInit, this) 52 } 53 } 54 55 fun onInit() { 56 transitions.get().registerObserver(this) 57 } 58 59 override fun onTransitionReady( 60 transition: IBinder, 61 info: TransitionInfo, 62 startTransaction: SurfaceControl.Transaction, 63 finishTransaction: SurfaceControl.Transaction 64 ) { 65 if (enableTaskStackObserverInShell()) { 66 val taskInfoList = mutableListOf<RunningTaskInfo>() 67 val transitionTypeList = mutableListOf<Int>() 68 69 for (change in info.changes) { 70 if (change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0) { 71 continue 72 } 73 74 val taskInfo = change.taskInfo 75 if (taskInfo == null || taskInfo.taskId == -1) { 76 continue 77 } 78 79 if (change.mode == WindowManager.TRANSIT_OPEN) { 80 change.taskInfo?.let { taskInfoList.add(it) } 81 transitionTypeList.add(change.mode) 82 } 83 } 84 transitionToTransitionChanges.put( 85 transition, 86 TransitionChanges(taskInfoList, transitionTypeList) 87 ) 88 } 89 } 90 91 override fun onTransitionStarting(transition: IBinder) {} 92 93 override fun onTransitionMerged(merged: IBinder, playing: IBinder) {} 94 95 override fun onTransitionFinished(transition: IBinder, aborted: Boolean) { 96 val taskInfoList = 97 transitionToTransitionChanges.getOrDefault(transition, TransitionChanges()).taskInfoList 98 val typeList = 99 transitionToTransitionChanges 100 .getOrDefault(transition, TransitionChanges()) 101 .transitionTypeList 102 transitionToTransitionChanges.remove(transition) 103 104 for ((index, taskInfo) in taskInfoList.withIndex()) { 105 if ( 106 TransitionUtil.isOpeningType(typeList[index]) && 107 taskInfo.windowingMode == WINDOWING_MODE_FREEFORM 108 ) { 109 notifyTaskStackTransitionObserverListeners(taskInfo) 110 } 111 } 112 } 113 114 fun addTaskStackTransitionObserverListener( 115 taskStackTransitionObserverListener: TaskStackTransitionObserverListener, 116 executor: Executor 117 ) { 118 taskStackTransitionObserverListeners[taskStackTransitionObserverListener] = executor 119 } 120 121 fun removeTaskStackTransitionObserverListener( 122 taskStackTransitionObserverListener: TaskStackTransitionObserverListener 123 ) { 124 taskStackTransitionObserverListeners.remove(taskStackTransitionObserverListener) 125 } 126 127 private fun notifyTaskStackTransitionObserverListeners(taskInfo: RunningTaskInfo) { 128 taskStackTransitionObserverListeners.forEach { (listener, executor) -> 129 executor.execute { listener.onTaskMovedToFrontThroughTransition(taskInfo) } 130 } 131 } 132 133 /** Listener to use to get updates regarding task stack from this observer */ 134 interface TaskStackTransitionObserverListener { 135 /** Called when a task is moved to front. */ 136 fun onTaskMovedToFrontThroughTransition(taskInfo: RunningTaskInfo) {} 137 } 138 139 private data class TransitionChanges( 140 val taskInfoList: MutableList<RunningTaskInfo> = ArrayList(), 141 val transitionTypeList: MutableList<Int> = ArrayList() 142 ) 143 } 144