• 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 android.tools.common.traces.wm
18 
19 import android.tools.common.datatypes.Rect
20 import android.tools.common.traces.component.IComponentMatcher
21 import kotlin.js.JsExport
22 
23 /**
24  * Represents a task in the window manager hierarchy
25  *
26  * This is a generic object that is reused by both Flicker and Winscope and cannot access internal
27  * Java/Android functionality
28  */
29 @JsExport
30 class Task(
31     override val activityType: Int,
32     override val isFullscreen: Boolean,
33     override val bounds: Rect,
34     val taskId: Int,
35     val rootTaskId: Int,
36     val displayId: Int,
37     val lastNonFullscreenBounds: Rect,
38     val realActivity: String,
39     val origActivity: String,
40     val resizeMode: Int,
41     private val _resumedActivity: String,
42     var animatingBounds: Boolean,
43     val surfaceWidth: Int,
44     val surfaceHeight: Int,
45     val createdByOrganizer: Boolean,
46     val minWidth: Int,
47     val minHeight: Int,
48     private val windowContainer: IWindowContainer
49 ) : IWindowContainer by windowContainer {
50     override val isVisible: Boolean = false
51     override val name: String = taskId.toString()
52     override val isEmpty: Boolean
53         get() = tasks.isEmpty() && activities.isEmpty()
54     override val stableId: String
55         get() = "${this::class.simpleName} $token $title $taskId"
56 
57     val isRootTask: Boolean
58         get() = taskId == rootTaskId
59     val tasks: Array<Task>
60         get() = this.children.reversed().filterIsInstance<Task>().toTypedArray()
61     val taskFragments: Array<TaskFragment>
62         get() = this.children.reversed().filterIsInstance<TaskFragment>().toTypedArray()
63     val activities: Array<Activity>
64         get() = this.children.reversed().filterIsInstance<Activity>().toTypedArray()
65     /** The top task in the stack. */
66     // NOTE: Unlike the WindowManager internals, we dump the state from top to bottom,
67     //       so the indices are inverted
68     val topTask: Task?
69         get() = tasks.firstOrNull()
70     val resumedActivities: Array<String>
71         get() {
72             val result = mutableSetOf<String>()
73             if (this._resumedActivity.isNotEmpty()) {
74                 result.add(this._resumedActivity)
75             }
76             val activitiesInChildren =
77                 this.tasks.flatMap { it.resumedActivities.toList() }.filter { it.isNotEmpty() }
78             result.addAll(activitiesInChildren)
79             return result.toTypedArray()
80         }
81 
82     /** @return The first [Task] matching [predicate], or null otherwise */
83     fun getTask(predicate: (Task) -> Boolean) =
84         tasks.firstOrNull { predicate(it) } ?: if (predicate(this)) this else null
85 
86     /** @return the first [Activity] matching [predicate], or null otherwise */
87     internal fun getActivity(predicate: (Activity) -> Boolean): Activity? {
88         var activity: Activity? = activities.firstOrNull { predicate(it) }
89         if (activity != null) {
90             return activity
91         }
92         for (task in tasks) {
93             activity = task.getActivity(predicate)
94             if (activity != null) {
95                 return activity
96             }
97         }
98         for (taskFragment in taskFragments) {
99             activity = taskFragment.getActivity(predicate)
100             if (activity != null) {
101                 return activity
102             }
103         }
104         return null
105     }
106 
107     /**
108      * @param componentMatcher Components to search
109      * @return the first [Activity] matching [componentMatcher], or null otherwise
110      */
111     fun getActivity(componentMatcher: IComponentMatcher): Activity? = getActivity { activity ->
112         componentMatcher.activityMatchesAnyOf(activity)
113     }
114 
115     /**
116      * @param componentMatcher Components to search
117      * @return if any activity matches [componentMatcher]
118      */
119     fun containsActivity(componentMatcher: IComponentMatcher) =
120         getActivity(componentMatcher) != null
121 
122     override fun toString(): String {
123         return "${this::class.simpleName}: {$token $title} id=$taskId bounds=$bounds"
124     }
125 
126     override fun equals(other: Any?): Boolean {
127         if (this === other) return true
128         if (other !is Task) return false
129 
130         if (activityType != other.activityType) return false
131         if (isFullscreen != other.isFullscreen) return false
132         if (bounds != other.bounds) return false
133         if (taskId != other.taskId) return false
134         if (rootTaskId != other.rootTaskId) return false
135         if (displayId != other.displayId) return false
136         if (realActivity != other.realActivity) return false
137         if (resizeMode != other.resizeMode) return false
138         if (minWidth != other.minWidth) return false
139         if (minHeight != other.minHeight) return false
140         if (name != other.name) return false
141         if (orientation != other.orientation) return false
142         if (title != other.title) return false
143         if (token != other.token) return false
144         if (windowContainer != other.windowContainer) return false
145 
146         return true
147     }
148 
149     override fun hashCode(): Int {
150         var result = super.hashCode()
151         result = 31 * result + activityType
152         result = 31 * result + isFullscreen.hashCode()
153         result = 31 * result + bounds.hashCode()
154         result = 31 * result + taskId
155         result = 31 * result + rootTaskId
156         result = 31 * result + displayId
157         result = 31 * result + lastNonFullscreenBounds.hashCode()
158         result = 31 * result + realActivity.hashCode()
159         result = 31 * result + origActivity.hashCode()
160         result = 31 * result + resizeMode
161         result = 31 * result + _resumedActivity.hashCode()
162         result = 31 * result + animatingBounds.hashCode()
163         result = 31 * result + surfaceWidth
164         result = 31 * result + surfaceHeight
165         result = 31 * result + createdByOrganizer.hashCode()
166         result = 31 * result + minWidth
167         result = 31 * result + minHeight
168         result = 31 * result + isVisible.hashCode()
169         result = 31 * result + name.hashCode()
170         result = 31 * result + windowContainer.hashCode()
171         return result
172     }
173 }
174