• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2023 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 */
16
17import {assertDefined} from 'common/assert_utils';
18import {TimeUtils} from 'common/time_utils';
19import {LayerTraceEntry, Transition, WindowManagerState} from 'trace/flickerlib/common';
20import {Trace} from 'trace/trace';
21import {Traces} from 'trace/traces';
22import {TraceEntryFinder} from 'trace/trace_entry_finder';
23import {TracePosition} from 'trace/trace_position';
24import {TraceType} from 'trace/trace_type';
25import {PropertiesTreeNode} from 'viewers/common/ui_tree_utils';
26import {UiData} from './ui_data';
27
28export class Presenter {
29  private transitionTrace: Trace<object>;
30  private surfaceFlingerTrace: Trace<object> | undefined;
31  private windowManagerTrace: Trace<object> | undefined;
32  private uiData = UiData.EMPTY;
33  private readonly notifyUiDataCallback: (data: UiData) => void;
34
35  constructor(traces: Traces, notifyUiDataCallback: (data: UiData) => void) {
36    this.transitionTrace = assertDefined(traces.getTrace(TraceType.TRANSITION));
37    this.surfaceFlingerTrace = traces.getTrace(TraceType.SURFACE_FLINGER);
38    this.windowManagerTrace = traces.getTrace(TraceType.WINDOW_MANAGER);
39    this.notifyUiDataCallback = notifyUiDataCallback;
40  }
41
42  async onTracePositionUpdate(position: TracePosition) {
43    if (this.uiData === UiData.EMPTY) {
44      this.uiData = await this.computeUiData();
45    }
46
47    const entry = TraceEntryFinder.findCorrespondingEntry(this.transitionTrace, position);
48
49    this.uiData.selectedTransition = await entry?.getValue();
50
51    this.notifyUiDataCallback(this.uiData);
52  }
53
54  onTransitionSelected(transition: Transition): void {
55    this.uiData.selectedTransition = transition;
56    this.uiData.selectedTransitionPropertiesTree =
57      this.makeSelectedTransitionPropertiesTree(transition);
58    this.notifyUiDataCallback(this.uiData);
59  }
60
61  private async computeUiData(): Promise<UiData> {
62    const entryPromises = this.transitionTrace.mapEntry((entry, originalIndex) => {
63      return entry.getValue();
64    });
65    const transitions = await Promise.all(entryPromises);
66
67    const selectedTransition = this.uiData?.selectedTransition ?? undefined;
68    const selectedTransitionPropertiesTree =
69      this.uiData?.selectedTransitionPropertiesTree ?? undefined;
70
71    const timestampType = this.transitionTrace.getTimestampType();
72    if (timestampType === undefined) {
73      throw new Error('Missing timestamp type in trace!');
74    }
75    return new UiData(
76      transitions,
77      selectedTransition,
78      timestampType,
79      selectedTransitionPropertiesTree
80    );
81  }
82
83  private makeSelectedTransitionPropertiesTree(transition: Transition): PropertiesTreeNode {
84    const changes: PropertiesTreeNode[] = [];
85
86    for (const change of transition.changes) {
87      let layerName: string | undefined = undefined;
88      let windowName: string | undefined = undefined;
89
90      if (this.surfaceFlingerTrace) {
91        this.surfaceFlingerTrace.forEachEntry((entry, originalIndex) => {
92          if (layerName !== undefined) {
93            return;
94          }
95          const layerTraceEntry = entry.getValue() as LayerTraceEntry;
96          for (const layer of layerTraceEntry.flattenedLayers) {
97            if (layer.id === change.layerId) {
98              layerName = layer.name;
99            }
100          }
101        });
102      }
103
104      if (this.windowManagerTrace) {
105        this.windowManagerTrace.forEachEntry((entry, originalIndex) => {
106          if (windowName !== undefined) {
107            return;
108          }
109          const wmState = entry.getValue() as WindowManagerState;
110          for (const window of wmState.windowContainers) {
111            if (window.token.toLowerCase() === change.windowId.toString(16).toLowerCase()) {
112              windowName = window.title;
113            }
114          }
115        });
116      }
117
118      const layerIdValue = layerName ? `${change.layerId} (${layerName})` : change.layerId;
119      const windowIdValue = windowName
120        ? `0x${change.windowId.toString(16)} (${windowName})`
121        : `0x${change.windowId.toString(16)}`;
122
123      changes.push({
124        propertyKey: 'change',
125        children: [
126          {propertyKey: 'transitMode', propertyValue: change.transitMode},
127          {propertyKey: 'layerId', propertyValue: layerIdValue},
128          {propertyKey: 'windowId', propertyValue: windowIdValue},
129        ],
130      });
131    }
132
133    const properties: PropertiesTreeNode[] = [
134      {propertyKey: 'id', propertyValue: transition.id},
135      {propertyKey: 'type', propertyValue: transition.type},
136      {propertyKey: 'aborted', propertyValue: `${transition.aborted}`},
137    ];
138
139    if (transition.handler) {
140      properties.push({propertyKey: 'handler', propertyValue: transition.handler});
141    }
142
143    const timestampType = this.transitionTrace.getTimestampType();
144
145    if (!transition.createTime.isMin) {
146      properties.push({
147        propertyKey: 'createTime',
148        propertyValue: TimeUtils.formattedKotlinTimestamp(transition.createTime, timestampType),
149      });
150    }
151
152    if (!transition.sendTime.isMin) {
153      properties.push({
154        propertyKey: 'sendTime',
155        propertyValue: TimeUtils.formattedKotlinTimestamp(transition.sendTime, timestampType),
156      });
157    }
158
159    if (!transition.dispatchTime.isMin) {
160      properties.push({
161        propertyKey: 'dispatchTime',
162        propertyValue: TimeUtils.formattedKotlinTimestamp(transition.dispatchTime, timestampType),
163      });
164    }
165
166    if (!transition.finishTime.isMax) {
167      properties.push({
168        propertyKey: 'finishTime',
169        propertyValue: TimeUtils.formattedKotlinTimestamp(transition.finishTime, timestampType),
170      });
171    }
172
173    if (transition.mergeRequestTime) {
174      properties.push({
175        propertyKey: 'mergeRequestTime',
176        propertyValue: TimeUtils.formattedKotlinTimestamp(
177          transition.mergeRequestTime,
178          timestampType
179        ),
180      });
181    }
182
183    if (transition.shellAbortTime) {
184      properties.push({
185        propertyKey: 'shellAbortTime',
186        propertyValue: TimeUtils.formattedKotlinTimestamp(transition.shellAbortTime, timestampType),
187      });
188    }
189
190    if (transition.mergeTime) {
191      properties.push({
192        propertyKey: 'mergeTime',
193        propertyValue: TimeUtils.formattedKotlinTimestamp(transition.mergeTime, timestampType),
194      });
195    }
196
197    if (transition.mergedInto) {
198      properties.push({propertyKey: 'mergedInto', propertyValue: transition.mergedInto});
199    }
200
201    if (transition.startTransactionId !== -1) {
202      properties.push({
203        propertyKey: 'startTransactionId',
204        propertyValue: transition.startTransactionId,
205      });
206    }
207    if (transition.finishTransactionId !== -1) {
208      properties.push({
209        propertyKey: 'finishTransactionId',
210        propertyValue: transition.finishTransactionId,
211      });
212    }
213    if (changes.length > 0) {
214      properties.push({propertyKey: 'changes', children: changes});
215    }
216
217    return {
218      children: properties,
219      propertyKey: 'Selected Transition',
220    };
221  }
222}
223