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 {perfetto} from 'protos/windowmanager/latest/static'; 19import {com} from 'protos/windowmanager/udc/static'; 20import {HierarchyTreeBuilder} from 'test/unit/hierarchy_tree_builder'; 21import {TreeNodeUtils} from 'test/unit/tree_node_utils'; 22import {TraceRect} from 'trace/trace_rect'; 23import {TraceRectBuilder} from 'trace/trace_rect_builder'; 24import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node'; 25import {RectsComputation} from './rects_computation'; 26 27type DisplayContentProto = 28 | com.android.server.wm.IDisplayContentProto 29 | perfetto.protos.IDisplayContentProto; 30type WindowStateProto = 31 | com.android.server.wm.IWindowStateProto 32 | perfetto.protos.IWindowStateProto; 33 34describe('WindowManager RectsComputation', () => { 35 let hierarchyRoot: HierarchyTreeNode; 36 let computation: RectsComputation; 37 let displayContent: HierarchyTreeNode; 38 39 beforeEach(() => { 40 hierarchyRoot = new HierarchyTreeBuilder() 41 .setId('WindowManagerState') 42 .setName('root') 43 .setProperties({focusedApp: 'testApp'}) 44 .setChildren([ 45 { 46 id: 1, 47 name: 'Test Display', 48 properties: { 49 id: 1, 50 name: 'Test Display', 51 displayInfo: { 52 logicalWidth: 5, 53 logicalHeight: 5, 54 }, 55 } as DisplayContentProto, 56 }, 57 { 58 id: 2, 59 name: 'Focused Display', 60 properties: { 61 id: 2, 62 name: 'Focused Display', 63 displayInfo: { 64 logicalWidth: 5, 65 logicalHeight: 5, 66 }, 67 focusedApp: 'testApp', 68 } as DisplayContentProto, 69 }, 70 ]) 71 .build(); 72 displayContent = assertDefined( 73 hierarchyRoot.getChildByName('Test Display'), 74 ); 75 computation = new RectsComputation(); 76 }); 77 78 it('makes display rects', () => { 79 const expectedDisplayRects = [ 80 new TraceRectBuilder() 81 .setX(0) 82 .setY(0) 83 .setWidth(5) 84 .setHeight(5) 85 .setId('1 Test Display') 86 .setName('Display - Test Display') 87 .setCornerRadius(0) 88 .setDepth(0) 89 .setGroupId(1) 90 .setIsVisible(false) 91 .setIsDisplay(true) 92 .setIsActiveDisplay(false) 93 .setIsSpy(false) 94 .build(), 95 96 new TraceRectBuilder() 97 .setX(0) 98 .setY(0) 99 .setWidth(5) 100 .setHeight(5) 101 .setId('2 Focused Display') 102 .setName('Display - Focused Display') 103 .setCornerRadius(0) 104 .setDepth(0) 105 .setGroupId(2) 106 .setIsVisible(false) 107 .setIsDisplay(true) 108 .setIsActiveDisplay(true) 109 .setIsSpy(false) 110 .build(), 111 ]; 112 113 computation.setRoot(hierarchyRoot).executeInPlace(); 114 115 const displayRects = displayContent 116 .getRects() 117 ?.concat( 118 assertDefined( 119 hierarchyRoot.getChildByName('Focused Display')?.getRects(), 120 ), 121 ); 122 123 expect(displayRects).toEqual(expectedDisplayRects); 124 }); 125 126 it('makes window state rects', () => { 127 const state1Node = TreeNodeUtils.makeHierarchyNode({ 128 id: 'WindowState', 129 name: 'state1', 130 displayId: 1, 131 isComputedVisible: true, 132 windowFrames: { 133 frame: {left: 0, top: 0, right: 1, bottom: 1}, 134 }, 135 attributes: { 136 alpha: 0.5, 137 }, 138 } as WindowStateProto); 139 140 state1Node.addOrReplaceChild( 141 TreeNodeUtils.makeHierarchyNode({ 142 id: 'WindowState', 143 name: 'state2', 144 displayId: 1, 145 isComputedVisible: false, 146 windowFrames: { 147 frame: {left: 0, top: 0, right: 2, bottom: 2}, 148 }, 149 attributes: { 150 alpha: 0.5, 151 }, 152 } as WindowStateProto), 153 ); 154 displayContent.addOrReplaceChild(state1Node); 155 156 const expectedRects: TraceRect[] = [ 157 new TraceRectBuilder() 158 .setX(0) 159 .setY(0) 160 .setWidth(1) 161 .setHeight(1) 162 .setId('WindowState state1') 163 .setName('state1') 164 .setCornerRadius(0) 165 .setDepth(1) 166 .setGroupId(1) 167 .setIsVisible(true) 168 .setIsDisplay(false) 169 .setOpacity(0.5) 170 .setIsSpy(false) 171 .build(), 172 173 new TraceRectBuilder() 174 .setX(0) 175 .setY(0) 176 .setWidth(2) 177 .setHeight(2) 178 .setId('WindowState state2') 179 .setName('state2') 180 .setCornerRadius(0) 181 .setDepth(2) 182 .setGroupId(1) 183 .setIsVisible(false) 184 .setIsDisplay(false) 185 .setOpacity(0.5) 186 .setIsSpy(false) 187 .build(), 188 ]; 189 190 computation.setRoot(hierarchyRoot).executeInPlace(); 191 192 const rects: TraceRect[] = []; 193 hierarchyRoot.forEachNodeDfs((node) => { 194 const nodeRects = node.getRects(); 195 if (nodeRects && nodeRects.every((rect) => !rect.isDisplay)) { 196 rects.push(...nodeRects); 197 } 198 }); 199 200 expect(rects).toEqual(expectedRects); 201 }); 202}); 203