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