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