• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2023 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.quickstep.util
18 
19 import android.util.Log
20 import android.view.WindowManager.TRANSIT_OPEN
21 import android.view.WindowManager.TRANSIT_TO_FRONT
22 import android.window.TransitionInfo
23 import android.window.TransitionInfo.Change
24 import android.window.TransitionInfo.FLAG_FIRST_CUSTOM
25 import com.android.launcher3.util.SplitConfigurationOptions
26 import com.android.wm.shell.shared.split.SplitBounds
27 import java.lang.IllegalStateException
28 
29 class SplitScreenUtils {
30     companion object {
31         private const val TAG = "SplitScreenUtils"
32 
33         // TODO(b/254378592): Remove these methods when the two classes are reunited
34         /** Converts the shell version of SplitBounds to the launcher version */
35         @JvmStatic
36         fun convertShellSplitBoundsToLauncher(shellSplitBounds: SplitBounds) =
37             SplitConfigurationOptions.SplitBounds(
38                 shellSplitBounds.leftTopBounds,
39                 shellSplitBounds.rightBottomBounds,
40                 shellSplitBounds.leftTopTaskId,
41                 shellSplitBounds.rightBottomTaskId,
42                 shellSplitBounds.snapPosition,
43             )
44 
45         /**
46          * Given a TransitionInfo, generates the tree structure for those changes and extracts out
47          * the top most root and it's two immediate children. Changes can be provided in any order.
48          *
49          * @return a [Pair] where first -> top most split root, second -> [List] of 2,
50          *   leftTop/bottomRight stage roots
51          */
52         fun extractTopParentAndChildren(
53             transitionInfo: TransitionInfo
54         ): Pair<Change, List<Change>>? {
55             val parentToChildren = mutableMapOf<Change, MutableList<Change>>()
56             val hasParent = mutableSetOf<Change>()
57             // filter out anything that isn't opening and the divider
58             val taskChanges: List<Change> =
59                 transitionInfo.changes
60                     .filter { change ->
61                         (change.mode == TRANSIT_OPEN || change.mode == TRANSIT_TO_FRONT) &&
62                             change.flags < FLAG_FIRST_CUSTOM
63                     }
64                     .toList()
65 
66             // 1. Build Parent-Child Relationships
67             for (change in taskChanges) {
68                 // TODO (b/316490565): Replace this logic when SplitBounds is available to
69                 //  startAnimation() and we can know the precise taskIds of launching tasks.
70                 change.parent?.let { parent ->
71                     parentToChildren
72                         .getOrPut(transitionInfo.getChange(parent)!!) { mutableListOf() }
73                         .add(change)
74                     hasParent.add(change)
75                 }
76             }
77 
78             // 2. Find Top Parent
79             val topParent = taskChanges.firstOrNull { it !in hasParent }
80 
81             // 3. Extract Immediate Children
82             return if (topParent != null) {
83                 val immediateChildren = parentToChildren.getOrDefault(topParent, emptyList())
84                 if (immediateChildren.size != 2) {
85                     throw IllegalStateException("incorrect split stage root size")
86                 }
87                 Pair(topParent, immediateChildren)
88             } else {
89                 Log.w(TAG, "No top parent found")
90                 null
91             }
92         }
93     }
94 }
95