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 {Transform} from 'parsers/surface_flinger/transform_utils'; 19import {HierarchyTreeBuilder} from 'test/unit/hierarchy_tree_builder'; 20import {TraceRectBuilder} from 'trace/trace_rect_builder'; 21import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node'; 22import {UiRect} from 'viewers/components/rects/ui_rect'; 23import {UiRectBuilder} from 'viewers/components/rects/ui_rect_builder'; 24import {UI_RECT_FACTORY} from './ui_rect_factory'; 25 26describe('UI_RECT_FACTORY', () => { 27 let hierarchyRoot: HierarchyTreeNode; 28 let node1: HierarchyTreeNode; 29 let node2: HierarchyTreeNode; 30 31 beforeEach(() => { 32 hierarchyRoot = new HierarchyTreeBuilder() 33 .setId('TreeEntry') 34 .setName('root') 35 .setChildren([ 36 {id: 1, name: 'node1'}, 37 {id: 2, name: 'node2'}, 38 ]) 39 .build(); 40 node1 = assertDefined(hierarchyRoot.getChildByName('node1')); 41 node2 = assertDefined(hierarchyRoot.getChildByName('node2')); 42 }); 43 44 it('extracts rects from hierarchy tree', () => { 45 buildRectAndSetToNode(node1, 0); 46 buildRectAndSetToNode(node2, 1); 47 48 const expectedUiRect1 = new UiRectBuilder() 49 .setX(0) 50 .setY(0) 51 .setWidth(1) 52 .setHeight(1) 53 .setId('1 node1') 54 .setLabel('node1') 55 .setCornerRadius(0) 56 .setGroupId(0) 57 .setTransform(Transform.EMPTY.matrix) 58 .setIsVisible(true) 59 .setIsDisplay(false) 60 .setIsActiveDisplay(false) 61 .setIsClickable(true) 62 .setHasContent(false) 63 .setDepth(0) 64 .setOpacity(0.5) 65 .build(); 66 67 const expectedUiRect2 = new UiRectBuilder() 68 .setX(0) 69 .setY(0) 70 .setWidth(1) 71 .setHeight(1) 72 .setId('2 node2') 73 .setLabel('node2') 74 .setCornerRadius(0) 75 .setGroupId(0) 76 .setTransform(Transform.EMPTY.matrix) 77 .setIsVisible(true) 78 .setIsDisplay(false) 79 .setIsActiveDisplay(false) 80 .setIsClickable(true) 81 .setHasContent(false) 82 .setDepth(1) 83 .setOpacity(0.5) 84 .build(); 85 86 const expectedRects: UiRect[] = [expectedUiRect1, expectedUiRect2]; 87 88 expect(UI_RECT_FACTORY.makeUiRects(hierarchyRoot)).toEqual(expectedRects); 89 }); 90 91 it('makes rects with data from trace rect', () => { 92 buildRectAndSetToNode(node2, 1, 5, 10, true, true, false, true); 93 94 const expectedUiRect2 = new UiRectBuilder() 95 .setX(0) 96 .setY(0) 97 .setWidth(5) 98 .setHeight(10) 99 .setId('2 node2') 100 .setLabel('node2') 101 .setCornerRadius(0) 102 .setGroupId(0) 103 .setTransform(Transform.EMPTY.matrix) 104 .setIsVisible(true) 105 .setIsDisplay(true) 106 .setIsActiveDisplay(true) 107 .setIsClickable(false) 108 .setHasContent(false) 109 .setDepth(1) 110 .setOpacity(0.5) 111 .build(); 112 113 const expectedRects: UiRect[] = [expectedUiRect2]; 114 115 expect(UI_RECT_FACTORY.makeUiRects(hierarchyRoot)).toEqual(expectedRects); 116 }); 117 118 it('handles depth order different to dfs order', () => { 119 buildRectAndSetToNode(node1, 1); 120 buildRectAndSetToNode(node2, 0); 121 122 const expectedUiRect1 = new UiRectBuilder() 123 .setX(0) 124 .setY(0) 125 .setWidth(1) 126 .setHeight(1) 127 .setId('1 node1') 128 .setLabel('node1') 129 .setCornerRadius(0) 130 .setGroupId(0) 131 .setTransform(Transform.EMPTY.matrix) 132 .setIsVisible(true) 133 .setIsDisplay(false) 134 .setIsActiveDisplay(false) 135 .setIsClickable(true) 136 .setHasContent(false) 137 .setDepth(1) 138 .setOpacity(0.5) 139 .build(); 140 141 const expectedUiRect2 = new UiRectBuilder() 142 .setX(0) 143 .setY(0) 144 .setWidth(1) 145 .setHeight(1) 146 .setId('2 node2') 147 .setLabel('node2') 148 .setCornerRadius(0) 149 .setGroupId(0) 150 .setTransform(Transform.EMPTY.matrix) 151 .setIsVisible(true) 152 .setIsDisplay(false) 153 .setIsActiveDisplay(false) 154 .setIsClickable(true) 155 .setHasContent(false) 156 .setDepth(0) 157 .setOpacity(0.5) 158 .build(); 159 160 const expectedRects: UiRect[] = [expectedUiRect1, expectedUiRect2]; 161 expect(UI_RECT_FACTORY.makeUiRects(hierarchyRoot)).toEqual(expectedRects); 162 }); 163 164 it('makes vc rects with groupId, content and empty label', () => { 165 const GROUP_ID = 11; 166 167 buildRectAndSetToNode(node1, 1); 168 buildRectAndSetToNode(node2, 0); 169 170 const expectedVcUiRect1 = new UiRectBuilder() 171 .setX(0) 172 .setY(0) 173 .setWidth(1) 174 .setHeight(1) 175 .setId('1 node1') 176 .setLabel('') 177 .setCornerRadius(0) 178 .setGroupId(GROUP_ID) 179 .setTransform(Transform.EMPTY.matrix) 180 .setIsVisible(true) 181 .setIsDisplay(false) 182 .setIsActiveDisplay(false) 183 .setIsClickable(true) 184 .setHasContent(true) 185 .setDepth(1) 186 .setOpacity(0.5) 187 .build(); 188 189 const expectedVcUiRect2 = new UiRectBuilder() 190 .setX(0) 191 .setY(0) 192 .setWidth(1) 193 .setHeight(1) 194 .setId('2 node2') 195 .setLabel('') 196 .setCornerRadius(0) 197 .setGroupId(GROUP_ID) 198 .setTransform(Transform.EMPTY.matrix) 199 .setIsVisible(true) 200 .setIsDisplay(false) 201 .setIsActiveDisplay(false) 202 .setIsClickable(true) 203 .setHasContent(true) 204 .setDepth(0) 205 .setOpacity(0.5) 206 .build(); 207 208 const expectedRects: UiRect[] = [expectedVcUiRect1, expectedVcUiRect2]; 209 expect(UI_RECT_FACTORY.makeVcUiRects(hierarchyRoot, GROUP_ID)).toEqual( 210 expectedRects, 211 ); 212 }); 213 214 it('discards vc trace rects with zero height or width', () => { 215 const GROUP_ID = 11; 216 217 buildRectAndSetToNode(node1, 1, 0, 1); 218 buildRectAndSetToNode(node2, 0, 1, 0); 219 220 expect(UI_RECT_FACTORY.makeVcUiRects(hierarchyRoot, GROUP_ID)).toEqual([]); 221 }); 222 223 it('makes input rects', () => { 224 // The root of the hierarchy should contain the display info in the primary rects. 225 buildRectAndSetToNode(hierarchyRoot, 0, 1, 1, true, true); 226 // The rest of the nodes should contain input windows in the secondary rects. 227 // The opacity is determined by whether the window is a spy and display. 228 buildRectAndSetToNode(node1, 1, 1, 1, false, false, true); 229 buildRectAndSetToNode(node2, 2, 1, 1, false, false, false); 230 231 function hasContent(id: string) { 232 return id === node1.id; 233 } 234 235 const expectedRootRect = new UiRectBuilder() 236 .setX(0) 237 .setY(0) 238 .setWidth(1) 239 .setHeight(1) 240 .setId('TreeEntry root') 241 .setLabel('root') 242 .setCornerRadius(0) 243 .setGroupId(0) 244 .setTransform(Transform.EMPTY.matrix) 245 .setIsVisible(true) 246 .setIsDisplay(true) 247 .setIsActiveDisplay(false) 248 .setIsClickable(true) 249 .setHasContent(false) 250 .setDepth(0) 251 .setOpacity(1) 252 .build(); 253 254 const expectedInputRect1 = new UiRectBuilder() 255 .setX(0) 256 .setY(0) 257 .setWidth(1) 258 .setHeight(1) 259 .setId('1 node1') 260 .setLabel('node1') 261 .setCornerRadius(0) 262 .setGroupId(0) 263 .setTransform(Transform.EMPTY.matrix) 264 .setIsVisible(true) 265 .setIsDisplay(false) 266 .setIsActiveDisplay(false) 267 .setIsClickable(true) 268 .setHasContent(true) 269 .setDepth(1) 270 .setOpacity(0.25) 271 .build(); 272 273 const expectedInputRect2 = new UiRectBuilder() 274 .setX(0) 275 .setY(0) 276 .setWidth(1) 277 .setHeight(1) 278 .setId('2 node2') 279 .setLabel('node2') 280 .setCornerRadius(0) 281 .setGroupId(0) 282 .setTransform(Transform.EMPTY.matrix) 283 .setIsVisible(true) 284 .setIsDisplay(false) 285 .setIsActiveDisplay(false) 286 .setIsClickable(true) 287 .setHasContent(false) 288 .setDepth(2) 289 .setOpacity(0.9) 290 .build(); 291 292 const expectedRects: UiRect[] = [ 293 expectedRootRect, 294 expectedInputRect1, 295 expectedInputRect2, 296 ]; 297 expect(UI_RECT_FACTORY.makeInputRects(hierarchyRoot, hasContent)).toEqual( 298 expectedRects, 299 ); 300 }); 301 302 function buildRectAndSetToNode( 303 node: HierarchyTreeNode, 304 depth: number, 305 width = 1, 306 height = 1, 307 isPrimary = true, 308 isDisplay = false, 309 isSpy = false, 310 isActiveDisplay = false, 311 ) { 312 const rect = new TraceRectBuilder() 313 .setX(0) 314 .setY(0) 315 .setWidth(width) 316 .setHeight(height) 317 .setId(node.id) 318 .setName(node.name) 319 .setCornerRadius(0) 320 .setTransform(Transform.EMPTY.matrix) 321 .setDepth(depth) 322 .setGroupId(0) 323 .setIsVisible(true) 324 .setIsDisplay(isDisplay) 325 .setIsActiveDisplay(isActiveDisplay) 326 .setOpacity(0.5) 327 .setIsSpy(isSpy) 328 .build(); 329 330 isPrimary ? node.setRects([rect]) : node.setSecondaryRects([rect]); 331 } 332}); 333