• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2024 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 {Analytics} from 'logging/analytics';
18import {TRACE_INFO} from 'trace/trace_info';
19import {TraceType} from 'trace/trace_type';
20import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node';
21import {Operation} from 'trace/tree_node/operations/operation';
22import {PropertyTreeNode} from 'trace/tree_node/property_tree_node';
23import {TreeNode} from 'trace/tree_node/tree_node';
24import {TextFilter} from 'viewers/common/text_filter';
25import {IsModifiedCallbackType} from './add_diffs';
26import {AddDiffsPropertiesTree} from './add_diffs_properties_tree';
27import {Filter} from './operations/filter';
28import {UiPropertyTreeNode} from './ui_property_tree_node';
29import {UiTreeFormatter} from './ui_tree_formatter';
30import {TreeNodeFilter, UiTreeUtils} from './ui_tree_utils';
31import {UserOptions} from './user_options';
32
33export class PropertiesPresenter {
34  private propertiesFilter: TreeNodeFilter;
35  private highlightedProperty = '';
36  private propertiesTree: PropertyTreeNode | undefined;
37  private formattedTree: UiPropertyTreeNode | undefined;
38
39  constructor(
40    private userOptions: UserOptions,
41    private textFilter: TextFilter,
42    private propertiesDenylist: string[],
43    private customOperations?: Array<Operation<UiPropertyTreeNode>>,
44    private defaultAllowlist: string[] = [],
45  ) {
46    this.propertiesFilter = UiTreeUtils.makeNodeFilter(
47      this.textFilter.getFilterPredicate(),
48    );
49  }
50
51  getUserOptions(): UserOptions {
52    return this.userOptions;
53  }
54
55  setPropertiesTree(tree: PropertyTreeNode | undefined) {
56    this.propertiesTree = tree;
57  }
58
59  getPropertiesTree(): PropertyTreeNode | undefined {
60    return this.propertiesTree;
61  }
62
63  getFormattedTree(): UiPropertyTreeNode | undefined {
64    return this.formattedTree;
65  }
66
67  getHighlightedProperty(): string {
68    return this.highlightedProperty;
69  }
70
71  applyHighlightedPropertyChange(id: string) {
72    if (this.highlightedProperty === id) {
73      this.highlightedProperty = '';
74    } else {
75      this.highlightedProperty = id;
76    }
77  }
78
79  getTextFilter(): TextFilter | undefined {
80    return this.textFilter;
81  }
82
83  applyPropertiesFilterChange(textFilter: TextFilter) {
84    this.textFilter = textFilter;
85    this.propertiesFilter = UiTreeUtils.makeNodeFilter(
86      textFilter.getFilterPredicate(),
87    );
88  }
89
90  applyPropertiesUserOptionsChange(userOptions: UserOptions) {
91    this.userOptions = userOptions;
92  }
93
94  updateDefaultAllowList(value: string[]) {
95    this.defaultAllowlist = value;
96  }
97
98  async formatPropertiesTree(
99    previousHierarchyTree: HierarchyTreeNode | undefined,
100    displayName: string | undefined,
101    keepCalculated: boolean,
102    traceType?: TraceType,
103  ): Promise<void> {
104    if (!this.propertiesTree) {
105      this.formattedTree = undefined;
106      return;
107    }
108    const uiTree = UiPropertyTreeNode.from(this.propertiesTree);
109
110    if (
111      this.userOptions['showDiff']?.enabled &&
112      !this.userOptions['showDiff']?.isUnavailable
113    ) {
114      const prevEntryNode = previousHierarchyTree?.findDfs(
115        UiTreeUtils.makeIdMatchFilter(this.propertiesTree.id),
116      );
117      const prevEntryUiTree = prevEntryNode
118        ? UiPropertyTreeNode.from(await prevEntryNode.getAllProperties())
119        : undefined;
120
121      const startTimeMs = Date.now();
122      await new AddDiffsPropertiesTree(
123        PropertiesPresenter.isPropertyNodeModified,
124        this.propertiesDenylist,
125      ).executeInPlace(uiTree, prevEntryUiTree);
126      Analytics.Navigation.logDiffComputationTime(
127        'properties',
128        traceType ? TRACE_INFO[traceType].name : 'Unknown',
129        Date.now() - startTimeMs,
130      );
131    }
132
133    if (displayName) {
134      uiTree.setDisplayName(displayName);
135    }
136
137    const predicatesKeepingChildren = [this.propertiesFilter];
138    const predicatesDiscardingChildren = [];
139
140    if (this.propertiesDenylist) {
141      predicatesDiscardingChildren.push(
142        UiTreeUtils.makeDenyListFilterByName(this.propertiesDenylist),
143      );
144    }
145
146    if (!this.userOptions['showDefaults']?.enabled) {
147      predicatesDiscardingChildren.push(
148        UiTreeUtils.makeIsNotDefaultFilter(this.defaultAllowlist),
149      );
150    }
151
152    if (!keepCalculated) {
153      predicatesDiscardingChildren.push(UiTreeUtils.isNotCalculated);
154    }
155    const formatter = new UiTreeFormatter<UiPropertyTreeNode>().setUiTree(
156      uiTree,
157    );
158    if (predicatesDiscardingChildren.length > 0) {
159      formatter.addOperation(new Filter(predicatesDiscardingChildren, false));
160    }
161    formatter.addOperation(new Filter(predicatesKeepingChildren, true));
162
163    this.customOperations?.forEach((op) => formatter.addOperation(op));
164
165    this.formattedTree = formatter.format();
166  }
167
168  clear() {
169    this.propertiesTree = undefined;
170    this.formattedTree = undefined;
171  }
172
173  static isPropertyNodeModified: IsModifiedCallbackType = async (
174    newTree: TreeNode,
175    oldTree: TreeNode,
176  ) => {
177    const newValue = (newTree as UiPropertyTreeNode).formattedValue();
178    const oldValue = (oldTree as UiPropertyTreeNode).formattedValue();
179
180    return oldValue !== newValue;
181  };
182}
183