1/* 2 * Copyright (C) 2022 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 {Component, Input} from '@angular/core'; 17import {Layer} from 'trace/flickerlib/common'; 18 19@Component({ 20 selector: 'property-groups', 21 template: ` 22 <div class="group"> 23 <h3 class="group-header mat-subheading-2">Visibility</h3> 24 <div class="left-column"> 25 <p class="mat-body-1 flags"> 26 <span class="mat-body-2">Flags:</span> 27 &ngsp; 28 {{ item.verboseFlags ? item.verboseFlags : item.flags }} 29 </p> 30 <p *ngFor="let reason of summary()" class="mat-body-1"> 31 <span class="mat-body-2">{{ reason.key }}:</span> 32 &ngsp; 33 {{ reason.value }} 34 </p> 35 </div> 36 </div> 37 <mat-divider></mat-divider> 38 <div class="group"> 39 <h3 class="group-header mat-subheading-2">Geometry</h3> 40 <div class="left-column"> 41 <p class="column-header mat-small">Calculated</p> 42 <p class="property mat-body-2">Transform:</p> 43 <transform-matrix 44 [transform]="item.transform" 45 [formatFloat]="formatFloat"></transform-matrix> 46 <p class="mat-body-1"> 47 <span 48 class="mat-body-2" 49 matTooltip="Raw value read from proto.bounds. This is the buffer size or 50 requested crop cropped by parent bounds." 51 >Crop:</span 52 > 53 &ngsp; 54 {{ item.bounds }} 55 </p> 56 57 <p class="mat-body-1"> 58 <span 59 class="mat-body-2" 60 matTooltip="Raw value read from proto.screenBounds. This is the calculated crop 61 transformed." 62 >Final Bounds:</span 63 > 64 &ngsp; 65 {{ item.screenBounds }} 66 </p> 67 </div> 68 <div class="right-column"> 69 <p class="column-header mat-small">Requested</p> 70 <p class="property mat-body-2">Transform:</p> 71 <transform-matrix 72 [transform]="item.requestedTransform" 73 [formatFloat]="formatFloat"></transform-matrix> 74 <p class="mat-body-1"> 75 <span class="mat-body-2">Crop:</span> 76 &ngsp; 77 {{ item.crop ? item.crop : '[empty]' }} 78 </p> 79 </div> 80 </div> 81 <mat-divider></mat-divider> 82 <div class="group"> 83 <h3 class="group-header mat-subheading-2">Buffer</h3> 84 <div class="left-column"> 85 <p class="mat-body-1"> 86 <span class="mat-body-2">Size:</span> 87 &ngsp; 88 {{ item.activeBuffer }} 89 </p> 90 <p class="mat-body-1"> 91 <span class="mat-body-2">Frame Number:</span> 92 &ngsp; 93 {{ item.currFrame }} 94 </p> 95 <p class="mat-body-1"> 96 <span 97 class="mat-body-2" 98 matTooltip="Rotates or flips the buffer in place. Used with display transform 99 hint to cancel out any buffer transformation when sending to 100 HWC." 101 >Transform:</span 102 > 103 &ngsp; 104 {{ item.bufferTransform }} 105 </p> 106 </div> 107 <div class="right-column"> 108 <p class="mat-body-1"> 109 <span 110 class="mat-body-2" 111 matTooltip="Scales buffer to the frame by overriding the requested transform 112 for this item." 113 >Destination Frame:</span 114 > 115 &ngsp; 116 {{ getDestinationFrame() }} 117 </p> 118 <p *ngIf="hasIgnoreDestinationFrame()" class="mat-body-1"> 119 Destination Frame ignored because item has eIgnoreDestinationFrame flag set. 120 </p> 121 </div> 122 </div> 123 <mat-divider></mat-divider> 124 <div class="group"> 125 <h3 class="group-header mat-subheading-2">Hierarchy</h3> 126 <div class="left-column"> 127 <p class="mat-body-1"> 128 <span class="mat-body-2">z-order:</span> 129 &ngsp; 130 {{ item.z }} 131 </p> 132 <p class="mat-body-1"> 133 <span 134 class="mat-body-2" 135 matTooltip="item is z-ordered relative to its relative parents but its bounds 136 and other properties are inherited from its parents." 137 >relative parent:</span 138 > 139 &ngsp; 140 {{ item.zOrderRelativeOfId == -1 ? 'none' : item.zOrderRelativeOfId }} 141 </p> 142 </div> 143 </div> 144 <mat-divider></mat-divider> 145 <div class="group"> 146 <h3 class="group-header mat-subheading-2">Effects</h3> 147 <div class="left-column"> 148 <p class="column-header mat-small">Calculated</p> 149 <p class="mat-body-1"> 150 <span class="mat-body-2">Color:</span> 151 &ngsp; 152 {{ item.color }} 153 </p> 154 <p class="mat-body-1"> 155 <span class="mat-body-2">Shadow:</span> 156 &ngsp; 157 {{ item.shadowRadius }} px 158 </p> 159 <p class="mat-body-1"> 160 <span class="mat-body-2">Corner Radius:</span> 161 &ngsp; 162 {{ formatFloat(item.cornerRadius) }} px 163 </p> 164 <p class="mat-body-1"> 165 <span 166 class="mat-body-2" 167 matTooltip="Crop used to define the bounds of the corner radii. If the bounds 168 are greater than the item bounds then the rounded corner will not 169 be visible." 170 >Corner Radius Crop:</span 171 > 172 &ngsp; 173 {{ item.cornerRadiusCrop }} 174 </p> 175 <p class="mat-body-1"> 176 <span class="mat-body-2">Blur:</span> 177 &ngsp; 178 {{ item.proto?.backgroundBlurRadius ? item.proto?.backgroundBlurRadius : 0 }} px 179 </p> 180 </div> 181 <div class="right-column"> 182 <p class="column-header mat-small">Requested</p> 183 <p class="mat-body-1"> 184 <span class="mat-body-2">Color:</span> 185 &ngsp; 186 {{ item.requestedColor }} 187 </p> 188 <p class="mat-body-1"> 189 <span class="mat-body-2">Shadow:</span> 190 &ngsp; 191 {{ item.proto?.requestedShadowRadius ? item.proto?.requestedShadowRadius : 0 }} px 192 </p> 193 <p class="mat-body-1"> 194 <span class="mat-body-2">Corner Radius:</span> 195 &ngsp; 196 {{ 197 item.proto?.requestedCornerRadius ? formatFloat(item.proto?.requestedCornerRadius) : 0 198 }} 199 px 200 </p> 201 </div> 202 </div> 203 <mat-divider></mat-divider> 204 <div class="group"> 205 <h3 class="group-header mat-subheading-2">Input</h3> 206 <ng-container *ngIf="hasInputChannel()"> 207 <div class="left-column"> 208 <p class="property mat-body-2">To Display Transform:</p> 209 <transform-matrix 210 [transform]="item.inputTransform" 211 [formatFloat]="formatFloat"></transform-matrix> 212 <p class="mat-body-1"> 213 <span class="mat-body-2">Touchable Region:</span> 214 &ngsp; 215 {{ item.inputRegion }} 216 </p> 217 </div> 218 <div class="right-column"> 219 <p class="column-header mat-small">Config</p> 220 <p class="mat-body-1"> 221 <span class="mat-body-2">Focusable:</span> 222 &ngsp; 223 {{ item.proto?.inputWindowInfo.focusable }} 224 </p> 225 <p class="mat-body-1"> 226 <span class="mat-body-2">Crop touch region with item:</span> 227 &ngsp; 228 {{ 229 item.proto?.inputWindowInfo.cropLayerId <= 0 230 ? "none" 231 : item.proto?.inputWindowInfo.cropLayerId 232 }} 233 </p> 234 <p class="mat-body-1"> 235 <span class="mat-body-2">Replace touch region with crop:</span> 236 &ngsp; 237 {{ item.proto?.inputWindowInfo.replaceTouchableRegionWithCrop }} 238 </p> 239 </div> 240 </ng-container> 241 <div *ngIf="!hasInputChannel()" class="left-column"> 242 <p class="mat-body-1"> 243 <span class="mat-body-2">Input channel:</span> 244 &ngsp; not set 245 </p> 246 </div> 247 </div> 248 `, 249 styles: [ 250 ` 251 .group { 252 display: flex; 253 flex-direction: row; 254 padding: 8px; 255 } 256 257 .group-header { 258 width: 80px; 259 color: gray; 260 } 261 262 .left-column { 263 flex: 1; 264 padding: 0 5px; 265 } 266 267 .right-column { 268 flex: 1; 269 border: 1px solid var(--border-color); 270 border-left-width: 5px; 271 padding: 0 5px; 272 } 273 274 .column-header { 275 color: gray; 276 } 277 `, 278 ], 279}) 280export class PropertyGroupsComponent { 281 @Input() item!: Layer; 282 283 hasInputChannel() { 284 return this.item.proto?.inputWindowInfo; 285 } 286 287 getDestinationFrame() { 288 const frame = this.item.proto?.destinationFrame; 289 if (frame) { 290 return ` left: ${frame.left}, top: ${frame.top}, right: ${frame.right}, bottom: ${frame.bottom}`; 291 } else return ''; 292 } 293 294 hasIgnoreDestinationFrame() { 295 return (this.item.flags & 0x400) === 0x400; 296 } 297 298 formatFloat(num: number) { 299 return Math.round(num * 100) / 100; 300 } 301 302 summary(): TreeSummary { 303 const summary = []; 304 305 if (this.item?.visibilityReason?.length > 0) { 306 let reason = ''; 307 if (Array.isArray(this.item.visibilityReason)) { 308 reason = this.item.visibilityReason.join(', '); 309 } else { 310 reason = this.item.visibilityReason; 311 } 312 313 summary.push({key: 'Invisible due to', value: reason}); 314 } 315 316 if (this.item?.occludedBy?.length > 0) { 317 summary.push({ 318 key: 'Occluded by', 319 value: this.item.occludedBy.map((it: any) => it.id).join(', '), 320 }); 321 } 322 323 if (this.item?.partiallyOccludedBy?.length > 0) { 324 summary.push({ 325 key: 'Partially occluded by', 326 value: this.item.partiallyOccludedBy.map((it: any) => it.id).join(', '), 327 }); 328 } 329 330 if (this.item?.coveredBy?.length > 0) { 331 summary.push({ 332 key: 'Covered by', 333 value: this.item.coveredBy.map((it: any) => it.id).join(', '), 334 }); 335 } 336 337 return summary; 338 } 339} 340 341type TreeSummary = Array<{key: string; value: string}>; 342