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 { 17 Component, 18 ElementRef, 19 EventEmitter, 20 Inject, 21 Input, 22 Output, 23} from '@angular/core'; 24import {EMPTY_OBJ_STRING} from 'trace/tree_node/formatters'; 25import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node'; 26import {PropertyTreeNode} from 'trace/tree_node/property_tree_node'; 27import {TreeNode} from 'trace/tree_node/tree_node'; 28import {ImeAdditionalProperties} from 'viewers/common/ime_additional_properties'; 29import { 30 ImeContainerProperties, 31 InputMethodSurfaceProperties, 32} from 'viewers/common/ime_utils'; 33import {ViewerEvents} from 'viewers/common/viewer_events'; 34import {selectedElementStyle} from './styles/selected_element.styles'; 35import {viewerCardInnerStyle} from './styles/viewer_card.styles'; 36 37@Component({ 38 selector: 'ime-additional-properties', 39 template: ` 40 <div class="title-section"> 41 <collapsible-section-title 42 class="view-header" 43 title="WM & SF PROPERTIES" 44 (collapseButtonClicked)="collapseButtonClicked.emit()"></collapsible-section-title> 45 </div> 46 <div class="additional-properties-content" *ngIf="additionalProperties"> 47 <div *ngIf="isAllPropertiesUndefined()" class="group"> 48 <p class="mat-body-1"> 49 There is no corresponding WM / SF additionalProperties for this IME entry – no WM / SF 50 entry is recorded before this IME entry in time. View later frames for WM & SF properties. 51 </p> 52 </div> 53 54 <ng-container *ngIf="isImeManagerService"> 55 <div class="group ime-manager-service"> 56 <button 57 *ngIf="wmHierarchyTree()" 58 [color]="getButtonColor(wmHierarchyTree())" 59 mat-button 60 class="group-header" 61 [class]="{selected: isHighlighted(wmHierarchyTree())}" 62 (click)="onClickShowInPropertiesPanelWm(wmHierarchyTree(), 'Window Manager State')"> 63 WMState 64 </button> 65 <h3 *ngIf="!wmHierarchyTree()" class="group-header mat-subheading-2">WMState</h3> 66 <div class="left-column wm-state"> 67 <p *ngIf="additionalProperties?.wm" class="mat-body-1"> 68 {{ wmRootLabel() }} 69 </p> 70 <p *ngIf="!additionalProperties?.wm" class="mat-body-1"> 71 There is no corresponding WMState entry. 72 </p> 73 </div> 74 </div> 75 <div *ngIf="wmInsetsSourceProvider()" class="group insets-source-provider"> 76 <button 77 [color]="getButtonColor(wmInsetsSourceProvider())" 78 mat-button 79 class="group-header" 80 [class]="{selected: isHighlighted(wmInsetsSourceProvider())}" 81 (click)=" 82 onClickShowInPropertiesPanelWm(wmInsetsSourceProvider(), 'Ime Insets Source Provider') 83 "> 84 IME Insets Source Provider 85 </button> 86 <div class="left-column"> 87 <p class="mat-body-2">Source Frame:</p> 88 <coordinates-table 89 [coordinates]="wmInsetsSourceProviderSourceFrame()"></coordinates-table> 90 <p class="mat-body-1"> 91 <span class="mat-body-2">Source Visible:</span> 92 &ngsp; 93 {{ wmInsetsSourceProviderSourceVisible() }} 94 </p> 95 <p class="mat-body-2">Source Visible Frame:</p> 96 <coordinates-table 97 [coordinates]="wmInsetsSourceProviderSourceVisibleFrame()"></coordinates-table> 98 <p class="mat-body-1"> 99 <span class="mat-body-2">Position:</span> 100 &ngsp; 101 {{ wmInsetsSourceProviderPosition() }} 102 </p> 103 <p class="mat-body-1"> 104 <span class="mat-body-2">IsLeashReadyForDispatching:</span> 105 &ngsp; 106 {{ wmInsetsSourceProviderIsLeashReady() }} 107 </p> 108 <p class="mat-body-1"> 109 <span class="mat-body-2">Controllable:</span> 110 &ngsp; 111 {{ wmInsetsSourceProviderControllable() }} 112 </p> 113 </div> 114 </div> 115 <div *ngIf="wmImeControlTarget()" class="group ime-control-target"> 116 <button 117 [color]="getButtonColor(wmImeControlTarget())" 118 mat-button 119 class="group-header ime-control-target-button" 120 [class]="{selected: isHighlighted(wmImeControlTarget())}" 121 (click)="onClickShowInPropertiesPanelWm(wmImeControlTarget(), 'Ime Control Target')"> 122 IME Control Target 123 </button> 124 <div class="left-column"> 125 <p *ngIf="wmImeControlTargetTitle()" class="mat-body-1"> 126 <span class="mat-body-2">Title:</span> 127 &ngsp; 128 {{ wmImeControlTargetTitle() }} 129 </p> 130 </div> 131 </div> 132 <div *ngIf="wmImeInputTarget()" class="group ime-input-target"> 133 <button 134 [color]="getButtonColor(wmImeInputTarget())" 135 mat-button 136 class="group-header" 137 [class]="{selected: isHighlighted(wmImeInputTarget())}" 138 (click)="onClickShowInPropertiesPanelWm(wmImeInputTarget(), 'Ime Input Target')"> 139 IME Input Target 140 </button> 141 <div class="left-column"> 142 <p *ngIf="wmImeInputTargetTitle()" class="mat-body-1"> 143 <span class="mat-body-2">Title:</span> 144 &ngsp; 145 {{ wmImeInputTargetTitle() }} 146 </p> 147 </div> 148 </div> 149 <div *ngIf="wmImeLayeringTarget()" class="group ime-layering-target"> 150 <button 151 [color]="getButtonColor(wmImeLayeringTarget())" 152 mat-button 153 class="group-header" 154 [class]="{selected: isHighlighted(wmImeLayeringTarget())}" 155 (click)="onClickShowInPropertiesPanelWm(wmImeLayeringTarget(), 'Ime Layering Target')"> 156 IME Layering Target 157 </button> 158 <div class="left-column"> 159 <p *ngIf="wmImeLayeringTargetTitle()" class="mat-body-1"> 160 <span class="mat-body-2">Title:</span> 161 &ngsp; 162 {{ wmImeLayeringTargetTitle() }} 163 </p> 164 </div> 165 </div> 166 </ng-container> 167 168 <ng-container *ngIf="!isImeManagerService"> 169 <!-- Ime Client or Ime Service --> 170 <div class="group"> 171 <button 172 *ngIf="wmHierarchyTree()" 173 [color]="getButtonColor(wmHierarchyTree())" 174 mat-button 175 class="group-header wm-state-button" 176 [class]="{selected: isHighlighted(wmHierarchyTree())}" 177 (click)="onClickShowInPropertiesPanelWm(wmHierarchyTree(), 'Window Manager State')"> 178 WMState 179 </button> 180 <h3 *ngIf="!wmHierarchyTree()" class="group-header mat-subheading-2">WMState</h3> 181 <div class="left-column wm-state"> 182 <p *ngIf="additionalProperties?.wm" class="mat-body-1"> 183 {{ wmRootLabel() }} 184 </p> 185 <p *ngIf="!additionalProperties?.wm" class="mat-body-1"> 186 There is no corresponding WMState entry. 187 </p> 188 </div> 189 </div> 190 <div class="group"> 191 <h3 class="group-header mat-subheading-2">SFLayer</h3> 192 <div class="left-column sf-state"> 193 <p *ngIf="additionalProperties?.sf" class="mat-body-1"> 194 {{ sfRootLabel() }} 195 </p> 196 <p *ngIf="!additionalProperties?.sf" class="mat-body-1"> 197 There is no corresponding SFLayer entry. 198 </p> 199 </div> 200 </div> 201 <div *ngIf="additionalProperties?.wm" class="group focus"> 202 <h3 class="group-header mat-subheading-2">Focus</h3> 203 <div class="left-column"> 204 <p class="mat-body-1"> 205 <span class="mat-body-2">Focused App:</span> 206 &ngsp; 207 {{ additionalProperties.wm.wmStateProperties.focusedApp }} 208 </p> 209 <p class="mat-body-1"> 210 <span class="mat-body-2">Focused Activity:</span> 211 &ngsp; 212 {{ additionalProperties.wm.wmStateProperties.focusedActivity }} 213 </p> 214 <p class="mat-body-1"> 215 <span class="mat-body-2">Focused Window:</span> 216 &ngsp; 217 {{ additionalProperties.wm.wmStateProperties.focusedWindow ?? 'null' }} 218 </p> 219 <p *ngIf="additionalProperties.sf" class="mat-body-1"> 220 <span class="mat-body-2">Focused Window Color:</span> 221 &ngsp; 222 {{ formattedWindowColor() }} 223 </p> 224 <p class="mat-body-2">Input Control Target Frame:</p> 225 <coordinates-table [coordinates]="wmControlTargetFrame()"></coordinates-table> 226 </div> 227 </div> 228 <div class="group visibility"> 229 <h3 class="group-header mat-subheading-2">Visibility</h3> 230 <div class="left-column"> 231 <p *ngIf="additionalProperties?.wm" class="mat-body-1"> 232 <span class="mat-body-2">InputMethod Window:</span> 233 &ngsp; 234 {{ additionalProperties.wm.wmStateProperties.isInputMethodWindowVisible }} 235 </p> 236 <p *ngIf="additionalProperties?.sf" class="mat-body-1"> 237 <span class="mat-body-2">InputMethod Surface:</span> 238 &ngsp; 239 {{ additionalProperties.sf.properties.inputMethodSurface?.isVisible ?? false }} 240 </p> 241 </div> 242 </div> 243 <div *ngIf="additionalProperties?.sf" class="group ime-container"> 244 <button 245 [color]="getButtonColor(additionalProperties.sf.properties.imeContainer)" 246 mat-button 247 class="group-header ime-container-button" 248 [class]="{selected: isHighlighted(additionalProperties.sf.properties.imeContainer)}" 249 (click)=" 250 onClickShowInPropertiesPanelSf(additionalProperties.sf.properties.imeContainer) 251 "> 252 Ime Container 253 </button> 254 <div class="left-column"> 255 <p class="mat-body-1"> 256 <span class="mat-body-2">ZOrderRelativeOfId:</span> 257 &ngsp; 258 {{ additionalProperties.sf.properties.imeContainer.zOrderRelativeOfId }} 259 </p> 260 <p class="mat-body-1"> 261 <span class="mat-body-2">Z:</span> 262 &ngsp; 263 {{ additionalProperties.sf.properties.imeContainer.z }} 264 </p> 265 </div> 266 </div> 267 <div *ngIf="additionalProperties?.sf" class="group input-method-surface"> 268 <button 269 [color]="getButtonColor(additionalProperties.sf.properties.inputMethodSurface)" 270 mat-button 271 class="group-header input-method-surface-button" 272 [class]="{ 273 selected: isHighlighted(additionalProperties.sf.properties.inputMethodSurface) 274 }" 275 (click)=" 276 onClickShowInPropertiesPanelSf(additionalProperties.sf.properties.inputMethodSurface) 277 "> 278 Input Method Surface 279 </button> 280 <div class="left-column"> 281 <p class="mat-body-2">Screen Bounds:</p> 282 <coordinates-table [coordinates]="sfImeContainerScreenBounds()"></coordinates-table> 283 </div> 284 <div class="right-column"> 285 <p class="mat-body-2">Rect:</p> 286 <coordinates-table [coordinates]="sfImeContainerRect()"></coordinates-table> 287 </div> 288 </div> 289 </ng-container> 290 </div> 291 `, 292 styles: [ 293 ` 294 :host collapsible-section-title { 295 padding-bottom: 8px; 296 } 297 298 .additional-properties-content { 299 height: 0; 300 flex-grow: 1; 301 overflow-y: auto; 302 } 303 304 .group { 305 padding: 8px; 306 display: flex; 307 flex-direction: row; 308 border-bottom: 1px solid var(--border-color); 309 } 310 311 .mat-body-1 { 312 overflow-wrap: anywhere; 313 } 314 315 .group-header { 316 height: 100%; 317 width: 80px; 318 padding: 0; 319 text-align: center; 320 line-height: normal; 321 white-space: normal; 322 } 323 324 p.group-header { 325 color: gray; 326 } 327 328 .left-column { 329 flex: 1; 330 padding: 0 5px; 331 } 332 333 .right-column { 334 flex: 1; 335 padding: 0 5px; 336 } 337 `, 338 selectedElementStyle, 339 viewerCardInnerStyle, 340 ], 341}) 342export class ImeAdditionalPropertiesComponent { 343 @Input() additionalProperties: ImeAdditionalProperties | undefined; 344 @Input() isImeManagerService: boolean | undefined; 345 @Input() highlightedItem: string = ''; 346 347 @Output() collapseButtonClicked = new EventEmitter(); 348 349 constructor(@Inject(ElementRef) private elementRef: ElementRef) {} 350 351 isHighlighted( 352 item: 353 | TreeNode 354 | ImeContainerProperties 355 | InputMethodSurfaceProperties 356 | undefined, 357 ): boolean { 358 return item ? item.id === this.highlightedItem : false; 359 } 360 361 getButtonColor(node: TreeNode | undefined) { 362 return this.isHighlighted(node) ? undefined : 'primary'; 363 } 364 365 formattedWindowColor(): string { 366 const color = this.additionalProperties?.sf?.properties.focusedWindowColor; 367 if (!color) return EMPTY_OBJ_STRING; 368 return color.formattedValue(); 369 } 370 371 sfRootLabel(): string { 372 const rootProps = this.additionalProperties?.sf?.properties.root; 373 if (!rootProps) { 374 return this.additionalProperties?.sf?.name ?? 'root'; 375 } 376 377 return rootProps.timestamp; 378 } 379 380 wmRootLabel(): string { 381 const timestamp = 382 this.additionalProperties?.wm?.wmStateProperties.timestamp; 383 if (!timestamp) { 384 return this.additionalProperties?.wm?.name ?? 'root'; 385 } 386 return timestamp; 387 } 388 389 wmHierarchyTree(): HierarchyTreeNode | undefined { 390 return this.additionalProperties?.wm?.hierarchyTree; 391 } 392 393 wmInsetsSourceProvider(): PropertyTreeNode | undefined { 394 return this.additionalProperties?.wm?.wmStateProperties 395 .imeInsetsSourceProvider; 396 } 397 398 wmControlTargetFrame(): PropertyTreeNode | undefined { 399 return this.additionalProperties?.wm?.wmStateProperties.imeInsetsSourceProvider 400 ?.getChildByName('insetsSourceProvider') 401 ?.getChildByName('controlTarget') 402 ?.getChildByName('windowFrames') 403 ?.getChildByName('frame'); 404 } 405 406 wmInsetsSourceProviderPosition(): string { 407 return ( 408 this.additionalProperties?.wm?.wmStateProperties.imeInsetsSourceProvider 409 ?.getChildByName('insetsSourceProvider') 410 ?.getChildByName('control') 411 ?.getChildByName('position') 412 ?.formattedValue() ?? 'null' 413 ); 414 } 415 416 wmInsetsSourceProviderIsLeashReady(): string { 417 return ( 418 this.additionalProperties?.wm?.wmStateProperties.imeInsetsSourceProvider 419 ?.getChildByName('insetsSourceProvider') 420 ?.getChildByName('isLeashReadyForDispatching') 421 ?.formattedValue() ?? 'null' 422 ); 423 } 424 425 wmInsetsSourceProviderControllable(): string { 426 return ( 427 this.additionalProperties?.wm?.wmStateProperties.imeInsetsSourceProvider 428 ?.getChildByName('insetsSourceProvider') 429 ?.getChildByName('controllable') 430 ?.formattedValue() ?? 'null' 431 ); 432 } 433 434 wmInsetsSourceProviderSourceFrame(): PropertyTreeNode | undefined { 435 return this.additionalProperties?.wm?.wmStateProperties.imeInsetsSourceProvider 436 ?.getChildByName('source') 437 ?.getChildByName('frame'); 438 } 439 440 wmInsetsSourceProviderSourceVisible(): string { 441 return ( 442 this.additionalProperties?.wm?.wmStateProperties.imeInsetsSourceProvider 443 ?.getChildByName('source') 444 ?.getChildByName('visible') 445 ?.formattedValue() ?? 'null' 446 ); 447 } 448 449 wmInsetsSourceProviderSourceVisibleFrame(): PropertyTreeNode | undefined { 450 return this.additionalProperties?.wm?.wmStateProperties.imeInsetsSourceProvider 451 ?.getChildByName('source') 452 ?.getChildByName('visibleFrame'); 453 } 454 455 wmImeControlTarget(): PropertyTreeNode | undefined { 456 return this.additionalProperties?.wm?.wmStateProperties.imeControlTarget; 457 } 458 459 wmImeControlTargetTitle(): string | undefined { 460 return ( 461 this.additionalProperties?.wm?.wmStateProperties.imeControlTarget 462 ?.getChildByName('windowContainer') 463 ?.getChildByName('identifier') 464 ?.getChildByName('title') 465 ?.formattedValue() ?? undefined 466 ); 467 } 468 469 wmImeInputTarget(): PropertyTreeNode | undefined { 470 return this.additionalProperties?.wm?.wmStateProperties.imeInputTarget; 471 } 472 473 wmImeInputTargetTitle(): string | undefined { 474 return ( 475 this.additionalProperties?.wm?.wmStateProperties.imeInputTarget 476 ?.getChildByName('windowContainer') 477 ?.getChildByName('identifier') 478 ?.getChildByName('title') 479 ?.formattedValue() ?? undefined 480 ); 481 } 482 483 wmImeLayeringTarget(): PropertyTreeNode | undefined { 484 return this.additionalProperties?.wm?.wmStateProperties.imeLayeringTarget; 485 } 486 487 wmImeLayeringTargetTitle(): string | undefined { 488 return ( 489 this.additionalProperties?.wm?.wmStateProperties.imeLayeringTarget 490 ?.getChildByName('windowContainer') 491 ?.getChildByName('identifier') 492 ?.getChildByName('title') 493 ?.formattedValue() ?? undefined 494 ); 495 } 496 497 sfImeContainerScreenBounds(): PropertyTreeNode | undefined { 498 return ( 499 this.additionalProperties?.sf?.properties.inputMethodSurface 500 ?.screenBounds ?? undefined 501 ); 502 } 503 504 sfImeContainerRect(): PropertyTreeNode | undefined { 505 return ( 506 this.additionalProperties?.sf?.properties.inputMethodSurface?.rect ?? 507 undefined 508 ); 509 } 510 511 isAllPropertiesUndefined(): boolean { 512 if (this.isImeManagerService) { 513 return !this.additionalProperties?.wm; 514 } else { 515 return !(this.additionalProperties?.wm || this.additionalProperties?.sf); 516 } 517 } 518 519 onClickShowInPropertiesPanelWm(item: TreeNode, name: string) { 520 this.updateAdditionalPropertySelected(item, name); 521 } 522 523 onClickShowInPropertiesPanelSf( 524 item: ImeContainerProperties | InputMethodSurfaceProperties, 525 ) { 526 this.updateHighlightedItem(item.id); 527 } 528 529 private updateHighlightedItem(newId: string) { 530 const event: CustomEvent = new CustomEvent( 531 ViewerEvents.HighlightedIdChange, 532 { 533 bubbles: true, 534 detail: {id: newId}, 535 }, 536 ); 537 this.elementRef.nativeElement.dispatchEvent(event); 538 } 539 540 private updateAdditionalPropertySelected(item: TreeNode, name: string) { 541 const itemWrapper = { 542 name, 543 treeNode: item, 544 }; 545 const event: CustomEvent = new CustomEvent( 546 ViewerEvents.AdditionalPropertySelected, 547 { 548 bubbles: true, 549 detail: {selectedItem: itemWrapper}, 550 }, 551 ); 552 this.elementRef.nativeElement.dispatchEvent(event); 553 } 554} 555