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.traces.parsers.wm
18 
19 import android.app.nano.WindowConfigurationProto
20 import android.content.nano.ConfigurationProto
21 import android.graphics.Insets
22 import android.graphics.Rect
23 import android.graphics.nano.RectProto
24 import android.tools.PlatformConsts
25 import android.tools.Rotation
26 import android.tools.datatypes.Size
27 import android.tools.traces.wm.Activity
28 import android.tools.traces.wm.Configuration
29 import android.tools.traces.wm.ConfigurationContainer
30 import android.tools.traces.wm.ConfigurationContainerImpl
31 import android.tools.traces.wm.DisplayArea
32 import android.tools.traces.wm.DisplayContent
33 import android.tools.traces.wm.DisplayCutout
34 import android.tools.traces.wm.KeyguardControllerState
35 import android.tools.traces.wm.RootWindowContainer
36 import android.tools.traces.wm.Task
37 import android.tools.traces.wm.TaskFragment
38 import android.tools.traces.wm.WindowConfiguration
39 import android.tools.traces.wm.WindowContainer
40 import android.tools.traces.wm.WindowContainerImpl
41 import android.tools.traces.wm.WindowLayoutParams
42 import android.tools.traces.wm.WindowManagerPolicy
43 import android.tools.traces.wm.WindowManagerState
44 import android.tools.traces.wm.WindowManagerTraceEntryBuilder
45 import android.tools.traces.wm.WindowState
46 import android.tools.traces.wm.WindowToken
47 import android.view.Surface
48 import android.view.nano.DisplayCutoutProto
49 import android.view.nano.ViewProtoEnums
50 import android.view.nano.WindowLayoutParamsProto
51 import com.android.server.wm.nano.ActivityRecordProto
52 import com.android.server.wm.nano.AppTransitionProto
53 import com.android.server.wm.nano.ConfigurationContainerProto
54 import com.android.server.wm.nano.DisplayAreaProto
55 import com.android.server.wm.nano.DisplayContentProto
56 import com.android.server.wm.nano.KeyguardControllerProto
57 import com.android.server.wm.nano.RootWindowContainerProto
58 import com.android.server.wm.nano.TaskFragmentProto
59 import com.android.server.wm.nano.TaskProto
60 import com.android.server.wm.nano.WindowContainerChildProto
61 import com.android.server.wm.nano.WindowContainerProto
62 import com.android.server.wm.nano.WindowManagerPolicyProto
63 import com.android.server.wm.nano.WindowManagerServiceDumpProto
64 import com.android.server.wm.nano.WindowStateProto
65 import com.android.server.wm.nano.WindowTokenProto
66 
67 /** Helper class to create a new WM state */
68 class WindowManagerStateBuilder {
69     private var computedZCounter = 0
70     private var realToElapsedTimeOffsetNanos = 0L
71     private var where = ""
72     private var timestamp = 0L
73     private var proto: WindowManagerServiceDumpProto? = null
74 
75     fun withRealTimeOffset(value: Long) = apply { realToElapsedTimeOffsetNanos = value }
76 
77     fun atPlace(_where: String) = apply { where = _where }
78 
79     fun forTimestamp(value: Long) = apply { timestamp = value }
80 
81     fun forProto(value: WindowManagerServiceDumpProto) = apply { proto = value }
82 
83     fun build(): WindowManagerState {
84         val proto = proto
85         requireNotNull(proto) { "Proto object not specified" }
86 
87         computedZCounter = 0
88         return WindowManagerTraceEntryBuilder()
89             .setElapsedTimestamp(timestamp)
90             .setPolicy(createWindowManagerPolicy(proto.policy))
91             .setFocusedApp(proto.focusedApp)
92             .setFocusedDisplayId(proto.focusedDisplayId)
93             .setFocusedWindow(proto.focusedWindow?.title ?: "")
94             .setInputMethodWindowAppToken(
95                 if (proto.inputMethodWindow != null) {
96                     Integer.toHexString(proto.inputMethodWindow.hashCode)
97                 } else {
98                     ""
99                 }
100             )
101             .setIsHomeRecentsComponent(proto.rootWindowContainer.isHomeRecentsComponent)
102             .setIsDisplayFrozen(proto.displayFrozen)
103             .setPendingActivities(proto.rootWindowContainer.pendingActivities.map { it.title })
104             .setRoot(createRootWindowContainer(proto.rootWindowContainer))
105             .setKeyguardControllerState(
106                 createKeyguardControllerState(proto.rootWindowContainer.keyguardController)
107             )
108             .setWhere(where)
109             .setRealToElapsedTimeOffsetNs(realToElapsedTimeOffsetNanos)
110             .build()
111     }
112 
113     private fun createWindowManagerPolicy(proto: WindowManagerPolicyProto): WindowManagerPolicy {
114         return WindowManagerPolicy.from(
115             focusedAppToken = proto.focusedAppToken ?: "",
116             forceStatusBar = proto.forceStatusBar,
117             forceStatusBarFromKeyguard = proto.forceStatusBarFromKeyguard,
118             keyguardDrawComplete = proto.keyguardDrawComplete,
119             keyguardOccluded = proto.keyguardOccluded,
120             keyguardOccludedChanged = proto.keyguardOccludedChanged,
121             keyguardOccludedPending = proto.keyguardOccludedPending,
122             lastSystemUiFlags = proto.lastSystemUiFlags,
123             orientation = proto.orientation,
124             rotation = Rotation.getByValue(proto.rotation),
125             rotationMode = proto.rotationMode,
126             screenOnFully = proto.screenOnFully,
127             windowManagerDrawComplete = proto.windowManagerDrawComplete
128         )
129     }
130 
131     private fun createRootWindowContainer(proto: RootWindowContainerProto): RootWindowContainer {
132         return RootWindowContainer(
133             createWindowContainer(
134                 proto.windowContainer,
135                 proto.windowContainer.children.mapNotNull { p ->
136                     createWindowContainerChild(p, isActivityInTree = false)
137                 }
138             )
139                 ?: error("Window container should not be null")
140         )
141     }
142 
143     private fun createKeyguardControllerState(
144         proto: KeyguardControllerProto?
145     ): KeyguardControllerState {
146         return KeyguardControllerState.from(
147             isAodShowing = proto?.aodShowing ?: false,
148             isKeyguardShowing = proto?.keyguardShowing ?: false,
149             keyguardOccludedStates =
150                 proto?.keyguardOccludedStates?.associate { it.displayId to it.keyguardOccluded }
151                     ?: emptyMap()
152         )
153     }
154 
155     private fun createWindowContainerChild(
156         proto: WindowContainerChildProto,
157         isActivityInTree: Boolean
158     ): WindowContainer? {
159         return createDisplayContent(proto.displayContent, isActivityInTree)
160             ?: createDisplayArea(proto.displayArea, isActivityInTree)
161                 ?: createTask(proto.task, isActivityInTree)
162                 ?: createTaskFragment(proto.taskFragment, isActivityInTree)
163                 ?: createActivity(proto.activity)
164                 ?: createWindowToken(proto.windowToken, isActivityInTree)
165                 ?: createWindowState(proto.window, isActivityInTree)
166                 ?: createWindowContainer(proto.windowContainer, children = emptyList())
167     }
168 
169     private fun createDisplayContent(
170         proto: DisplayContentProto?,
171         isActivityInTree: Boolean
172     ): DisplayContent? {
173         return if (proto == null) {
174             null
175         } else {
176             DisplayContent(
177                 displayId = proto.id,
178                 focusedRootTaskId = proto.focusedRootTaskId,
179                 resumedActivity = proto.resumedActivity?.title ?: "",
180                 singleTaskInstance = proto.singleTaskInstance,
181                 defaultPinnedStackBounds = proto.pinnedTaskController?.defaultBounds?.toRect()
182                         ?: Rect(),
183                 pinnedStackMovementBounds = proto.pinnedTaskController?.movementBounds?.toRect()
184                         ?: Rect(),
185                 displayRect =
186                     Rect(
187                         0,
188                         0,
189                         proto.displayInfo?.logicalWidth ?: 0,
190                         proto.displayInfo?.logicalHeight ?: 0
191                     ),
192                 appRect =
193                     Rect(0, 0, proto.displayInfo?.appWidth ?: 0, proto.displayInfo?.appHeight ?: 0),
194                 dpi = proto.dpi,
195                 flags = proto.displayInfo?.flags ?: 0,
196                 stableBounds = proto.displayFrames?.stableBounds?.toRect() ?: Rect(),
197                 surfaceSize = proto.surfaceSize,
198                 focusedApp = proto.focusedApp,
199                 lastTransition =
200                     appTransitionToString(proto.appTransition?.lastUsedAppTransition ?: 0),
201                 appTransitionState = appStateToString(proto.appTransition?.appTransitionState ?: 0),
202                 rotation =
203                     Rotation.getByValue(proto.displayRotation?.rotation ?: Surface.ROTATION_0),
204                 lastOrientation = proto.displayRotation?.lastOrientation ?: 0,
205                 cutout = createDisplayCutout(proto.displayInfo?.cutout),
206                 windowContainer =
207                     createWindowContainer(
208                         proto.rootDisplayArea.windowContainer,
209                         proto.rootDisplayArea.windowContainer.children.mapNotNull { p ->
210                             createWindowContainerChild(p, isActivityInTree)
211                         },
212                         nameOverride = proto.displayInfo?.name ?: ""
213                     )
214                         ?: error("Window container should not be null")
215             )
216         }
217     }
218 
219     private fun createDisplayArea(
220         proto: DisplayAreaProto?,
221         isActivityInTree: Boolean
222     ): DisplayArea? {
223         return if (proto == null) {
224             null
225         } else {
226             DisplayArea(
227                 isTaskDisplayArea = proto.isTaskDisplayArea,
228                 windowContainer =
229                     createWindowContainer(
230                         proto.windowContainer,
231                         proto.windowContainer.children.mapNotNull { p ->
232                             createWindowContainerChild(p, isActivityInTree)
233                         }
234                     )
235                         ?: error("Window container should not be null")
236             )
237         }
238     }
239 
240     private fun createTask(proto: TaskProto?, isActivityInTree: Boolean): Task? {
241         return if (proto == null) {
242             null
243         } else {
244             Task(
245                 activityType = proto.taskFragment?.activityType ?: proto.activityType,
246                 isFullscreen = proto.fillsParent,
247                 bounds = proto.bounds.toRect(),
248                 taskId = proto.id,
249                 rootTaskId = proto.rootTaskId,
250                 displayId = proto.taskFragment?.displayId ?: proto.displayId,
251                 lastNonFullscreenBounds = proto.lastNonFullscreenBounds?.toRect() ?: Rect(),
252                 realActivity = proto.realActivity,
253                 origActivity = proto.origActivity,
254                 resizeMode = proto.resizeMode,
255                 _resumedActivity = proto.resumedActivity?.title ?: "",
256                 animatingBounds = proto.animatingBounds,
257                 surfaceWidth = proto.surfaceWidth,
258                 surfaceHeight = proto.surfaceHeight,
259                 createdByOrganizer = proto.createdByOrganizer,
260                 minWidth = proto.taskFragment?.minWidth ?: proto.minWidth,
261                 minHeight = proto.taskFragment?.minHeight ?: proto.minHeight,
262                 windowContainer =
263                     createWindowContainer(
264                         proto.taskFragment?.windowContainer ?: proto.windowContainer,
265                         if (proto.taskFragment != null) {
266                             proto.taskFragment.windowContainer.children.mapNotNull { p ->
267                                 createWindowContainerChild(p, isActivityInTree)
268                             }
269                         } else {
270                             proto.windowContainer.children.mapNotNull { p ->
271                                 createWindowContainerChild(p, isActivityInTree)
272                             }
273                         }
274                     )
275                         ?: error("Window container should not be null")
276             )
277         }
278     }
279 
280     private fun createTaskFragment(
281         proto: TaskFragmentProto?,
282         isActivityInTree: Boolean
283     ): TaskFragment? {
284         return if (proto == null) {
285             null
286         } else {
287             TaskFragment(
288                 activityType = proto.activityType,
289                 displayId = proto.displayId,
290                 minWidth = proto.minWidth,
291                 minHeight = proto.minHeight,
292                 windowContainer =
293                     createWindowContainer(
294                         proto.windowContainer,
295                         proto.windowContainer.children.mapNotNull { p ->
296                             createWindowContainerChild(p, isActivityInTree)
297                         }
298                     )
299                         ?: error("Window container should not be null")
300             )
301         }
302     }
303 
304     private fun createActivity(proto: ActivityRecordProto?): Activity? {
305         return if (proto == null) {
306             null
307         } else {
308             Activity(
309                 state = proto.state,
310                 frontOfTask = proto.frontOfTask,
311                 procId = proto.procId,
312                 isTranslucent = proto.translucent,
313                 windowContainer =
314                     createWindowContainer(
315                         proto.windowToken.windowContainer,
316                         proto.windowToken.windowContainer.children.mapNotNull { p ->
317                             createWindowContainerChild(p, isActivityInTree = true)
318                         },
319                         nameOverride = proto.name
320                     )
321                         ?: error("Window container should not be null")
322             )
323         }
324     }
325 
326     private fun createWindowToken(
327         proto: WindowTokenProto?,
328         isActivityInTree: Boolean
329     ): WindowToken? {
330         return if (proto == null) {
331             null
332         } else {
333             WindowToken(
334                 createWindowContainer(
335                     proto.windowContainer,
336                     proto.windowContainer.children.mapNotNull { p ->
337                         createWindowContainerChild(p, isActivityInTree)
338                     }
339                 )
340                     ?: error("Window container should not be null")
341             )
342         }
343     }
344 
345     private fun createWindowState(
346         proto: WindowStateProto?,
347         isActivityInTree: Boolean
348     ): WindowState? {
349         return if (proto == null) {
350             null
351         } else {
352             val identifierName = proto.windowContainer.identifier?.title ?: ""
353             WindowState(
354                 attributes = createWindowLayerParams(proto.attributes),
355                 displayId = proto.displayId,
356                 stackId = proto.stackId,
357                 layer = proto.animator?.surface?.layer ?: 0,
358                 isSurfaceShown = proto.animator?.surface?.shown ?: false,
359                 windowType =
360                     when {
361                         identifierName.startsWith(PlatformConsts.STARTING_WINDOW_PREFIX) ->
362                             PlatformConsts.WINDOW_TYPE_STARTING
363                         proto.animatingExit -> PlatformConsts.WINDOW_TYPE_EXITING
364                         identifierName.startsWith(PlatformConsts.DEBUGGER_WINDOW_PREFIX) ->
365                             PlatformConsts.WINDOW_TYPE_STARTING
366                         else -> 0
367                     },
368                 requestedSize = Size.from(proto.requestedWidth, proto.requestedHeight),
369                 surfacePosition = proto.surfacePosition?.toRect(),
370                 frame = proto.windowFrames?.frame?.toRect() ?: Rect(),
371                 containingFrame = proto.windowFrames?.containingFrame?.toRect() ?: Rect(),
372                 parentFrame = proto.windowFrames?.parentFrame?.toRect() ?: Rect(),
373                 contentFrame = proto.windowFrames?.contentFrame?.toRect() ?: Rect(),
374                 contentInsets = proto.windowFrames?.contentInsets?.toRect() ?: Rect(),
375                 surfaceInsets = proto.surfaceInsets?.toRect() ?: Rect(),
376                 givenContentInsets = proto.givenContentInsets?.toRect() ?: Rect(),
377                 crop = proto.animator?.lastClipRect?.toRect() ?: Rect(),
378                 windowContainer =
379                     createWindowContainer(
380                         proto.windowContainer,
381                         proto.windowContainer.children.mapNotNull { p ->
382                             createWindowContainerChild(p, isActivityInTree)
383                         },
384                         nameOverride =
385                             getWindowTitle(
386                                 when {
387                                     // Existing code depends on the prefix being removed
388                                     identifierName.startsWith(
389                                         PlatformConsts.STARTING_WINDOW_PREFIX
390                                     ) ->
391                                         identifierName.substring(
392                                             PlatformConsts.STARTING_WINDOW_PREFIX.length
393                                         )
394                                     identifierName.startsWith(
395                                         PlatformConsts.DEBUGGER_WINDOW_PREFIX
396                                     ) ->
397                                         identifierName.substring(
398                                             PlatformConsts.DEBUGGER_WINDOW_PREFIX.length
399                                         )
400                                     else -> identifierName
401                                 }
402                             )
403                     )
404                         ?: error("Window container should not be null"),
405                 isAppWindow = isActivityInTree
406             )
407         }
408     }
409 
410     private fun createWindowLayerParams(proto: WindowLayoutParamsProto?): WindowLayoutParams {
411         return WindowLayoutParams.from(
412             type = proto?.type ?: 0,
413             x = proto?.x ?: 0,
414             y = proto?.y ?: 0,
415             width = proto?.width ?: 0,
416             height = proto?.height ?: 0,
417             horizontalMargin = proto?.horizontalMargin ?: 0f,
418             verticalMargin = proto?.verticalMargin ?: 0f,
419             gravity = proto?.gravity ?: 0,
420             softInputMode = proto?.softInputMode ?: 0,
421             format = proto?.format ?: 0,
422             windowAnimations = proto?.windowAnimations ?: 0,
423             alpha = proto?.alpha ?: 0f,
424             screenBrightness = proto?.screenBrightness ?: 0f,
425             buttonBrightness = proto?.buttonBrightness ?: 0f,
426             rotationAnimation = proto?.rotationAnimation ?: 0,
427             preferredRefreshRate = proto?.preferredRefreshRate ?: 0f,
428             preferredDisplayModeId = proto?.preferredDisplayModeId ?: 0,
429             hasSystemUiListeners = proto?.hasSystemUiListeners ?: false,
430             inputFeatureFlags = proto?.inputFeatureFlags ?: 0,
431             userActivityTimeout = proto?.userActivityTimeout ?: 0,
432             colorMode = proto?.colorMode ?: 0,
433             flags = proto?.flags ?: 0,
434             privateFlags = proto?.privateFlags ?: 0,
435             systemUiVisibilityFlags = proto?.systemUiVisibilityFlags ?: 0,
436             subtreeSystemUiVisibilityFlags = proto?.subtreeSystemUiVisibilityFlags ?: 0,
437             appearance = proto?.appearance ?: 0,
438             behavior = proto?.behavior ?: 0,
439             fitInsetsTypes = proto?.fitInsetsTypes ?: 0,
440             fitInsetsSides = proto?.fitInsetsSides ?: 0,
441             fitIgnoreVisibility = proto?.fitIgnoreVisibility ?: false
442         )
443     }
444 
445     private fun createConfigurationContainer(
446         proto: ConfigurationContainerProto?
447     ): ConfigurationContainer {
448         return ConfigurationContainerImpl.from(
449             overrideConfiguration = createConfiguration(proto?.overrideConfiguration),
450             fullConfiguration = createConfiguration(proto?.fullConfiguration),
451             mergedOverrideConfiguration = createConfiguration(proto?.mergedOverrideConfiguration)
452         )
453     }
454 
455     private fun createConfiguration(proto: ConfigurationProto?): Configuration? {
456         return if (proto == null) {
457             null
458         } else {
459             Configuration.from(
460                 windowConfiguration =
461                     if (proto.windowConfiguration != null) {
462                         createWindowConfiguration(proto.windowConfiguration)
463                     } else {
464                         null
465                     },
466                 densityDpi = proto.densityDpi,
467                 orientation = proto.orientation,
468                 screenHeightDp = proto.screenHeightDp,
469                 screenWidthDp = proto.screenWidthDp,
470                 smallestScreenWidthDp = proto.smallestScreenWidthDp,
471                 screenLayout = proto.screenLayout,
472                 uiMode = proto.uiMode
473             )
474         }
475     }
476 
477     private fun createWindowConfiguration(proto: WindowConfigurationProto): WindowConfiguration {
478         return WindowConfiguration.from(
479             appBounds = proto.appBounds?.toRect(),
480             bounds = proto.bounds?.toRect(),
481             maxBounds = proto.maxBounds?.toRect(),
482             windowingMode = proto.windowingMode,
483             activityType = proto.activityType
484         )
485     }
486 
487     private fun createWindowContainer(
488         proto: WindowContainerProto?,
489         children: List<WindowContainer>,
490         nameOverride: String? = null,
491         visibleOverride: Boolean? = null
492     ): WindowContainer? {
493         return if (proto == null) {
494             null
495         } else {
496             WindowContainerImpl(
497                 title = nameOverride ?: proto.identifier?.title ?: "",
498                 token = proto.identifier?.hashCode?.toString(16) ?: "",
499                 orientation = proto.orientation,
500                 _isVisible = visibleOverride ?: proto.visible,
501                 configurationContainer = createConfigurationContainer(proto.configurationContainer),
502                 layerId = proto.surfaceControl?.layerId ?: 0,
503                 _children = children,
504                 computedZ = computedZCounter++
505             )
506         }
507     }
508 
509     private fun createDisplayCutout(proto: DisplayCutoutProto?): DisplayCutout? {
510         return if (proto == null) {
511             null
512         } else {
513             DisplayCutout.from(
514                 proto.insets?.toInsets() ?: Insets.NONE,
515                 proto.boundLeft?.toRect() ?: Rect(),
516                 proto.boundTop?.toRect() ?: Rect(),
517                 proto.boundRight?.toRect() ?: Rect(),
518                 proto.boundBottom?.toRect() ?: Rect(),
519                 proto.waterfallInsets?.toInsets() ?: Insets.NONE
520             )
521         }
522     }
523 
524     private fun appTransitionToString(transition: Int): String {
525         return when (transition) {
526             ViewProtoEnums.TRANSIT_UNSET -> "TRANSIT_UNSET"
527             ViewProtoEnums.TRANSIT_NONE -> "TRANSIT_NONE"
528             ViewProtoEnums.TRANSIT_ACTIVITY_OPEN -> TRANSIT_ACTIVITY_OPEN
529             ViewProtoEnums.TRANSIT_ACTIVITY_CLOSE -> TRANSIT_ACTIVITY_CLOSE
530             ViewProtoEnums.TRANSIT_TASK_OPEN -> TRANSIT_TASK_OPEN
531             ViewProtoEnums.TRANSIT_TASK_CLOSE -> TRANSIT_TASK_CLOSE
532             ViewProtoEnums.TRANSIT_TASK_TO_FRONT -> "TRANSIT_TASK_TO_FRONT"
533             ViewProtoEnums.TRANSIT_TASK_TO_BACK -> "TRANSIT_TASK_TO_BACK"
534             ViewProtoEnums.TRANSIT_WALLPAPER_CLOSE -> TRANSIT_WALLPAPER_CLOSE
535             ViewProtoEnums.TRANSIT_WALLPAPER_OPEN -> TRANSIT_WALLPAPER_OPEN
536             ViewProtoEnums.TRANSIT_WALLPAPER_INTRA_OPEN -> TRANSIT_WALLPAPER_INTRA_OPEN
537             ViewProtoEnums.TRANSIT_WALLPAPER_INTRA_CLOSE -> TRANSIT_WALLPAPER_INTRA_CLOSE
538             ViewProtoEnums.TRANSIT_TASK_OPEN_BEHIND -> "TRANSIT_TASK_OPEN_BEHIND"
539             ViewProtoEnums.TRANSIT_ACTIVITY_RELAUNCH -> "TRANSIT_ACTIVITY_RELAUNCH"
540             ViewProtoEnums.TRANSIT_DOCK_TASK_FROM_RECENTS -> "TRANSIT_DOCK_TASK_FROM_RECENTS"
541             ViewProtoEnums.TRANSIT_KEYGUARD_GOING_AWAY -> TRANSIT_KEYGUARD_GOING_AWAY
542             ViewProtoEnums.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER ->
543                 TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER
544             ViewProtoEnums.TRANSIT_KEYGUARD_OCCLUDE -> TRANSIT_KEYGUARD_OCCLUDE
545             ViewProtoEnums.TRANSIT_KEYGUARD_UNOCCLUDE -> TRANSIT_KEYGUARD_UNOCCLUDE
546             ViewProtoEnums.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN -> TRANSIT_TRANSLUCENT_ACTIVITY_OPEN
547             ViewProtoEnums.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE -> TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE
548             ViewProtoEnums.TRANSIT_CRASHING_ACTIVITY_CLOSE -> "TRANSIT_CRASHING_ACTIVITY_CLOSE"
549             else -> error("Invalid lastUsedAppTransition")
550         }
551     }
552 
553     private fun appStateToString(appState: Int): String {
554         return when (appState) {
555             AppTransitionProto.APP_STATE_IDLE -> "APP_STATE_IDLE"
556             AppTransitionProto.APP_STATE_READY -> "APP_STATE_READY"
557             AppTransitionProto.APP_STATE_RUNNING -> "APP_STATE_RUNNING"
558             AppTransitionProto.APP_STATE_TIMEOUT -> "APP_STATE_TIMEOUT"
559             else -> error("Invalid AppTransitionState")
560         }
561     }
562 
563     private fun RectProto.toRect() = Rect(this.left, this.top, this.right, this.bottom)
564 
565     private fun RectProto.toInsets() = Insets.of(this.left, this.top, this.right, this.bottom)
566 
567     companion object {
568         private const val TRANSIT_ACTIVITY_OPEN = "TRANSIT_ACTIVITY_OPEN"
569         private const val TRANSIT_ACTIVITY_CLOSE = "TRANSIT_ACTIVITY_CLOSE"
570         private const val TRANSIT_TASK_OPEN = "TRANSIT_TASK_OPEN"
571         private const val TRANSIT_TASK_CLOSE = "TRANSIT_TASK_CLOSE"
572         private const val TRANSIT_WALLPAPER_OPEN = "TRANSIT_WALLPAPER_OPEN"
573         private const val TRANSIT_WALLPAPER_CLOSE = "TRANSIT_WALLPAPER_CLOSE"
574         private const val TRANSIT_WALLPAPER_INTRA_OPEN = "TRANSIT_WALLPAPER_INTRA_OPEN"
575         private const val TRANSIT_WALLPAPER_INTRA_CLOSE = "TRANSIT_WALLPAPER_INTRA_CLOSE"
576         private const val TRANSIT_KEYGUARD_GOING_AWAY = "TRANSIT_KEYGUARD_GOING_AWAY"
577         private const val TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER =
578             "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER"
579         private const val TRANSIT_KEYGUARD_OCCLUDE = "TRANSIT_KEYGUARD_OCCLUDE"
580         private const val TRANSIT_KEYGUARD_UNOCCLUDE = "TRANSIT_KEYGUARD_UNOCCLUDE"
581         private const val TRANSIT_TRANSLUCENT_ACTIVITY_OPEN = "TRANSIT_TRANSLUCENT_ACTIVITY_OPEN"
582         private const val TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE = "TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE"
583 
584         private fun getWindowTitle(title: String): String {
585             return when {
586                 // Existing code depends on the prefix being removed
587                 title.startsWith(PlatformConsts.STARTING_WINDOW_PREFIX) ->
588                     title.substring(PlatformConsts.STARTING_WINDOW_PREFIX.length)
589                 title.startsWith(PlatformConsts.DEBUGGER_WINDOW_PREFIX) ->
590                     title.substring(PlatformConsts.DEBUGGER_WINDOW_PREFIX.length)
591                 else -> title
592             }
593         }
594     }
595 }
596