1/* 2 * 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 17import {assertDefined} from 'common/assert_utils'; 18import {TraceRect} from 'trace/trace_rect'; 19import {TraceRectBuilder} from 'trace/trace_rect_builder'; 20import {Computation} from 'trace/tree_node/computation'; 21import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node'; 22 23class RectWmFactory { 24 makeDisplayRect( 25 display: HierarchyTreeNode, 26 absoluteZ: number, 27 focusedApp: string, 28 ): TraceRect { 29 const displayInfo = display.getEagerPropertyByName('displayInfo'); 30 const displayRectWidth = 31 displayInfo?.getChildByName('logicalWidth')?.getValue() ?? 0; 32 const displayRectHeight = 33 displayInfo?.getChildByName('logicalHeight')?.getValue() ?? 0; 34 35 const displayFocusedApp = display 36 .getEagerPropertyByName('focusedApp') 37 ?.getValue(); 38 39 return new TraceRectBuilder() 40 .setX(0) 41 .setY(0) 42 .setWidth(displayRectWidth) 43 .setHeight(displayRectHeight) 44 .setId(display.id) 45 .setName(`Display - ${display.name}`) 46 .setCornerRadius(0) 47 .setGroupId( 48 assertDefined(display.getEagerPropertyByName('id')).getValue(), 49 ) 50 .setIsVisible(false) 51 .setIsDisplay(true) 52 .setIsActiveDisplay(focusedApp === displayFocusedApp) 53 .setDepth(absoluteZ) 54 .setIsSpy(false) 55 .build(); 56 } 57 58 makeWindowStateRect( 59 container: HierarchyTreeNode, 60 absoluteZ: number, 61 ): TraceRect | undefined { 62 const displayId = container.getEagerPropertyByName('displayId')?.getValue(); 63 if (displayId === undefined) { 64 return undefined; 65 } 66 67 const isVisible = 68 container.getEagerPropertyByName('isComputedVisible')?.getValue() ?? 69 false; 70 71 const alpha = 72 container 73 .getEagerPropertyByName('attributes') 74 ?.getChildByName('alpha') 75 ?.getValue() ?? 1; 76 77 const frame = container 78 .getEagerPropertyByName('windowFrames') 79 ?.getChildByName('frame'); 80 if (frame === undefined || frame.getAllChildren().length === 0) { 81 return undefined; 82 } 83 84 const rectLeft = assertDefined(frame.getChildByName('left')).getValue(); 85 const rectTop = assertDefined(frame.getChildByName('top')).getValue(); 86 const rectRight = assertDefined(frame.getChildByName('right')).getValue(); 87 const rectBottom = assertDefined(frame.getChildByName('bottom')).getValue(); 88 89 return new TraceRectBuilder() 90 .setX(rectLeft) 91 .setY(rectTop) 92 .setWidth(rectRight - rectLeft) 93 .setHeight(rectBottom - rectTop) 94 .setId(container.id) 95 .setName(container.name) 96 .setCornerRadius(0) 97 .setGroupId(displayId) 98 .setIsVisible(isVisible) 99 .setIsDisplay(false) 100 .setDepth(absoluteZ) 101 .setOpacity(alpha) 102 .setIsSpy(false) 103 .build(); 104 } 105} 106 107export class RectsComputation implements Computation { 108 private root: HierarchyTreeNode | undefined; 109 private readonly rectsFactory = new RectWmFactory(); 110 111 setRoot(value: HierarchyTreeNode): this { 112 this.root = value; 113 return this; 114 } 115 116 executeInPlace(): void { 117 if (!this.root) { 118 throw new Error('root not set in WM rects computation'); 119 } 120 121 const focusedApp = this.root 122 .getEagerPropertyByName('focusedApp') 123 ?.getValue(); 124 125 this.root.getAllChildren().forEach((displayContent) => { 126 const displayRect = this.rectsFactory.makeDisplayRect( 127 displayContent, 128 0, 129 focusedApp, 130 ); 131 displayContent.setRects([displayRect]); 132 133 let absoluteZ = 1; 134 displayContent.getAllChildren().forEach((child) => { 135 child.forEachNodeDfs((container) => { 136 if (!container.id.startsWith('WindowState ')) return; 137 138 const rect = this.rectsFactory.makeWindowStateRect( 139 container, 140 absoluteZ, 141 ); 142 if (!rect) { 143 return; 144 } 145 container.setRects([rect]); 146 absoluteZ++; 147 }); 148 }); 149 }); 150 } 151} 152