blob: 5a66d48aa1812c6207995985633bbbb50615033f [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ImeUiData } from "viewers/common/ime_ui_data";
import { TraceType } from "common/trace/trace_type";
import { UserOptions } from "viewers/common/user_options";
import { HierarchyTreeNode, PropertiesTreeNode } from "viewers/common/ui_tree_utils";
import { TreeGenerator } from "viewers/common/tree_generator";
import { TreeTransformer } from "viewers/common/tree_transformer";
import { TreeUtils, FilterType } from "common/utils/tree_utils";
import { TraceTreeNode } from "common/trace/trace_tree_node";
import { ImeLayers, ImeUtils, ProcessedWindowManagerState } from "viewers/common/ime_utils";
import { ImeAdditionalProperties } from "viewers/common/ime_additional_properties";
import { TableProperties } from "viewers/common/table_properties";
import { PersistentStoreObject } from "common/utils/persistent_store_object";
type NotifyImeViewCallbackType = (uiData: ImeUiData) => void;
export abstract class PresenterInputMethod {
constructor(
notifyViewCallback: NotifyImeViewCallbackType,
dependencies: Array<TraceType>,
private storage: Storage
) {
this.notifyViewCallback = notifyViewCallback;
this.dependencies = dependencies;
this.uiData = new ImeUiData(dependencies);
this.notifyViewCallback(this.uiData);
}
public updatePinnedItems(pinnedItem: HierarchyTreeNode) {
const pinnedId = `${pinnedItem.id}`;
if (this.pinnedItems.map(item => `${item.id}`).includes(pinnedId)) {
this.pinnedItems = this.pinnedItems.filter(pinned => `${pinned.id}` != pinnedId);
} else {
this.pinnedItems.push(pinnedItem);
}
this.updatePinnedIds(pinnedId);
this.uiData.pinnedItems = this.pinnedItems;
this.notifyViewCallback(this.uiData);
}
public updateHighlightedItems(id: string) {
if (this.highlightedItems.includes(id)) {
this.highlightedItems = this.highlightedItems.filter(hl => hl != id);
} else {
this.highlightedItems = []; //if multi-select surfaces implemented, remove this line
this.highlightedItems.push(id);
}
this.uiData.highlightedItems = this.highlightedItems;
this.notifyViewCallback(this.uiData);
}
public updateHierarchyTree(userOptions: UserOptions) {
this.hierarchyUserOptions = userOptions;
this.uiData.hierarchyUserOptions = this.hierarchyUserOptions;
this.uiData.tree = this.generateTree();
this.notifyViewCallback(this.uiData);
}
public filterHierarchyTree(filterString: string) {
this.hierarchyFilter = TreeUtils.makeNodeFilter(filterString);
this.uiData.tree = this.generateTree();
this.notifyViewCallback(this.uiData);
}
public updatePropertiesTree(userOptions: UserOptions) {
this.propertiesUserOptions = userOptions;
this.uiData.propertiesUserOptions = this.propertiesUserOptions;
this.updateSelectedTreeUiData();
}
public filterPropertiesTree(filterString: string) {
this.propertiesFilter = TreeUtils.makeNodeFilter(filterString);
this.updateSelectedTreeUiData();
}
public newPropertiesTree(selectedItem: HierarchyTreeNode) {
this.additionalPropertyEntry = null;
this.selectedHierarchyTree = selectedItem;
this.updateSelectedTreeUiData();
}
public newAdditionalPropertiesTree(selectedItem: any) {
this.selectedHierarchyTree = new HierarchyTreeNode(selectedItem.name, "AdditionalProperty", "AdditionalProperty");
this.additionalPropertyEntry = {
name: selectedItem.name,
kind: "AdditionalProperty",
children: [],
stableId: "AdditionalProperty",
proto: selectedItem.proto,
};
this.updateSelectedTreeUiData();
}
public notifyCurrentTraceEntries(entries: Map<TraceType, [any, any]>) {
this.uiData = new ImeUiData(this.dependencies);
this.uiData.hierarchyUserOptions = this.hierarchyUserOptions;
this.uiData.propertiesUserOptions = this.propertiesUserOptions;
const imEntries = entries.get(this.dependencies[0]);
if (imEntries && imEntries[0]) {
this.entry = imEntries[0];
this.uiData.highlightedItems = this.highlightedItems;
const wmEntries = entries.get(TraceType.WINDOW_MANAGER);
const sfEntries = entries.get(TraceType.SURFACE_FLINGER);
this.uiData.additionalProperties = this.getAdditionalProperties(
wmEntries ? wmEntries[0] : undefined,
sfEntries ? sfEntries[0] : undefined
);
this.uiData.tree = this.generateTree();
this.uiData.hierarchyTableProperties = this.updateHierarchyTableProperties();
}
this.notifyViewCallback(this.uiData);
}
protected getAdditionalProperties(wmEntry: TraceTreeNode | undefined, sfEntry: TraceTreeNode | undefined) {
let wmProperties: ProcessedWindowManagerState | undefined;
let sfProperties: ImeLayers | undefined;
let sfSubtrees: any[];
if (wmEntry) {
wmProperties = ImeUtils.processWindowManagerTraceEntry(wmEntry);
if (sfEntry) {
sfProperties = ImeUtils.getImeLayers(sfEntry, wmProperties);
sfSubtrees = [sfProperties?.taskOfImeContainer, sfProperties?.taskOfImeSnapshot]
.filter((node) => node) // filter away null values
.map((node) => {
node.kind = "SF subtree - " + node.id;
return node;
});
this.entry?.children.push(...sfSubtrees);
}
}
return new ImeAdditionalProperties(
wmProperties,
sfProperties,
);
}
protected generateTree() {
if (!this.entry) {
return null;
}
const generator = new TreeGenerator(this.entry, this.hierarchyFilter, this.pinnedIds)
.setIsOnlyVisibleView(this.hierarchyUserOptions["onlyVisible"]?.enabled)
.setIsSimplifyNames(this.hierarchyUserOptions["simplifyNames"]?.enabled)
.setIsFlatView(this.hierarchyUserOptions["flat"]?.enabled)
.withUniqueNodeId();
const tree: HierarchyTreeNode | null = generator.generateTree();
this.pinnedItems = generator.getPinnedItems();
this.uiData.pinnedItems = this.pinnedItems;
return tree;
}
private updateSelectedTreeUiData() {
if (this.selectedHierarchyTree) {
this.uiData.propertiesTree = this.getTreeWithTransformedProperties(this.selectedHierarchyTree);
}
this.notifyViewCallback(this.uiData);
}
private updatePinnedIds(newId: string) {
if (this.pinnedIds.includes(newId)) {
this.pinnedIds = this.pinnedIds.filter(pinned => pinned != newId);
} else {
this.pinnedIds.push(newId);
}
}
private getTreeWithTransformedProperties(selectedTree: HierarchyTreeNode): PropertiesTreeNode {
const transformer = new TreeTransformer(selectedTree, this.propertiesFilter)
.setOnlyProtoDump(this.additionalPropertyEntry != null)
.setIsShowDefaults(this.propertiesUserOptions["showDefaults"]?.enabled)
.setTransformerOptions({skip: selectedTree.skip})
.setProperties(this.additionalPropertyEntry ?? this.entry);
const transformedTree = transformer.transform();
return transformedTree;
}
private hierarchyFilter: FilterType = TreeUtils.makeNodeFilter("");
private propertiesFilter: FilterType = TreeUtils.makeNodeFilter("");
private pinnedItems: Array<HierarchyTreeNode> = [];
private pinnedIds: Array<string> = [];
private selectedHierarchyTree: HierarchyTreeNode | null = null;
readonly notifyViewCallback: NotifyImeViewCallbackType;
protected readonly dependencies: Array<TraceType>;
protected uiData: ImeUiData;
protected highlightedItems: Array<string> = [];
protected entry: TraceTreeNode | null = null;
protected additionalPropertyEntry: TraceTreeNode | null = null;
protected hierarchyUserOptions: UserOptions = PersistentStoreObject.new<UserOptions>("ImeHierarchyOptions", {
simplifyNames: {
name: "Simplify names",
enabled: true
},
onlyVisible: {
name: "Only visible",
enabled: false
},
flat: {
name: "Flat",
enabled: false
}
}, this.storage);
protected propertiesUserOptions: UserOptions = PersistentStoreObject.new<UserOptions>("ImePropertiesOptions", {
showDefaults: {
name: "Show defaults",
enabled: false,
tooltip: `
If checked, shows the value of all properties.
Otherwise, hides all properties whose value is
the default for its data type.
`
},
}, this.storage);
protected abstract updateHierarchyTableProperties(): TableProperties;
}