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 */ 16import { 17 Component, 18 ElementRef, 19 EventEmitter, 20 Inject, 21 Input, 22 Output, 23} from '@angular/core'; 24import {assertDefined} from 'common/assert_utils'; 25import {SfCuratedProperties} from 'viewers/common/curated_properties'; 26import {UiPropertyTreeNode} from 'viewers/common/ui_property_tree_node'; 27import {ViewerEvents} from 'viewers/common/viewer_events'; 28import {inlineButtonStyle} from './styles/clickable_property.styles'; 29import {viewerCardInnerStyle} from './styles/viewer_card.styles'; 30 31@Component({ 32 selector: 'surface-flinger-property-groups', 33 template: ` 34 <div class="title-section"> 35 <collapsible-section-title 36 title="PROPERTIES" 37 (collapseButtonClicked)="collapseButtonClicked.emit()"></collapsible-section-title> 38 </div> 39 40 <span class="mat-body-1 placeholder-text" *ngIf="!properties"> Layer not selected. </span> 41 42 <div class="property-groups-content" *ngIf="properties"> 43 <div class="group"> 44 <h3 class="group-header mat-subheading-2">Visibility</h3> 45 <div class="left-column"> 46 <p class="mat-body-2 flags"> 47 <span class="mat-body-1">Flags:</span> 48 &ngsp; 49 {{ properties.flags }} 50 </p> 51 <span *ngFor="let summaryProperty of properties.summary" class="mat-body-2 summary inline"> 52 <span class="mat-body-1" [matTooltip]="summaryProperty.desc" [matTooltipShowDelay]="400">{{ summaryProperty.key }}:</span> 53 <ng-container *ngIf="summaryProperty.simpleValue"> 54 {{ summaryProperty.simpleValue }} 55 </ng-container> 56 <ng-container *ngIf="summaryProperty.layerValues"> 57 &ngsp; 58 <ng-container *ngFor="let layer of summaryProperty.layerValues; index as i"> 59 <button 60 mat-button 61 color="primary" 62 [matTooltip]="layer.name" 63 (click)="onIdClicked(layer.nodeId)"> 64 {{ layer.layerId }} 65 </button> 66 {{(i === summaryProperty.layerValues.length - 1) ? '' : ', '}} 67 </ng-container> 68 </ng-container> 69 </span> 70 </div> 71 </div> 72 73 <mat-divider></mat-divider> 74 75 <div class="group geometry"> 76 <h3 class="group-header mat-subheading-2">Geometry</h3> 77 <div class="left-column"> 78 <p class="column-header mat-small">Calculated</p> 79 <p class="property mat-body-1">Transform:</p> 80 <transform-matrix 81 *ngIf="properties.calcTransform?.getAllChildren().length > 0" 82 [matTooltip]="getTransformType(properties.calcTransform)" 83 [matrix]="getTransformMatrix(properties.calcTransform)"></transform-matrix> 84 <p class="mat-body-2 crop"> 85 <span 86 class="mat-body-1" 87 matTooltip="Raw value read from proto.bounds. This is the buffer size or 88 requested crop cropped by parent bounds." 89 >Crop:</span 90 > 91 &ngsp; 92 {{ properties.calcCrop }} 93 </p> 94 95 <p class="mat-body-2 final-bounds"> 96 <span 97 class="mat-body-1" 98 matTooltip="Raw value read from proto.screenBounds. This is the calculated crop 99 transformed." 100 >Final Bounds:</span 101 > 102 &ngsp; 103 {{ properties.finalBounds }} 104 </p> 105 </div> 106 <div class="right-column"> 107 <p class="column-header mat-small">Requested</p> 108 <p class="property mat-body-1">Transform:</p> 109 <transform-matrix 110 *ngIf="properties.reqTransform?.getAllChildren().length > 0" 111 [matTooltip]="getTransformType(properties.reqTransform)" 112 [matrix]="getTransformMatrix(properties.reqTransform)"></transform-matrix> 113 <p class="mat-body-2 crop"> 114 <span class="mat-body-1">Crop:</span> 115 &ngsp; 116 {{ properties.reqCrop }} 117 </p> 118 </div> 119 </div> 120 121 <mat-divider></mat-divider> 122 123 <div class="group buffer"> 124 <h3 class="group-header mat-subheading-2">Buffer</h3> 125 <div class="left-column"> 126 <p class="mat-body-2 size"> 127 <span class="mat-body-1">Size:</span> 128 &ngsp; 129 {{ properties.bufferSize }} 130 </p> 131 <p class="mat-body-2 frame-number"> 132 <span class="mat-body-1">Frame Number:</span> 133 &ngsp; 134 {{ properties.frameNumber }} 135 </p> 136 <p class="mat-body-2 transform"> 137 <span 138 class="mat-body-1" 139 matTooltip="Rotates or flips the buffer in place. Used with display transform 140 hint to cancel out any buffer transformation when sending to 141 HWC." 142 >Transform:</span 143 > 144 &ngsp; 145 {{ properties.bufferTransformType }} 146 </p> 147 </div> 148 <div class="right-column"> 149 <p class="mat-body-2 dest-frame"> 150 <span 151 class="mat-body-1" 152 matTooltip="Scales buffer to the frame by overriding the requested transform 153 for this item." 154 >Destination Frame:</span 155 > 156 &ngsp; 157 {{ properties.destinationFrame }} 158 </p> 159 <p *ngIf="properties.ignoreDestinationFrame" class="mat-body-2 ignore-frame"> 160 Destination Frame ignored because item has eIgnoreDestinationFrame flag set. 161 </p> 162 </div> 163 </div> 164 165 <mat-divider></mat-divider> 166 167 <div class="group hierarchy-info"> 168 <h3 class="group-header mat-subheading-2">Hierarchy</h3> 169 <div class="left-column"> 170 <p class="mat-body-2 z-order"> 171 <span class="mat-body-1">z-order:</span> 172 &ngsp; 173 {{ properties.z }} 174 </p> 175 <p class="mat-body-2 rel-parent inline"> 176 <span 177 class="mat-body-1" 178 matTooltip="item is z-ordered relative to its relative parents but its bounds 179 and other properties are inherited from its parents." 180 >relative parent:</span> 181 &ngsp; 182 <ng-container *ngIf="!properties.relativeParent.nodeId"> 183 {{ properties.relativeParent }} 184 </ng-container> 185 <ng-container *ngIf="properties.relativeParent.nodeId"> 186 <button 187 mat-button 188 color="primary" 189 [matTooltip]="properties.relativeParent.name" 190 (click)="onIdClicked(properties.relativeParent.nodeId)"> 191 {{ properties.relativeParent.layerId }} 192 </button> 193 </ng-container> 194 </p> 195 <span class="mat-body-2 rel-children inline"> 196 <span class="mat-body-1">relative children:</span> 197 &ngsp; 198 <ng-container *ngIf="properties.relativeChildren.length === 0"> 199 none 200 </ng-container> 201 <ng-container *ngFor="let layer of properties.relativeChildren; index as i"> 202 <button 203 mat-button 204 color="primary" 205 [matTooltip]="layer.name" 206 (click)="onIdClicked(layer.nodeId)"> 207 {{ layer.layerId }} 208 </button> 209 {{(i === properties.relativeChildren.length - 1) ? '' : ', '}} 210 </ng-container> 211 </span> 212 </div> 213 </div> 214 215 <mat-divider></mat-divider> 216 217 <div class="group effects"> 218 <h3 class="group-header mat-subheading-2">Effects</h3> 219 <div class="left-column"> 220 <p class="column-header mat-small">Calculated</p> 221 <p class="mat-body-2 color"> 222 <span class="mat-body-1">Color:</span> 223 &ngsp; 224 {{ properties.calcColor }} 225 </p> 226 <p class="mat-body-2 corner-radius"> 227 <span class="mat-body-1">Corner Radius:</span> 228 &ngsp; 229 {{ properties.calcCornerRadius }} 230 </p> 231 <p class="mat-body-2 shadow"> 232 <span class="mat-body-1">Shadow:</span> 233 &ngsp; 234 {{ properties.calcShadowRadius }} 235 </p> 236 <p class="mat-body-2"> 237 <span 238 class="mat-body-1" 239 matTooltip="Crop used to define the bounds of the corner radii. If the bounds 240 are greater than the item bounds then the rounded corner will not 241 be visible." 242 >Corner Radius Crop:</span 243 > 244 &ngsp; 245 {{ properties.calcCornerRadiusCrop }} 246 </p> 247 <p class="mat-body-2 blur"> 248 <span class="mat-body-1">Blur:</span> 249 &ngsp; 250 {{ properties.backgroundBlurRadius }} 251 </p> 252 </div> 253 <div class="right-column"> 254 <p class="column-header mat-small">Requested</p> 255 <p class="mat-body-2"> 256 <span class="mat-body-1">Color:</span> 257 &ngsp; 258 {{ properties.reqColor }} 259 </p> 260 <p class="mat-body-2 corner-radius"> 261 <span class="mat-body-1">Corner Radius:</span> 262 &ngsp; 263 {{ properties.reqCornerRadius }} 264 </p> 265 </div> 266 </div> 267 268 <mat-divider></mat-divider> 269 270 <div class="group inputs"> 271 <h3 class="group-header mat-subheading-2">Input</h3> 272 <ng-container *ngIf="properties.hasInputChannel"> 273 <div class="left-column"> 274 <p class="property mat-body-1">To Display Transform:</p> 275 <transform-matrix 276 *ngIf="properties.inputTransform?.getAllChildren().length > 0" 277 [matTooltip]="getTransformType(properties.inputTransform)" 278 [matrix]="getTransformMatrix(properties.inputTransform)"></transform-matrix> 279 <p class="mat-body-2"> 280 <span class="mat-body-1">Touchable Region:</span> 281 &ngsp; 282 {{ properties.inputRegion }} 283 </p> 284 </div> 285 <div class="right-column"> 286 <p class="column-header mat-small">Config</p> 287 <p class="mat-body-2 focusable"> 288 <span class="mat-body-1">Focusable:</span> 289 &ngsp; 290 {{ properties.focusable }} 291 </p> 292 <p class="mat-body-2 crop-touch-region"> 293 <span class="mat-body-1">Crop touch region with item:</span> 294 &ngsp; 295 {{ properties.cropTouchRegionWithItem }} 296 </p> 297 <p class="mat-body-2 replace-touch-region"> 298 <span class="mat-body-1">Replace touch region with crop:</span> 299 &ngsp; 300 {{ properties.replaceTouchRegionWithCrop }} 301 </p> 302 <p class="mat-body-2 input-config"> 303 <span class="mat-body-1">Input Config:</span> 304 &ngsp; 305 {{ properties.inputConfig }} 306 </p> 307 </div> 308 </ng-container> 309 <div *ngIf="!properties.hasInputChannel" class="left-column"> 310 <p class="mat-body-2"> 311 <span class="mat-body-1">Input channel:</span> 312 &ngsp; not set 313 </p> 314 </div> 315 </div> 316 </div> 317 `, 318 styles: [ 319 ` 320 :host collapsible-section-title { 321 padding-bottom: 8px; 322 } 323 .placeholder-text { 324 padding: 8px 12px; 325 } 326 327 .property-groups-content { 328 overflow-y: auto; 329 padding: 0px 12px; 330 } 331 332 .group { 333 display: flex; 334 flex-direction: row; 335 padding: 8px; 336 } 337 338 .group-header { 339 width: 80px; 340 color: gray; 341 } 342 343 .left-column { 344 flex: 1; 345 padding: 0 5px; 346 } 347 348 .right-column { 349 flex: 1; 350 border: 1px solid var(--border-color); 351 border-left-width: 5px; 352 padding: 0 5px; 353 } 354 355 .column-header { 356 color: gray; 357 } 358 359 .summary { 360 display: block; 361 } 362 `, 363 inlineButtonStyle, 364 viewerCardInnerStyle, 365 ], 366}) 367export class SurfaceFlingerPropertyGroupsComponent { 368 @Input() properties: SfCuratedProperties | undefined; 369 370 @Output() collapseButtonClicked = new EventEmitter(); 371 372 constructor(@Inject(ElementRef) private elementRef: ElementRef) {} 373 374 getTransformType(transformNode: UiPropertyTreeNode): string { 375 const typeFlags = transformNode.formattedValue(); 376 return typeFlags !== 'null' ? typeFlags : 'IDENTITY'; 377 } 378 379 getTransformMatrix(transformNode: UiPropertyTreeNode): UiPropertyTreeNode { 380 return assertDefined(transformNode.getChildByName('matrix')); 381 } 382 383 onIdClicked(layerNodeId: string) { 384 const event = new CustomEvent(ViewerEvents.HighlightedIdChange, { 385 bubbles: true, 386 detail: {id: layerNodeId}, 387 }); 388 this.elementRef.nativeElement.dispatchEvent(event); 389 } 390} 391