• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {CdkVirtualScrollViewport} from '@angular/cdk/scrolling';
17import {Component, ElementRef, Inject, Input, ViewChild} from '@angular/core';
18import {MatSelectChange} from '@angular/material/select';
19import {Events} from './events';
20import {UiData} from './ui_data';
21
22@Component({
23  selector: 'viewer-transactions',
24  template: `
25    <div class="card-grid">
26      <div class="entries">
27        <div class="filters">
28          <div class="time"></div>
29          <div class="id">
30            <mat-form-field appearance="fill">
31              <mat-label>TX ID</mat-label>
32              <input matInput [(ngModel)]="idString" (input)="onIdSearchStringChanged()" />
33            </mat-form-field>
34          </div>
35          <div class="vsyncid">
36            <mat-form-field appearance="fill">
37              <mat-label>VSYNC ID</mat-label>
38              <mat-select (selectionChange)="onVSyncIdFilterChanged($event)" multiple>
39                <mat-option *ngFor="let vsyncId of uiData.allVSyncIds" [value]="vsyncId">
40                  {{ vsyncId }}
41                </mat-option>
42              </mat-select>
43            </mat-form-field>
44          </div>
45          <div class="pid">
46            <mat-form-field appearance="fill">
47              <mat-label>PID</mat-label>
48              <mat-select (selectionChange)="onPidFilterChanged($event)" multiple>
49                <mat-option *ngFor="let pid of uiData.allPids" [value]="pid">
50                  {{ pid }}
51                </mat-option>
52              </mat-select>
53            </mat-form-field>
54          </div>
55          <div class="uid">
56            <mat-form-field appearance="fill">
57              <mat-label>UID</mat-label>
58              <mat-select (selectionChange)="onUidFilterChanged($event)" multiple>
59                <mat-option *ngFor="let uid of uiData.allUids" [value]="uid">
60                  {{ uid }}
61                </mat-option>
62              </mat-select>
63            </mat-form-field>
64          </div>
65          <div class="type">
66            <mat-form-field appearance="fill">
67              <mat-label>Type</mat-label>
68              <mat-select (selectionChange)="onTypeFilterChanged($event)" multiple>
69                <mat-option *ngFor="let type of uiData.allTypes" [value]="type">
70                  {{ type }}
71                </mat-option>
72              </mat-select>
73            </mat-form-field>
74          </div>
75          <div class="id">
76            <mat-form-field appearance="fill">
77              <mat-label>LAYER/DISP ID</mat-label>
78              <mat-select (selectionChange)="onLayerIdFilterChanged($event)" multiple>
79                <mat-option *ngFor="let id of uiData.allLayerAndDisplayIds" [value]="id">
80                  {{ id }}
81                </mat-option>
82              </mat-select>
83            </mat-form-field>
84          </div>
85          <div class="what">
86            <mat-form-field appearance="fill">
87              <mat-label>Search text</mat-label>
88              <input matInput [(ngModel)]="whatSearchString" (input)="onWhatSearchStringChange()" />
89            </mat-form-field>
90          </div>
91        </div>
92
93        <cdk-virtual-scroll-viewport itemSize="24" class="scroll">
94          <div
95            *cdkVirtualFor="let entry of uiData.entries; let i = index"
96            class="entry"
97            [class.current-entry]="isCurrentEntry(i)"
98            [class.selected-entry]="isSelectedEntry(i)"
99            (click)="onEntryClicked(i)">
100            <div class="time">
101              <span class="mat-body-1">{{ entry.time }}</span>
102            </div>
103            <div class="id">
104              <span class="mat-body-1">{{ entry.transactionId }}</span>
105            </div>
106            <div class="vsyncid">
107              <span class="mat-body-1">{{ entry.vsyncId }}</span>
108            </div>
109            <div class="pid">
110              <span class="mat-body-1">{{ entry.pid }}</span>
111            </div>
112            <div class="uid">
113              <span class="mat-body-1">{{ entry.uid }}</span>
114            </div>
115            <div class="type">
116              <span class="mat-body-1">{{ entry.type }}</span>
117            </div>
118            <div class="id">
119              <span class="mat-body-1">{{ entry.layerOrDisplayId }}</span>
120            </div>
121            <div class="what">
122              <span class="mat-body-1">{{ entry.what }}</span>
123            </div>
124          </div>
125        </cdk-virtual-scroll-viewport>
126      </div>
127
128      <mat-divider [vertical]="true"></mat-divider>
129
130      <div class="container-properties">
131        <h3 class="properties-title mat-title">Properties - Proto Dump</h3>
132        <tree-view
133          *ngIf="uiData.currentPropertiesTree"
134          class="properties-tree"
135          [item]="uiData.currentPropertiesTree"></tree-view>
136      </div>
137    </div>
138  `,
139  styles: [
140    `
141      .entries {
142        flex: 3;
143        display: flex;
144        flex-direction: column;
145        padding: 16px;
146      }
147
148      .container-properties {
149        flex: 1;
150        padding: 16px;
151      }
152
153      .entries .filters {
154        display: flex;
155        flex-direction: row;
156      }
157
158      .entries .scroll {
159        flex: 1;
160        height: 100%;
161      }
162
163      .scroll .entry {
164        display: flex;
165        flex-direction: row;
166      }
167
168      .filters div {
169        flex: 1;
170        padding: 4px;
171      }
172
173      .filters .vsyncid mat-form-field {
174        width: 120px;
175      }
176
177      .filters div.time {
178        flex: 2;
179      }
180
181      .filters div.what {
182        flex: 3;
183      }
184
185      .filters .id mat-form-field {
186        width: 150px;
187      }
188
189      .filters .what {
190        margin-right: 16px;
191      }
192
193      .filters .what mat-form-field {
194        width: 250px;
195      }
196
197      .entry div {
198        flex: 1;
199        padding: 4px;
200      }
201
202      .entry div.time {
203        flex: 2;
204      }
205
206      .entry div.what {
207        flex: 3;
208      }
209
210      .entry.current-entry {
211        color: white;
212        background-color: #365179;
213      }
214
215      .entry.selected-entry {
216        color: white;
217        background-color: #98aecd;
218      }
219
220      mat-form-field {
221        width: 100px;
222      }
223
224      ::ng-deep .mat-select-panel-wrap {
225        overflow: scroll;
226        overflow-x: hidden;
227        max-height: 75vh;
228      }
229    `,
230  ],
231})
232class ViewerTransactionsComponent {
233  uiData: UiData = UiData.EMPTY;
234  idString = '';
235  whatSearchString = '';
236
237  @ViewChild(CdkVirtualScrollViewport) private scrollComponent?: CdkVirtualScrollViewport;
238  private elementRef: ElementRef;
239
240  constructor(@Inject(ElementRef) elementRef: ElementRef) {
241    this.elementRef = elementRef;
242  }
243
244  @Input()
245  set inputData(data: UiData) {
246    this.uiData = data;
247    if (this.uiData.scrollToIndex !== undefined && this.scrollComponent) {
248      this.scrollComponent.scrollToIndex(this.uiData.scrollToIndex);
249    }
250  }
251
252  onVSyncIdFilterChanged(event: MatSelectChange) {
253    this.emitEvent(Events.VSyncIdFilterChanged, event.value);
254  }
255
256  onPidFilterChanged(event: MatSelectChange) {
257    this.emitEvent(Events.PidFilterChanged, event.value);
258  }
259
260  onUidFilterChanged(event: MatSelectChange) {
261    this.emitEvent(Events.UidFilterChanged, event.value);
262  }
263
264  onTypeFilterChanged(event: MatSelectChange) {
265    this.emitEvent(Events.TypeFilterChanged, event.value);
266  }
267
268  onLayerIdFilterChanged(event: MatSelectChange) {
269    this.emitEvent(Events.LayerIdFilterChanged, event.value);
270  }
271
272  onWhatSearchStringChange() {
273    this.emitEvent(Events.WhatSearchStringChanged, this.whatSearchString);
274  }
275
276  onIdSearchStringChanged() {
277    this.emitEvent(Events.IdFilterChanges, this.idString);
278  }
279
280  onEntryClicked(index: number) {
281    this.emitEvent(Events.EntryClicked, index);
282  }
283
284  isCurrentEntry(index: number): boolean {
285    return index === this.uiData.currentEntryIndex;
286  }
287
288  isSelectedEntry(index: number): boolean {
289    return index === this.uiData.selectedEntryIndex;
290  }
291
292  private emitEvent(event: string, data: any) {
293    const customEvent = new CustomEvent(event, {
294      bubbles: true,
295      detail: data,
296    });
297    this.elementRef.nativeElement.dispatchEvent(customEvent);
298  }
299}
300
301export {ViewerTransactionsComponent};
302