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 */ 16 17import {PersistentStoreProxy} from 'common/store/persistent_store_proxy'; 18import {Store} from 'common/store/store'; 19import {Trace} from 'trace/trace'; 20import {Traces} from 'trace/traces'; 21import {TRACE_INFO} from 'trace/trace_info'; 22import {TraceType} from 'trace/trace_type'; 23import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node'; 24import { 25 AbstractHierarchyViewerPresenter, 26 NotifyHierarchyViewCallbackType, 27} from 'viewers/common/abstract_hierarchy_viewer_presenter'; 28import {VISIBLE_CHIP} from 'viewers/common/chip'; 29import {DisplayIdentifier} from 'viewers/common/display_identifier'; 30import { 31 HierarchyPresenter, 32 SelectedTree, 33} from 'viewers/common/hierarchy_presenter'; 34import {PropertiesPresenter} from 'viewers/common/properties_presenter'; 35import {RectsPresenter} from 'viewers/common/rects_presenter'; 36import {TextFilter} from 'viewers/common/text_filter'; 37import {UiHierarchyTreeNode} from 'viewers/common/ui_hierarchy_tree_node'; 38import {UiPropertyTreeNode} from 'viewers/common/ui_property_tree_node'; 39import {UI_RECT_FACTORY} from 'viewers/common/ui_rect_factory'; 40import {UserOptions} from 'viewers/common/user_options'; 41import {ViewerEvents} from 'viewers/common/viewer_events'; 42import { 43 RectLegendFactory, 44 TraceRectType, 45} from 'viewers/components/rects/rect_spec'; 46import {UiRect} from 'viewers/components/rects/ui_rect'; 47import {PropagateHashCodes} from './operations/propagate_hash_codes'; 48import {UpdateDisplayNames} from './operations/update_display_names'; 49import {UiData} from './ui_data'; 50 51export class Presenter extends AbstractHierarchyViewerPresenter<UiData> { 52 static readonly DENYLIST_PROPERTY_NAMES = [ 53 'name', 54 'children', 55 'dpiX', 56 'dpiY', 57 ]; 58 59 protected override hierarchyPresenter = new HierarchyPresenter( 60 PersistentStoreProxy.new<UserOptions>( 61 'WmHierarchyOptions', 62 { 63 showDiff: { 64 name: 'Show diff', 65 enabled: false, 66 isUnavailable: false, 67 }, 68 showOnlyVisible: { 69 name: 'Show only', 70 chip: VISIBLE_CHIP, 71 enabled: false, 72 }, 73 simplifyNames: { 74 name: 'Simplify names', 75 enabled: true, 76 }, 77 flat: { 78 name: 'Flat', 79 enabled: false, 80 }, 81 }, 82 this.storage, 83 ), 84 new TextFilter(), 85 Presenter.DENYLIST_PROPERTY_NAMES, 86 true, 87 false, 88 this.getEntryFormattedTimestamp, 89 [[TraceType.WINDOW_MANAGER, [new UpdateDisplayNames()]]], 90 ); 91 protected override rectsPresenter = new RectsPresenter( 92 PersistentStoreProxy.new<UserOptions>( 93 'WmRectsOptions', 94 { 95 ignoreRectShowState: { 96 name: 'Ignore', 97 icon: 'visibility', 98 enabled: false, 99 }, 100 showOnlyVisible: { 101 name: 'Show only', 102 chip: VISIBLE_CHIP, 103 enabled: false, 104 }, 105 }, 106 this.storage, 107 ), 108 (tree: HierarchyTreeNode) => UI_RECT_FACTORY.makeUiRects(tree), 109 this.getDisplays, 110 this.convertRectIdtoContainerName, 111 ); 112 protected override propertiesPresenter = new PropertiesPresenter( 113 PersistentStoreProxy.new<UserOptions>( 114 'WmPropertyOptions', 115 { 116 showDiff: { 117 name: 'Show diff', 118 enabled: false, 119 isUnavailable: false, 120 }, 121 showDefaults: { 122 name: 'Show defaults', 123 enabled: false, 124 tooltip: `If checked, shows the value of all properties. 125Otherwise, hides all properties whose value is 126the default for its data type.`, 127 }, 128 }, 129 this.storage, 130 ), 131 new TextFilter(), 132 Presenter.DENYLIST_PROPERTY_NAMES, 133 [new PropagateHashCodes()], 134 ); 135 protected override multiTraceType = undefined; 136 137 constructor( 138 trace: Trace<HierarchyTreeNode>, 139 traces: Traces, 140 storage: Readonly<Store>, 141 notifyViewCallback: NotifyHierarchyViewCallbackType<UiData>, 142 ) { 143 const uiData = new UiData(); 144 uiData.rectSpec = { 145 type: TraceRectType.WINDOW_STATES, 146 icon: TRACE_INFO[TraceType.WINDOW_MANAGER].icon, 147 legend: RectLegendFactory.makeLegendForWindowStateRects(), 148 }; 149 super(trace, traces, storage, notifyViewCallback, uiData); 150 } 151 152 async onPropagatePropertyClick(node: UiPropertyTreeNode) { 153 if (node.name !== 'hashCode') { 154 return; 155 } 156 const token = (node.getValue() ?? 0).toString(16); 157 const target = this.uiData.hierarchyTrees 158 ?.at(0) 159 ?.findDfs((node) => node.id.includes(token)); 160 if (target) { 161 await this.onHighlightedNodeChange(target); 162 } 163 } 164 165 protected override addViewerSpecificListeners(htmlElement: HTMLElement) { 166 htmlElement.addEventListener( 167 ViewerEvents.PropagatePropertyClick, 168 async (event) => { 169 const node = (event as CustomEvent).detail; 170 await this.onPropagatePropertyClick(node); 171 }, 172 ); 173 } 174 175 override async onHighlightedNodeChange(item: UiHierarchyTreeNode) { 176 await this.applyHighlightedNodeChange(item); 177 this.refreshUIData(); 178 } 179 180 override async onHighlightedIdChange(newId: string) { 181 await this.applyHighlightedIdChange(newId); 182 this.refreshUIData(); 183 } 184 185 protected override getOverrideDisplayName( 186 selected: SelectedTree, 187 ): string | undefined { 188 if (!selected.tree.isRoot()) { 189 return undefined; 190 } 191 return this.hierarchyPresenter 192 .getCurrentHierarchyTreeNames(selected.trace) 193 ?.at(0); 194 } 195 196 protected override keepCalculated(tree: HierarchyTreeNode): boolean { 197 return false; 198 } 199 200 protected override refreshUIData() { 201 this.refreshHierarchyViewerUiData(); 202 } 203 204 private getDisplays(rects: UiRect[]): DisplayIdentifier[] { 205 const ids: DisplayIdentifier[] = []; 206 rects.forEach((rect: UiRect) => { 207 if (!rect.isDisplay) return; 208 const displayName = rect.label.slice(10, rect.label.length); 209 ids.push({ 210 displayId: rect.id, 211 groupId: rect.groupId, 212 name: displayName, 213 isActive: rect.isActiveDisplay, 214 }); 215 }); 216 return ids.sort(); 217 } 218 219 private convertRectIdtoContainerName(id: string) { 220 const parts = id.split(' '); 221 return parts.slice(2).join(' '); 222 } 223} 224