diff --git a/tools/winscope-ng/src/parsers/parser_surface_flinger.ts b/tools/winscope-ng/src/parsers/parser_surface_flinger.ts index e09c4778f..d158ed900 100644 --- a/tools/winscope-ng/src/parsers/parser_surface_flinger.ts +++ b/tools/winscope-ng/src/parsers/parser_surface_flinger.ts @@ -59,7 +59,7 @@ class ParserSurfaceFlinger extends Parser { return undefined; } - override processDecodedEntry(entryProto: any): any { + override processDecodedEntry(entryProto: any): LayerTraceEntry { return LayerTraceEntry.fromProto(entryProto.layers.layers, entryProto.displays, entryProto.elapsedRealtimeNanos, entryProto.hwcBlob); } diff --git a/tools/winscope-ng/src/test/fixtures/traces/SurfaceFlinger_with_IME.pb b/tools/winscope-ng/src/test/fixtures/traces/SurfaceFlinger_with_IME.pb new file mode 100644 index 000000000..b6a11bb5c Binary files /dev/null and b/tools/winscope-ng/src/test/fixtures/traces/SurfaceFlinger_with_IME.pb differ diff --git a/tools/winscope-ng/src/test/fixtures/traces/WindowManager_with_IME.pb b/tools/winscope-ng/src/test/fixtures/traces/WindowManager_with_IME.pb new file mode 100644 index 000000000..a3514913f Binary files /dev/null and b/tools/winscope-ng/src/test/fixtures/traces/WindowManager_with_IME.pb differ diff --git a/tools/winscope-ng/src/test/unit/hierarchy_tree_builder.ts b/tools/winscope-ng/src/test/unit/hierarchy_tree_builder.ts index 9ba551c7b..7b92f2315 100644 --- a/tools/winscope-ng/src/test/unit/hierarchy_tree_builder.ts +++ b/tools/winscope-ng/src/test/unit/hierarchy_tree_builder.ts @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { HierarchyTree } from "viewers/common/tree_utils"; +import { HierarchyTreeNode } from "viewers/common/tree_utils"; import Chip from "viewers/common/chip"; class HierarchyTreeBuilder { stableId = ""; name = ""; kind = ""; - children: HierarchyTree[] = []; + children: HierarchyTreeNode[] = []; shortName?: string; type?: string; id?: string | number; @@ -76,7 +76,7 @@ class HierarchyTreeBuilder { return this; } - setChildren(children: HierarchyTree[]) { + setChildren(children: HierarchyTreeNode[]) { this.children = children; return this; } @@ -116,8 +116,8 @@ class HierarchyTreeBuilder { return this; } - build(): HierarchyTree { - const node = new HierarchyTree(this.name, this.kind, this.stableId, this.children); + build(): HierarchyTreeNode { + const node = new HierarchyTreeNode(this.name, this.kind, this.stableId, this.children); node.chips = this.chips; node.showInFilteredView = this.showInFilteredView; diff --git a/tools/winscope-ng/src/viewers/common/ime_utils.spec.ts b/tools/winscope-ng/src/viewers/common/ime_utils.spec.ts new file mode 100644 index 000000000..e1169adf2 --- /dev/null +++ b/tools/winscope-ng/src/viewers/common/ime_utils.spec.ts @@ -0,0 +1,108 @@ +/* + * 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 {ImeUtils} from "./ime_utils"; +import {UnitTestUtils} from "test/unit/utils"; + +import {LayerTraceEntry} from "common/trace/flickerlib/layers/LayerTraceEntry"; +import {WindowManagerState} from "common/trace/flickerlib/windows/WindowManagerState"; +import {Timestamp, TimestampType} from "common/trace/timestamp"; + +async function getWindowManagerTraceEntry(): WindowManagerState { + const parser = await UnitTestUtils.getParser("traces/WindowManager_with_IME.pb"); + const timestamp = new Timestamp(TimestampType.ELAPSED, 502938057652n); + return parser.getTraceEntry(timestamp)!; +} + +async function getSurfaceFlingerTraceEntry(): LayerTraceEntry { + const parser = await UnitTestUtils.getParser("traces/SurfaceFlinger_with_IME.pb"); + const timestamp = new Timestamp(TimestampType.ELAPSED, 502942319579n); + return parser.getTraceEntry(timestamp); +} + +describe("ImeUtils", () => { + it("processes WindowManager trace entry", async () => { + const entry = await getWindowManagerTraceEntry(); + const processed = ImeUtils.processWindowManagerTraceEntry(entry); + + expect(processed.focusedApp) + .toEqual("com.google.android.apps.messaging/.ui.search.ZeroStateSearchActivity"); + + expect(processed.focusedActivity.token) + .toEqual("9d8c2ef"); + expect(processed.focusedActivity.layerId) + .toEqual(260); + + expect(processed.focusedWindow.token) + .toEqual("928b3d"); + expect(processed.focusedWindow.title) + .toEqual("com.google.android.apps.messaging/com.google.android.apps.messaging.ui.search.ZeroStateSearchActivity"); + + expect(processed.protoImeControlTarget.windowContainer.identifier.title) + .toEqual("com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity"); + expect(processed.protoImeControlTarget.windowContainer.identifier.hashCode) + .toEqual(247026562); + + expect(processed.protoImeInputTarget.windowContainer.identifier.title) + .toEqual("com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity"); + expect(processed.protoImeInputTarget.windowContainer.identifier.hashCode) + .toEqual(247026562); + + expect(processed.protoImeInsetsSourceProvider + .insetsSourceProvider).toBeDefined(); + + expect(processed.protoImeLayeringTarget.windowContainer.identifier.title) + .toEqual("SnapshotStartingWindow for taskId=1393"); + expect(processed.protoImeLayeringTarget.windowContainer.identifier.hashCode) + .toEqual(222907471); + + expect( + processed.isInputMethodWindowVisible) + .toBeFalse(); + }); + + it("processes SurfaceFlinger trace entry", async () => { + const processedWindowManagerState = ImeUtils.processWindowManagerTraceEntry( + await getWindowManagerTraceEntry()); + const entry = await getSurfaceFlingerTraceEntry(); + const layers = ImeUtils.getImeLayers(entry, processedWindowManagerState)!; + + expect(layers.inputMethodSurface.id) + .toEqual(280); + expect(layers.inputMethodSurface.isVisible) + .toEqual(false); + expect(layers.inputMethodSurface.rect.label).toEqual( + "Surface(name=77f1069 InputMethod)/@0xb4afb8f - animation-leash of insets_animation#280"); + expect(layers.inputMethodSurface.screenBounds) + .toBeDefined(); + + expect(layers.imeContainer.id) + .toEqual(12); + expect(layers.imeContainer.z).toEqual(1); + expect(layers.imeContainer.zOrderRelativeOfId) + .toEqual(115); + + expect(String(layers.focusedWindow.color)) + .toEqual("r:0 g:0 b:0 a:1"); + + expect(layers.taskOfImeContainer.kind) + .toEqual("SF subtree - 114"); + expect(layers.taskOfImeContainer.name) + .toEqual("Task=1391#114"); + + expect(layers.taskOfImeSnapshot) + .toBeUndefined(); + }); +}); diff --git a/tools/winscope-ng/src/viewers/common/ime_utils.ts b/tools/winscope-ng/src/viewers/common/ime_utils.ts new file mode 100644 index 000000000..e714a92e2 --- /dev/null +++ b/tools/winscope-ng/src/viewers/common/ime_utils.ts @@ -0,0 +1,145 @@ +/* + * 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 Activity from "common/trace/flickerlib/windows/Activity"; +import Layer from "common/trace/flickerlib/layers/Layer"; +import {LayerTraceEntry} from "common/trace/flickerlib/layers/LayerTraceEntry"; +import {WindowManagerState} from "common/trace/flickerlib/windows/WindowManagerState"; +import WindowState from "common/trace/flickerlib/windows/WindowState"; +import {TreeUtils, FilterType} from "./tree_utils"; + +class ProcessedWindowManagerState { + constructor( + public stableId: string, + public focusedApp: string, + public focusedWindow: WindowState, + public focusedActivity: Activity, + public isInputMethodWindowVisible: boolean, + public protoImeControlTarget: any, + public protoImeInputTarget: any, + public protoImeLayeringTarget: any, + public protoImeInsetsSourceProvider: any) { + } +} + +class ImeLayers { + constructor( + public imeContainer: Layer, + public inputMethodSurface: Layer, + public focusedWindow: Layer|undefined, + public taskOfImeContainer: Layer|undefined, + public taskOfImeSnapshot: Layer|undefined) { + } +} + +class ImeUtils { + public static processWindowManagerTraceEntry(entry: WindowManagerState): ProcessedWindowManagerState { + const displayContent = entry.root.children[0]; + + return new ProcessedWindowManagerState( + entry.stableId, + entry.focusedApp, + entry.focusedWindow, + entry.focusedActivity, + this.isInputMethodVisible(displayContent), + this.getImeControlTargetProperty(displayContent.proto), + this.getImeInputTargetProperty(displayContent.proto), + this.getImeLayeringTargetProperty(displayContent.proto), + displayContent.proto.imeInsetsSourceProvider + ); + } + + public static getImeLayers( + entry: LayerTraceEntry, + processedWindowManagerState: ProcessedWindowManagerState): ImeLayers|undefined { + const isImeContainer = TreeUtils.makeNodeFilter("ImeContainer"); + const imeContainer = TreeUtils.findDescendantNode(entry, isImeContainer); + if (!imeContainer) { + return undefined; + } + + const isInputMethodSurface = TreeUtils.makeNodeFilter("InputMethod"); + const inputMethodSurface = + TreeUtils.findDescendantNode(imeContainer, isInputMethodSurface); + + let focusedWindowLayer: Layer = undefined; + const focusedWindowToken = processedWindowManagerState.focusedWindow?.token; + if (focusedWindowToken) { + const isFocusedWindow = TreeUtils.makeNodeFilter(focusedWindowToken); + focusedWindowLayer = TreeUtils.findDescendantNode(entry, isFocusedWindow); + } + + // we want to see both ImeContainer and IME-snapshot if there are + // cases where both exist + const taskLayerOfImeContainer = + this.findAncestorTaskLayerOfImeLayer(entry, TreeUtils.makeNodeFilter("ImeContainer")); + + const taskLayerOfImeSnapshot = + this.findAncestorTaskLayerOfImeLayer(entry, TreeUtils.makeNodeFilter("IME-snapshot")); + + return new ImeLayers( + imeContainer, + inputMethodSurface, + focusedWindowLayer, + taskLayerOfImeContainer, + taskLayerOfImeSnapshot + ); + } + + private static findAncestorTaskLayerOfImeLayer(entry: LayerTraceEntry, isTargetImeLayer: FilterType): Layer { + const imeLayer = TreeUtils.findDescendantNode(entry, isTargetImeLayer); + if (!imeLayer) { + return undefined; + } + + const isTaskLayer = TreeUtils.makeNodeFilter("Task, ImePlaceholder"); + const taskLayer = TreeUtils.findAncestorNode(imeLayer, isTaskLayer); + if (!taskLayer) { + return undefined; + } + + taskLayer.kind = "SF subtree - " + taskLayer.id; + return taskLayer; + } + + private static getImeControlTargetProperty(displayContentProto: any): any { + const POSSIBLE_NAMES = ["inputMethodControlTarget", "imeControlTarget"]; + return this.findAnyPropertyWithMatchingName(displayContentProto, POSSIBLE_NAMES); + } + + private static getImeInputTargetProperty(displayContentProto: any): any { + const POSSIBLE_NAMES = ["inputMethodInputTarget", "imeInputTarget"]; + return this.findAnyPropertyWithMatchingName(displayContentProto, POSSIBLE_NAMES); + } + + private static getImeLayeringTargetProperty(displayContentProto: any): any { + const POSSIBLE_NAMES = ["inputMethodTarget", "imeLayeringTarget"]; + return this.findAnyPropertyWithMatchingName(displayContentProto, POSSIBLE_NAMES); + } + + private static findAnyPropertyWithMatchingName(object: any, possible_names: string[]): any { + const key = Object.keys(object).find(key => possible_names.includes(key)); + return key ? object[key] : undefined; + } + + private static isInputMethodVisible(windowOrLayer: any) : boolean { + const isInputMethod = TreeUtils.makeNodeFilter("InputMethod"); + const inputMethodWindowOrLayer = + TreeUtils.findDescendantNode(windowOrLayer, isInputMethod); + return inputMethodWindowOrLayer?.isVisible == true; + } +} + +export {ImeUtils}; diff --git a/tools/winscope-ng/src/viewers/common/tree_generator.spec.ts b/tools/winscope-ng/src/viewers/common/tree_generator.spec.ts index 0da5f9d76..83ba72afd 100644 --- a/tools/winscope-ng/src/viewers/common/tree_generator.spec.ts +++ b/tools/winscope-ng/src/viewers/common/tree_generator.spec.ts @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { DiffType, getFilter, HierarchyTree, TreeFlickerItem } from "viewers/common/tree_utils"; +import { TreeUtils, DiffType, HierarchyTreeNode, TreeNodeTrace } from "viewers/common/tree_utils"; import { TreeGenerator } from "viewers/common/tree_generator"; import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder"; describe("TreeGenerator", () => { - let entry: TreeFlickerItem; + let entry: TreeNodeTrace; beforeAll(async () => { entry = { kind: "entry", @@ -26,44 +26,47 @@ describe("TreeGenerator", () => { stableId: "BaseLayerTraceEntry", id: 0, chips: [], + parent: undefined, children: [{ kind: "3", id: 3, name: "Child1", stableId: "3 Child1", + parent: undefined, children: [ { kind: "2", id: 2, name: "Child2", stableId: "2 Child2", - children: [] + parent: undefined, + children: [], } ]}] }; }); it("generates tree", () => { - const expected: HierarchyTree = new HierarchyTreeBuilder().setName("BaseLayerTraceEntry").setKind("entry").setStableId("BaseLayerTraceEntry") + const expected: HierarchyTreeNode = new HierarchyTreeBuilder().setName("BaseLayerTraceEntry").setKind("entry").setStableId("BaseLayerTraceEntry") .setChildren([ new HierarchyTreeBuilder().setName("Child1").setStableId("3 Child1").setKind("3").setChildren([ new HierarchyTreeBuilder().setName("Child2").setStableId("2 Child2").setKind("2").setId(2).build() ]).setId(3).build() ]).setId(0).build(); - const filter = getFilter(""); + const filter = TreeUtils.makeNodeFilter(""); const generator = new TreeGenerator(entry, filter); expect(generator.generateTree()).toEqual(expected); }); it("generates diff tree with no diff", () => { - const expected: HierarchyTree = new HierarchyTreeBuilder().setName("BaseLayerTraceEntry").setKind("entry").setStableId("BaseLayerTraceEntry") + const expected: HierarchyTreeNode = new HierarchyTreeBuilder().setName("BaseLayerTraceEntry").setKind("entry").setStableId("BaseLayerTraceEntry") .setChildren([ new HierarchyTreeBuilder().setName("Child1").setStableId("3 Child1").setKind("3").setChildren([ new HierarchyTreeBuilder().setName("Child2").setStableId("2 Child2").setKind("2").setId(2).setDiffType(DiffType.NONE).build() ]).setId(3).setDiffType(DiffType.NONE).build() ]).setId(0).setDiffType(DiffType.NONE).build(); - const filter = getFilter(""); + const filter = TreeUtils.makeNodeFilter(""); const tree = new TreeGenerator(entry, filter).withUniqueNodeId((node: any) => { if (node) return node.stableId; else return null; @@ -72,19 +75,20 @@ describe("TreeGenerator", () => { }); it("generates diff tree with moved node", () => { - const prevEntry: TreeFlickerItem = { + const prevEntry: TreeNodeTrace = { kind: "entry", name: "BaseLayerTraceEntry", stableId: "BaseLayerTraceEntry", chips: [], id: 0, - + parent: undefined, children: [ { kind: "3", id: 3, stableId: "3 Child1", name: "Child1", + parent: undefined, children: [] }, { @@ -92,12 +96,13 @@ describe("TreeGenerator", () => { id: 2, stableId: "2 Child2", name: "Child2", + parent: undefined, children: [], } ] }; - const expected: HierarchyTree = new HierarchyTreeBuilder().setName("BaseLayerTraceEntry").setKind("entry").setStableId("BaseLayerTraceEntry") + const expected: HierarchyTreeNode = new HierarchyTreeBuilder().setName("BaseLayerTraceEntry").setKind("entry").setStableId("BaseLayerTraceEntry") .setChildren([ new HierarchyTreeBuilder().setName("Child1").setStableId("3 Child1").setKind("3").setChildren([ new HierarchyTreeBuilder().setName("Child2").setStableId("2 Child2").setKind("2").setId(2).setDiffType(DiffType.ADDED_MOVE).build() @@ -105,7 +110,7 @@ describe("TreeGenerator", () => { new HierarchyTreeBuilder().setName("Child2").setStableId("2 Child2").setKind("2").setId(2).setDiffType(DiffType.DELETED_MOVE).build() ]).setId(0).setDiffType(DiffType.NONE).build(); - const filter = getFilter(""); + const filter = TreeUtils.makeNodeFilter(""); const generator = new TreeGenerator(entry, filter); const newDiffTree = generator.withUniqueNodeId((node: any) => { if (node) return node.stableId; diff --git a/tools/winscope-ng/src/viewers/common/tree_generator.ts b/tools/winscope-ng/src/viewers/common/tree_generator.ts index 34f7af2e2..2ebaf174b 100644 --- a/tools/winscope-ng/src/viewers/common/tree_generator.ts +++ b/tools/winscope-ng/src/viewers/common/tree_generator.ts @@ -14,12 +14,11 @@ * limitations under the License. */ import { + TreeUtils, FilterType, - TreeFlickerItem, + TreeNodeTrace, DiffType, - isVisibleNode, - isParentNode, - HierarchyTree + HierarchyTreeNode } from "./tree_utils"; import ObjectFormatter from "common/trace/flickerlib/ObjectFormatter"; import { @@ -31,8 +30,8 @@ import { RELATIVE_Z_PARENT_CHIP } from "viewers/common/chip"; -type GetNodeIdCallbackType = (node: TreeFlickerItem | null) => string | null; -type IsModifiedCallbackType = (newTree: TreeFlickerItem | null, oldTree: TreeFlickerItem | null) => boolean; +type GetNodeIdCallbackType = (node: TreeNodeTrace | null) => string | null; +type IsModifiedCallbackType = (newTree: TreeNodeTrace | null, oldTree: TreeNodeTrace | null) => boolean; const HwcCompositionType = { CLIENT: 1, @@ -45,18 +44,18 @@ export class TreeGenerator { private isSimplifyNames = false; private isFlatView = false; private filter: FilterType; - private inputEntry: TreeFlickerItem; - private previousEntry: TreeFlickerItem | null = null; + private inputEntry: TreeNodeTrace; + private previousEntry: TreeNodeTrace | null = null; private getNodeId?: GetNodeIdCallbackType; private isModified?: IsModifiedCallbackType; - private newMapping: Map | null = null; - private oldMapping: Map | null = null; + private newMapping: Map | null = null; + private oldMapping: Map | null = null; private readonly pinnedIds: Array; - private pinnedItems: Array = []; + private pinnedItems: Array = []; private relZParentIds: Array = []; - private flattenedChildren: Array = []; + private flattenedChildren: Array = []; - constructor(inputEntry: TreeFlickerItem, filter: FilterType, pinnedIds?: Array) { + constructor(inputEntry: TreeNodeTrace, filter: FilterType, pinnedIds?: Array) { this.inputEntry = inputEntry; this.filter = filter; this.pinnedIds = pinnedIds ?? []; @@ -77,17 +76,17 @@ export class TreeGenerator { return this; } - public generateTree(): HierarchyTree | null { + public generateTree(): HierarchyTreeNode | null { return this.getCustomisedTree(this.inputEntry); } - public compareWith(previousEntry: TreeFlickerItem | null): TreeGenerator { + public compareWith(previousEntry: TreeNodeTrace | null): TreeGenerator { this.previousEntry = previousEntry; return this; } public withUniqueNodeId(getNodeId?: GetNodeIdCallbackType): TreeGenerator { - this.getNodeId = (node: TreeFlickerItem | null) => { + this.getNodeId = (node: TreeNodeTrace | null) => { const id = getNodeId ? getNodeId(node) : this.defaultNodeIdCallback(node); if (id === null || id === undefined) { console.error("Null node ID for node", node); @@ -103,17 +102,18 @@ export class TreeGenerator { return this; } - public generateFinalTreeWithDiff(): HierarchyTree | null { + public generateFinalTreeWithDiff(): HierarchyTreeNode | null { this.newMapping = this.generateIdToNodeMapping(this.inputEntry); this.oldMapping = this.previousEntry ? this.generateIdToNodeMapping(this.previousEntry) : null; const diffTrees = this.generateDiffTree(this.inputEntry, this.previousEntry, [], []); - let diffTree; + let diffTree: TreeNodeTrace; if (diffTrees.length > 1) { diffTree = { kind: "", name: "DiffTree", + parent: undefined, children: diffTrees, stableId: "DiffTree", }; @@ -123,7 +123,7 @@ export class TreeGenerator { return this.getCustomisedTree(diffTree); } - private getCustomisedTree(tree: TreeFlickerItem | null): HierarchyTree | null { + private getCustomisedTree(tree: TreeNodeTrace | null): HierarchyTreeNode | null { if (!tree) return null; let newTree = this.generateTreeWithUserOptions(tree, false); if (!newTree) return null; @@ -136,14 +136,14 @@ export class TreeGenerator { return Object.freeze(newTree); } - public getPinnedItems(): Array { + public getPinnedItems(): Array { return this.pinnedItems; } - private flattenChildren(children: Array) { + private flattenChildren(children: Array) { for (let i = 0; i < children.length; i++) { const child = children[i]; - const childIsVisibleNode = child.isVisible && isVisibleNode(child.kind, child.type); + const childIsVisibleNode = child.isVisible && TreeUtils.isVisibleNode(child.kind, child.type); const showInOnlyVisibleView = this.isOnlyVisibleView && childIsVisibleNode; const passVisibleCheck = !this.isOnlyVisibleView || showInOnlyVisibleView; if (this.filterMatches(child) && passVisibleCheck) { @@ -155,25 +155,25 @@ export class TreeGenerator { } } - private filterMatches(item: HierarchyTree | null): boolean { + private filterMatches(item: HierarchyTreeNode | null): boolean { return this.filter(item) ?? false; } private generateTreeWithUserOptions( - tree: TreeFlickerItem, + tree: TreeNodeTrace, parentFilterMatch: boolean - ): HierarchyTree | null { + ): HierarchyTreeNode | null { return this.applyChecks( tree, parentFilterMatch ); } - private updateTreeWithRelZParentChips(tree: HierarchyTree): HierarchyTree { + private updateTreeWithRelZParentChips(tree: HierarchyTreeNode): HierarchyTreeNode { return this.applyRelZParentCheck(tree); } - private applyRelZParentCheck(tree: HierarchyTree) { + private applyRelZParentCheck(tree: HierarchyTreeNode) { if (tree.id && tree.chips && this.relZParentIds.includes(`${tree.id}`)) { tree.chips.push(RELATIVE_Z_PARENT_CHIP); } @@ -186,7 +186,7 @@ export class TreeGenerator { return tree; } - private addChips(tree: HierarchyTree): HierarchyTree { + private addChips(tree: HierarchyTreeNode): HierarchyTreeNode { tree.chips = []; if (tree.hwcCompositionType == HwcCompositionType.CLIENT) { tree.chips.push(GPU_CHIP); @@ -194,13 +194,13 @@ export class TreeGenerator { tree.hwcCompositionType == HwcCompositionType.SOLID_COLOR)) { tree.chips.push(HWC_CHIP); } - if (tree.isVisible && isVisibleNode(tree.kind, tree.type)) { + if (tree.isVisible && TreeUtils.isVisibleNode(tree.kind, tree.type)) { tree.chips.push(VISIBLE_CHIP); } if ( tree.zOrderRelativeOfId !== undefined && tree.zOrderRelativeOfId !== -1 - && !isParentNode(tree.kind) + && !TreeUtils.isParentNode(tree.kind) && !tree.isRootLayer ) { tree.chips.push(RELATIVE_Z_CHIP); @@ -213,9 +213,9 @@ export class TreeGenerator { } private applyChecks( - tree: TreeFlickerItem, + tree: TreeNodeTrace, parentFilterMatch: boolean - ): HierarchyTree | null { + ): HierarchyTreeNode | null { let newTree = this.getTreeNode(tree); // add id field to tree if id does not exist (e.g. for WM traces) @@ -227,7 +227,7 @@ export class TreeGenerator { newTree.simplifyNames = this.isSimplifyNames; // check item either matches filter, or has parents/children matching filter - if (isParentNode(tree.kind) || parentFilterMatch) { + if (TreeUtils.isParentNode(tree.kind) || parentFilterMatch) { newTree.showInFilteredView = true; } else { newTree.showInFilteredView = this.filterMatches(tree); @@ -271,8 +271,8 @@ export class TreeGenerator { return newTree; } - private generateIdToNodeMapping(node: TreeFlickerItem, acc?: Map): Map { - acc = acc || new Map(); + private generateIdToNodeMapping(node: TreeNodeTrace, acc?: Map): Map { + acc = acc || new Map(); const nodeId: string = this.getNodeId!(node)!; @@ -289,7 +289,7 @@ export class TreeGenerator { return acc; } - private cloneDiffTreeNode(node: TreeFlickerItem | null): TreeFlickerItem | null { + private cloneDiffTreeNode(node: TreeNodeTrace | null): TreeNodeTrace | null { const clone = ObjectFormatter.cloneObject(node); if (node) { clone.children = node.children; @@ -304,8 +304,8 @@ export class TreeGenerator { return clone; } - private getTreeNode(node: TreeFlickerItem): HierarchyTree { - const clone = new HierarchyTree( + private getTreeNode(node: TreeNodeTrace): HierarchyTreeNode { + const clone = new HierarchyTreeNode( node.name, node.kind, node.stableId, @@ -327,11 +327,11 @@ export class TreeGenerator { } private generateDiffTree( - newTree: TreeFlickerItem | null, - oldTree: TreeFlickerItem | null, - newTreeSiblings: Array, - oldTreeSiblings: Array - ): Array { + newTree: TreeNodeTrace | null, + oldTree: TreeNodeTrace | null, + newTreeSiblings: Array, + oldTreeSiblings: Array + ): Array { const diffTrees = []; // NOTE: A null ID represents a non existent node. if (!this.getNodeId) { @@ -350,9 +350,9 @@ export class TreeGenerator { // Default to no changes diffTree.diffType = DiffType.NONE; - if (!isParentNode(newTree.kind) && newId !== oldId) { + if (!TreeUtils.isParentNode(newTree.kind) && newId !== oldId) { // A move, addition, or deletion has occurred - let nextOldTree: TreeFlickerItem | null = null; + let nextOldTree: TreeNodeTrace | null = null; // Check if newTree has been added or moved if (newId && !oldTreeSiblingIds.includes(newId)) { @@ -422,7 +422,7 @@ export class TreeGenerator { return diffTrees; } - private visitChildren(newTree: TreeFlickerItem | null, oldTree: TreeFlickerItem | null): Array { + private visitChildren(newTree: TreeNodeTrace | null, oldTree: TreeNodeTrace | null): Array { // Recursively traverse all children of new and old tree. const diffChildren = []; const numOfChildren = Math.max(newTree?.children?.length ?? 0, oldTree?.children?.length ?? 0); @@ -440,14 +440,14 @@ export class TreeGenerator { return diffChildren; } - private defaultNodeIdCallback(node: TreeFlickerItem | null): string | null { + private defaultNodeIdCallback(node: TreeNodeTrace | null): string | null { return node ? node.stableId : null; } - private defaultModifiedCheck(newNode: TreeFlickerItem | null, oldNode: TreeFlickerItem | null): boolean { + private defaultModifiedCheck(newNode: TreeNodeTrace | null, oldNode: TreeNodeTrace | null): boolean { if (!newNode && !oldNode) { return false; - } else if (newNode && isParentNode(newNode.kind)) { + } else if (newNode && TreeUtils.isParentNode(newNode.kind)) { return false; } else if ((newNode && !oldNode) || (!newNode && oldNode)) { return true; diff --git a/tools/winscope-ng/src/viewers/common/tree_transformer.spec.ts b/tools/winscope-ng/src/viewers/common/tree_transformer.spec.ts index ea57d7c77..f72b671bf 100644 --- a/tools/winscope-ng/src/viewers/common/tree_transformer.spec.ts +++ b/tools/winscope-ng/src/viewers/common/tree_transformer.spec.ts @@ -14,11 +14,11 @@ * limitations under the License. */ import { TreeTransformer } from "viewers/common/tree_transformer"; -import { DiffType, getFilter, HierarchyTree, Terminal, TreeFlickerItem } from "viewers/common/tree_utils"; +import { TreeUtils, DiffType, HierarchyTreeNode, Terminal, TreeNodeTrace } from "viewers/common/tree_utils"; describe("TreeTransformer", () => { - let entry: TreeFlickerItem; - let selectedTree: HierarchyTree; + let entry: TreeNodeTrace; + let selectedTree: HierarchyTreeNode; beforeAll(async () => { entry = { id: 3, @@ -34,10 +34,12 @@ describe("TreeTransformer", () => { type: "ContainerLayer", }, chips: [], + parent: undefined, children: [{ id: 2, name: "Child2", stackId: 0, + parent: undefined, children: [], kind: "2", stableId: "2 Child2", @@ -104,7 +106,7 @@ describe("TreeTransformer", () => { propertyValue: null }; - const filter = getFilter(""); + const filter = TreeUtils.makeNodeFilter(""); const transformer = new TreeTransformer(selectedTree, filter) .showOnlyProtoDump() .setProperties(entry); @@ -145,7 +147,7 @@ describe("TreeTransformer", () => { propertyValue: null, }; - const filter = getFilter(""); + const filter = TreeUtils.makeNodeFilter(""); const transformer = new TreeTransformer(selectedTree, filter) .setIsShowDiff(true) .showOnlyProtoDump() diff --git a/tools/winscope-ng/src/viewers/common/tree_transformer.ts b/tools/winscope-ng/src/viewers/common/tree_transformer.ts index 9592e3541..90c9a2414 100644 --- a/tools/winscope-ng/src/viewers/common/tree_transformer.ts +++ b/tools/winscope-ng/src/viewers/common/tree_transformer.ts @@ -17,11 +17,11 @@ import ObjectFormatter from "common/trace/flickerlib/ObjectFormatter"; import { FilterType, - PropertiesTree, + PropertiesTreeNode, DiffType, Terminal, - TreeFlickerItem, - HierarchyTree, + TreeNodeTrace, + HierarchyTreeNode, PropertiesDump } from "./tree_utils"; @@ -49,7 +49,7 @@ export class TreeTransformer { keepOriginal: false, freeze: true, metadataKey: null, }; - constructor(selectedTree: HierarchyTree, filter: FilterType) { + constructor(selectedTree: HierarchyTreeNode, filter: FilterType) { this.stableId = this.compatibleStableId(selectedTree); this.rootName = selectedTree.name; this.filter = filter; @@ -79,7 +79,7 @@ export class TreeTransformer { return this; } - public setProperties(currentEntry: TreeFlickerItem): TreeTransformer { + public setProperties(currentEntry: TreeNodeTrace): TreeTransformer { const currFlickerItem = this.getOriginalFlickerItem(currentEntry, this.stableId); const target = currFlickerItem ? currFlickerItem.obj ?? currFlickerItem : null; ObjectFormatter.displayDefaults = this.isShowDefaults; @@ -87,7 +87,7 @@ export class TreeTransformer { return this; } - public setDiffProperties(previousEntry: TreeFlickerItem | null): TreeTransformer { + public setDiffProperties(previousEntry: TreeNodeTrace | null): TreeTransformer { if (this.isShowDiff) { const prevFlickerItem = this.findFlickerItem(previousEntry, this.stableId); const target = prevFlickerItem ? prevFlickerItem.obj ?? prevFlickerItem : null; @@ -96,11 +96,11 @@ export class TreeTransformer { return this; } - public getOriginalFlickerItem(entry: TreeFlickerItem, stableId: string): TreeFlickerItem | null { + public getOriginalFlickerItem(entry: TreeNodeTrace, stableId: string): TreeNodeTrace | null { return this.findFlickerItem(entry, stableId); } - private getProtoDumpPropertiesForDisplay(entry: TreeFlickerItem): PropertiesDump | null { + private getProtoDumpPropertiesForDisplay(entry: TreeNodeTrace): PropertiesDump | null { if (!entry) { return null; } @@ -120,7 +120,7 @@ export class TreeTransformer { return obj; } - private getPropertiesForDisplay(entry: TreeFlickerItem): PropertiesDump | null { + private getPropertiesForDisplay(entry: TreeNodeTrace): PropertiesDump | null { if (!entry) { return null; } @@ -155,7 +155,7 @@ export class TreeTransformer { return obj; } - private findFlickerItem(entryFlickerItem: TreeFlickerItem | null, stableId: string): TreeFlickerItem | null { + private findFlickerItem(entryFlickerItem: TreeNodeTrace | null, stableId: string): TreeNodeTrace | null { if (!entryFlickerItem) { return null; } @@ -179,7 +179,7 @@ export class TreeTransformer { } - public transform(): PropertiesTree { + public transform(): PropertiesTreeNode { const {formatter} = this.options!; if (!formatter) { throw new Error("Missing formatter, please set with setOptions()"); @@ -198,7 +198,7 @@ export class TreeTransformer { compareWithName: string | Terminal, stableId: string, transformOptions: TransformOptions, - ): PropertiesTree { + ): PropertiesTreeNode { const originalProperties = properties; const metadata = this.getMetadata( originalProperties, transformOptions.metadataKey @@ -305,7 +305,7 @@ export class TreeTransformer { return transformOptions.freeze ? Object.freeze(transformedProperties) : transformedProperties; } - private hasChildMatchingFilter(children: PropertiesTree[] | null | undefined): boolean { + private hasChildMatchingFilter(children: PropertiesTreeNode[] | null | undefined): boolean { if (!children || children.length === 0) return false; let match = false; @@ -350,9 +350,9 @@ export class TreeTransformer { return this.filter(item) ?? false; } - private transformProperties(properties: PropertiesDump, metadataKey: string | null): PropertiesTree { + private transformProperties(properties: PropertiesDump, metadataKey: string | null): PropertiesTreeNode { const {skip, formatter} = this.options!; - const transformedProperties: PropertiesTree = { + const transformedProperties: PropertiesTreeNode = { properties: {}, }; let formatted = undefined; @@ -399,7 +399,7 @@ export class TreeTransformer { } } - private compatibleStableId(item: HierarchyTree): string { + private compatibleStableId(item: HierarchyTreeNode): string { // For backwards compatibility // (the only item that doesn't have a unique stable ID in the tree) if (item.stableId === "winToken|-|") { diff --git a/tools/winscope-ng/src/viewers/common/tree_utils.ts b/tools/winscope-ng/src/viewers/common/tree_utils.ts index 9528c249e..35e1ebfcf 100644 --- a/tools/winscope-ng/src/viewers/common/tree_utils.ts +++ b/tools/winscope-ng/src/viewers/common/tree_utils.ts @@ -16,21 +16,49 @@ import Chip from "./chip"; -export type FilterType = (item: HierarchyTree | PropertiesTree | null) => boolean; +export type FilterType = (item: HierarchyTreeNode | PropertiesTreeNode | null) => boolean; -export type Tree = HierarchyTree | PropertiesTree; +export type UiTreeNode = HierarchyTreeNode | PropertiesTreeNode; -export class HierarchyTree { +export interface TreeNodeTrace { + parent: TreeNodeTrace|undefined; + children: TreeNodeTrace[]; + name: string; + kind: string; + stableId: string; + displays?: TreeNodeTrace[]; + windowStates?: TreeNodeTrace[]; + shortName?: string; + type?: string; + id?: string | number; + layerId?: number; + displayId?: number; + stackId?: number; + isVisible?: boolean; + isMissing?: boolean; + hwcCompositionType?: number; + zOrderRelativeOfId?: number; + isRootLayer?: boolean; + chips?: Chip[]; + diffType?: string; + skip?: any; + equals?: any; + obj?: any; + get?: any; + proto?: any; +} + +export class HierarchyTreeNode { constructor( public name: string, public kind: string, public stableId: string, - children?: HierarchyTree[] + children?: HierarchyTreeNode[] ) { this.children = children ?? []; } - children: HierarchyTree[]; + children: HierarchyTreeNode[]; shortName?: string; type?: string; id?: string | number; @@ -52,42 +80,15 @@ export class HierarchyTree { skip?: any; } -export interface TreeFlickerItem { - children: TreeFlickerItem[]; - name: string; - kind: string; - stableId: string; - displays?: TreeFlickerItem[]; - windowStates?: TreeFlickerItem[]; - shortName?: string; - type?: string; - id?: string | number; - layerId?: number; - displayId?: number; - stackId?: number; - isVisible?: boolean; - isMissing?: boolean; - hwcCompositionType?: number; - zOrderRelativeOfId?: number; - isRootLayer?: boolean; - chips?: Chip[]; - diffType?: string; - skip?: any; - equals?: any; - obj?: any; - get?: any; - proto?: any; -} - export interface PropertiesDump { [key: string]: any; } -export interface PropertiesTree { +export interface PropertiesTreeNode { properties?: any; kind?: string; stableId?: string; - children?: PropertiesTree[]; + children?: PropertiesTreeNode[]; propertyKey?: string | Terminal | null; propertyValue?: string | Terminal | null; name?: string | Terminal; @@ -106,46 +107,74 @@ export const DiffType = { export class Terminal {} -export function diffClass(item: Tree): string { - const diffType = item.diffType; - return diffType ?? ""; -} - -export function isHighlighted(item: Tree, highlightedItems: Array) { - return item instanceof HierarchyTree && highlightedItems.includes(`${item.id}`); -} - -export function getFilter(filterString: string): FilterType { - const filterStrings = filterString.split(","); - const positive: any[] = []; - const negative: any[] = []; - filterStrings.forEach((f) => { - f = f.trim(); - if (f.startsWith("!")) { - const regex = new RegExp(f.substring(1), "i"); - negative.push((s:any) => !regex.test(s)); - } else { - const regex = new RegExp(f, "i"); - positive.push((s:any) => regex.test(s)); +export class TreeUtils +{ + public static findDescendantNode(node: TreeNodeTrace, isTargetNode: FilterType): TreeNodeTrace|undefined { + if (isTargetNode(node)) { + return node; } - }); - const filter = (item: any) => { - if (item) { - const apply = (f:any) => f(`${item.name}`); - return (positive.length === 0 || positive.some(apply)) && - (negative.length === 0 || negative.every(apply)); + + for (const child of node.children) { + const target = this.findDescendantNode(child, isTargetNode); + if (target) { + return target; + } } - return false; - }; - return filter; -} -const parentNodeKinds = ["entry", "WindowManagerState"]; + return undefined; + } -export function isParentNode(kind: string) { - return parentNodeKinds.includes(kind); -} + public static findAncestorNode(node: TreeNodeTrace, isTargetNode: FilterType): TreeNodeTrace|undefined { + let ancestor = node.parent; -export function isVisibleNode(kind: string, type?: string) { - return kind === "WindowState" || kind === "Activity" || type?.includes("Layer"); + while (ancestor && !isTargetNode(ancestor)) { + ancestor = ancestor.parent; + } + + return ancestor; + } + + public static makeNodeFilter(filterString: string): FilterType { + const filterStrings = filterString.split(","); + const positive: any[] = []; + const negative: any[] = []; + filterStrings.forEach((f) => { + f = f.trim(); + if (f.startsWith("!")) { + const regex = new RegExp(f.substring(1), "i"); + negative.push((s: any) => !regex.test(s)); + } else { + const regex = new RegExp(f, "i"); + positive.push((s: any) => regex.test(s)); + } + }); + const filter = (item: any) => { + if (item) { + const apply = (f: any) => f(`${item.name}`); + return (positive.length === 0 || positive.some(apply)) && + (negative.length === 0 || negative.every(apply)); + } + return false; + }; + return filter; + } + + public static diffClass(item: UiTreeNode): string { + const diffType = item.diffType; + return diffType ?? ""; + } + + public static isHighlighted(item: UiTreeNode, highlightedItems: Array) { + return item instanceof HierarchyTreeNode && highlightedItems.includes(`${item.id}`); + } + + public static isVisibleNode(kind: string, type?: string) { + return kind === "WindowState" || kind === "Activity" || type?.includes("Layer"); + } + + public static isParentNode(kind: string) { + return this.PARENT_NODE_KINDS.includes(kind); + } + + private static readonly PARENT_NODE_KINDS = ["entry", "WindowManagerState"]; } diff --git a/tools/winscope-ng/src/viewers/components/hierarchy.component.spec.ts b/tools/winscope-ng/src/viewers/components/hierarchy.component.spec.ts index face16397..efd84682e 100644 --- a/tools/winscope-ng/src/viewers/components/hierarchy.component.spec.ts +++ b/tools/winscope-ng/src/viewers/components/hierarchy.component.spec.ts @@ -22,7 +22,7 @@ import { MatInputModule } from "@angular/material/input"; import { MatFormFieldModule } from "@angular/material/form-field"; import { MatCheckboxModule } from "@angular/material/checkbox"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; -import { HierarchyTree } from "viewers/common/tree_utils"; +import { HierarchyTreeNode } from "viewers/common/tree_utils"; import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder"; describe("HierarchyComponent", () => { diff --git a/tools/winscope-ng/src/viewers/components/hierarchy.component.ts b/tools/winscope-ng/src/viewers/components/hierarchy.component.ts index 6ee155bd0..988900d64 100644 --- a/tools/winscope-ng/src/viewers/components/hierarchy.component.ts +++ b/tools/winscope-ng/src/viewers/components/hierarchy.component.ts @@ -16,7 +16,7 @@ import { Component, Input, Inject, ElementRef } from "@angular/core"; import { UserOptions } from "viewers/common/user_options"; import { PersistentStore } from "common/persistent_store"; -import { HierarchyTree, diffClass, isHighlighted, Tree } from "viewers/common/tree_utils"; +import { TreeUtils, HierarchyTreeNode, UiTreeNode } from "viewers/common/tree_utils"; import { nodeStyles } from "viewers/components/styles/node.styles"; import { ViewerEvents } from "viewers/common/viewer_events"; import { TraceType } from "common/trace/trace_type"; @@ -147,13 +147,13 @@ import { TraceType } from "common/trace/trace_type"; export class HierarchyComponent { objectKeys = Object.keys; filterString = ""; - diffClass = diffClass; - isHighlighted = isHighlighted; + diffClass = TreeUtils.diffClass; + isHighlighted = TreeUtils.isHighlighted; - @Input() tree!: HierarchyTree | null; + @Input() tree!: HierarchyTreeNode | null; @Input() dependencies: Array = []; @Input() highlightedItems: Array = []; - @Input() pinnedItems: Array = []; + @Input() pinnedItems: Array = []; @Input() store!: PersistentStore; @Input() userOptions: UserOptions = {}; @@ -172,7 +172,7 @@ export class HierarchyComponent { }; } - public onPinnedNodeClick(event: MouseEvent, pinnedItem: HierarchyTree) { + public onPinnedNodeClick(event: MouseEvent, pinnedItem: HierarchyTreeNode) { event.preventDefault(); if (window.getSelection()?.type === "range") { return; @@ -211,8 +211,8 @@ export class HierarchyComponent { this.elementRef.nativeElement.dispatchEvent(event); } - public selectedTreeChange(item: Tree) { - if (!(item instanceof HierarchyTree)) { + public selectedTreeChange(item: UiTreeNode) { + if (!(item instanceof HierarchyTreeNode)) { return; } const event: CustomEvent = new CustomEvent( @@ -224,8 +224,8 @@ export class HierarchyComponent { this.elementRef.nativeElement.dispatchEvent(event); } - public pinnedItemChange(item: Tree) { - if (!(item instanceof HierarchyTree)) { + public pinnedItemChange(item: UiTreeNode) { + if (!(item instanceof HierarchyTreeNode)) { return; } const event: CustomEvent = new CustomEvent( diff --git a/tools/winscope-ng/src/viewers/components/properties.component.ts b/tools/winscope-ng/src/viewers/components/properties.component.ts index 68fdddd60..2fb128d54 100644 --- a/tools/winscope-ng/src/viewers/components/properties.component.ts +++ b/tools/winscope-ng/src/viewers/components/properties.component.ts @@ -16,7 +16,7 @@ import { Component, Input, Inject, ElementRef } from "@angular/core"; import { UserOptions } from "viewers/common/user_options"; import { ViewerEvents } from "viewers/common/viewer_events"; -import { PropertiesTree, Terminal, TreeFlickerItem } from "viewers/common/tree_utils"; +import { PropertiesTreeNode, Terminal, TreeNodeTrace } from "viewers/common/tree_utils"; @Component({ selector: "properties-view", @@ -134,8 +134,8 @@ export class PropertiesComponent { filterString = ""; @Input() userOptions: UserOptions = {}; - @Input() propertiesTree: PropertiesTree = {}; - @Input() selectedFlickerItem: TreeFlickerItem | null = null; + @Input() propertiesTree: PropertiesTreeNode = {}; + @Input() selectedFlickerItem: TreeNodeTrace | null = null; @Input() propertyGroups = false; constructor( diff --git a/tools/winscope-ng/src/viewers/components/tree.component.ts b/tools/winscope-ng/src/viewers/components/tree.component.ts index b0941e906..2bffa704d 100644 --- a/tools/winscope-ng/src/viewers/components/tree.component.ts +++ b/tools/winscope-ng/src/viewers/components/tree.component.ts @@ -16,7 +16,7 @@ import { Component, Inject, Input, Output, ElementRef, EventEmitter } from "@angular/core"; import { PersistentStore } from "common/persistent_store"; import { nodeStyles, treeNodeDataViewStyles } from "viewers/components/styles/node.styles"; -import { Tree, diffClass, isHighlighted, PropertiesTree, Terminal, isParentNode, HierarchyTree } from "viewers/common/tree_utils"; +import { TreeUtils, UiTreeNode, HierarchyTreeNode } from "viewers/common/tree_utils"; import { TraceType } from "common/trace/trace_type"; @Component({ @@ -77,17 +77,17 @@ import { TraceType } from "common/trace/trace_type"; }) export class TreeComponent { - diffClass = diffClass; - isHighlighted = isHighlighted; + diffClass = TreeUtils.diffClass; + isHighlighted = TreeUtils.isHighlighted; - @Input() item!: Tree; + @Input() item!: UiTreeNode; @Input() dependencies: Array = []; @Input() store!: PersistentStore; @Input() isFlattened? = false; @Input() isShaded? = false; @Input() initialDepth = 0; @Input() highlightedItems: Array = []; - @Input() pinnedItems?: Array = []; + @Input() pinnedItems?: Array = []; @Input() itemsClickable?: boolean; @Input() useGlobalCollapsedState?: boolean; @Input() isAlwaysCollapsed?: boolean; @@ -95,8 +95,8 @@ export class TreeComponent { @Input() isLeaf: (item: any) => boolean = (item: any) => !item.children || item.children.length === 0; @Output() highlightedItemChange = new EventEmitter(); - @Output() selectedTreeChange = new EventEmitter(); - @Output() pinnedItemChange = new EventEmitter(); + @Output() selectedTreeChange = new EventEmitter(); + @Output() pinnedItemChange = new EventEmitter(); @Output() hoverStart = new EventEmitter(); @Output() hoverEnd = new EventEmitter(); @@ -123,7 +123,7 @@ export class TreeComponent { } ngOnChanges() { - if (this.item instanceof HierarchyTree && isHighlighted(this.item, this.highlightedItems)) { + if (this.item instanceof HierarchyTreeNode && TreeUtils.isHighlighted(this.item, this.highlightedItems)) { this.selectedTreeChange.emit(this.item); } } @@ -159,7 +159,7 @@ export class TreeComponent { } private updateHighlightedItems() { - if (this.item instanceof HierarchyTree) { + if (this.item instanceof HierarchyTreeNode) { if (this.item && this.item.id) { this.highlightedItemChange.emit(`${this.item.id}`); } else if (!this.item.id) { @@ -169,7 +169,7 @@ export class TreeComponent { } public isPinned() { - if (this.item instanceof HierarchyTree) { + if (this.item instanceof HierarchyTreeNode) { return this.pinnedItems?.map(item => `${item.id}`).includes(`${this.item.id}`); } return false; @@ -179,11 +179,11 @@ export class TreeComponent { this.highlightedItemChange.emit(newId); } - public propagateNewPinnedItem(newPinnedItem: Tree) { + public propagateNewPinnedItem(newPinnedItem: UiTreeNode) { this.pinnedItemChange.emit(newPinnedItem); } - public propagateNewSelectedTree(newTree: Tree) { + public propagateNewSelectedTree(newTree: UiTreeNode) { this.selectedTreeChange.emit(newTree); } @@ -211,12 +211,12 @@ export class TreeComponent { return this.localCollapsedState; } - public children(): Tree[] { + public children(): UiTreeNode[] { return this.item.children ?? []; } public hasChildren() { - const isParentEntryInFlatView = isParentNode(this.item.kind ?? "") && this.isFlattened; + const isParentEntryInFlatView = TreeUtils.isParentNode(this.item.kind ?? "") && this.isFlattened; return (!this.isFlattened || isParentEntryInFlatView) && !this.isLeaf(this.item); } diff --git a/tools/winscope-ng/src/viewers/components/tree_node.component.ts b/tools/winscope-ng/src/viewers/components/tree_node.component.ts index fee32e573..c0520d9c9 100644 --- a/tools/winscope-ng/src/viewers/components/tree_node.component.ts +++ b/tools/winscope-ng/src/viewers/components/tree_node.component.ts @@ -15,7 +15,7 @@ */ import { Component, Input, Output, EventEmitter } from "@angular/core"; import { nodeInnerItemStyles } from "viewers/components/styles/node.styles"; -import { Tree, DiffType, isParentNode, HierarchyTree } from "viewers/common/tree_utils"; +import { TreeUtils, UiTreeNode, DiffType, HierarchyTreeNode } from "viewers/common/tree_utils"; @Component({ selector: "tree-node", @@ -76,7 +76,7 @@ import { Tree, DiffType, isParentNode, HierarchyTree } from "viewers/common/tree }) export class TreeNodeComponent { - @Input() item!: Tree; + @Input() item!: UiTreeNode; @Input() isLeaf?: boolean; @Input() flattened?: boolean; @Input() isCollapsed?: boolean; @@ -87,7 +87,7 @@ export class TreeNodeComponent { @Output() toggleTreeChange = new EventEmitter(); @Output() expandTreeChange = new EventEmitter(); - @Output() pinNodeChange = new EventEmitter(); + @Output() pinNodeChange = new EventEmitter(); collapseDiffClass = ""; @@ -96,11 +96,11 @@ export class TreeNodeComponent { } public isPropertiesTreeNode() { - return !(this.item instanceof HierarchyTree); + return !(this.item instanceof HierarchyTreeNode); } public showPinNodeIcon() { - return (!this.isPropertiesTreeNode() && !isParentNode(this.item.kind ?? "")) ?? false; + return (!this.isPropertiesTreeNode() && !TreeUtils.isParentNode(this.item.kind ?? "")) ?? false; } public toggleTree(event: MouseEvent) { @@ -148,7 +148,7 @@ export class TreeNodeComponent { return DiffType.MODIFIED; } - private getAllDiffTypesOfChildren(item: Tree) { + private getAllDiffTypesOfChildren(item: UiTreeNode) { if (!item.children) { return new Set(); } diff --git a/tools/winscope-ng/src/viewers/components/tree_node_data_view.component.ts b/tools/winscope-ng/src/viewers/components/tree_node_data_view.component.ts index 5ec6f929b..eced5445d 100644 --- a/tools/winscope-ng/src/viewers/components/tree_node_data_view.component.ts +++ b/tools/winscope-ng/src/viewers/components/tree_node_data_view.component.ts @@ -15,7 +15,7 @@ */ import { Component, Input } from "@angular/core"; import { treeNodeDataViewStyles } from "viewers/components/styles/tree_node_data_view.styles"; -import { Terminal, HierarchyTree, Tree } from "viewers/common/tree_utils"; +import { Terminal, HierarchyTreeNode, UiTreeNode } from "viewers/common/tree_utils"; import Chip from "viewers/common/chip"; @Component({ @@ -37,14 +37,14 @@ import Chip from "viewers/common/chip"; }) export class TreeNodeDataViewComponent { - @Input() item!: Tree; + @Input() item!: UiTreeNode; public chips() { - return (this.item instanceof HierarchyTree) ? this.item.chips : []; + return (this.item instanceof HierarchyTreeNode) ? this.item.chips : []; } public itemShortName() { - return (this.item instanceof HierarchyTree)? this.item.shortName : ""; + return (this.item instanceof HierarchyTreeNode)? this.item.shortName : ""; } public itemTooltip() { @@ -55,7 +55,7 @@ export class TreeNodeDataViewComponent { } public showShortName() { - return (this.item instanceof HierarchyTree) && this.item.simplifyNames && this.item.shortName !== this.item.name; + return (this.item instanceof HierarchyTreeNode) && this.item.simplifyNames && this.item.shortName !== this.item.name; } public chipClass(chip: Chip) { diff --git a/tools/winscope-ng/src/viewers/components/tree_node_properties_data_view.component.ts b/tools/winscope-ng/src/viewers/components/tree_node_properties_data_view.component.ts index 0867981b4..fc04ad876 100644 --- a/tools/winscope-ng/src/viewers/components/tree_node_properties_data_view.component.ts +++ b/tools/winscope-ng/src/viewers/components/tree_node_properties_data_view.component.ts @@ -15,7 +15,7 @@ */ import { Component, Input } from "@angular/core"; import { treeNodePropertiesDataViewStyles } from "viewers/components/styles/tree_node_data_view.styles"; -import { PropertiesTree } from "viewers/common/tree_utils"; +import { PropertiesTreeNode } from "viewers/common/tree_utils"; @Component({ selector: "tree-node-properties-data-view", @@ -30,7 +30,7 @@ import { PropertiesTree } from "viewers/common/tree_utils"; }) export class TreeNodePropertiesDataViewComponent { - @Input() item!: PropertiesTree; + @Input() item!: PropertiesTreeNode; public valueClass() { if (!this.item.propertyValue) { diff --git a/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.spec.ts b/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.spec.ts index cbbc52712..28244f739 100644 --- a/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.spec.ts +++ b/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.spec.ts @@ -18,7 +18,7 @@ import { UiData } from "./ui_data"; import { UserOptions } from "viewers/common/user_options"; import { TraceType } from "common/trace/trace_type"; import { LayerTraceEntry } from "common/trace/flickerlib/common"; -import { HierarchyTree, PropertiesTree } from "viewers/common/tree_utils"; +import { HierarchyTreeNode, PropertiesTreeNode } from "viewers/common/tree_utils"; import { UnitTestUtils } from "test/unit/utils"; import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder"; @@ -26,7 +26,7 @@ describe("PresenterSurfaceFlinger", () => { let presenter: Presenter; let uiData: UiData; let entries: Map; - let selectedTree: HierarchyTree; + let selectedTree: HierarchyTreeNode; beforeAll(async () => { entries = new Map(); @@ -182,14 +182,14 @@ describe("PresenterSurfaceFlinger", () => { presenter.notifyCurrentTraceEntries(entries); presenter.newPropertiesTree(selectedTree); let nonTerminalChildren = uiData.propertiesTree?.children?.filter( - (child: PropertiesTree) => typeof child.propertyKey === "string" + (child: PropertiesTreeNode) => typeof child.propertyKey === "string" ) ?? []; expect(nonTerminalChildren.length).toEqual(55); presenter.filterPropertiesTree("bound"); nonTerminalChildren = uiData.propertiesTree?.children?.filter( - (child: PropertiesTree) => typeof child.propertyKey === "string" + (child: PropertiesTreeNode) => typeof child.propertyKey === "string" ) ?? []; expect(nonTerminalChildren.length).toEqual(3); }); diff --git a/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.ts b/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.ts index 9b59740ea..04b332c4e 100644 --- a/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.ts +++ b/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.ts @@ -18,7 +18,7 @@ import { UiData } from "./ui_data"; import { Rectangle, RectMatrix, RectTransform } from "viewers/common/rectangle"; import { TraceType } from "common/trace/trace_type"; import { UserOptions } from "viewers/common/user_options"; -import { getFilter, FilterType, HierarchyTree, Tree, TreeFlickerItem, PropertiesTree } from "viewers/common/tree_utils"; +import { TreeUtils, FilterType, HierarchyTreeNode, PropertiesTreeNode } from "viewers/common/tree_utils"; import { TreeGenerator } from "viewers/common/tree_generator"; import { TreeTransformer } from "viewers/common/tree_transformer"; import { Layer, LayerTraceEntry } from "common/trace/flickerlib/common"; @@ -32,7 +32,7 @@ export class Presenter { this.notifyViewCallback(this.uiData); } - public updatePinnedItems(pinnedItem: HierarchyTree) { + 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); @@ -63,7 +63,7 @@ export class Presenter { } public filterHierarchyTree(filterString: string) { - this.hierarchyFilter = getFilter(filterString); + this.hierarchyFilter = TreeUtils.makeNodeFilter(filterString); this.uiData.tree = this.generateTree(); this.notifyViewCallback(this.uiData); } @@ -75,11 +75,11 @@ export class Presenter { } public filterPropertiesTree(filterString: string) { - this.propertiesFilter = getFilter(filterString); + this.propertiesFilter = TreeUtils.makeNodeFilter(filterString); this.updateSelectedTreeUiData(); } - public newPropertiesTree(selectedItem: HierarchyTree) { + public newPropertiesTree(selectedItem: HierarchyTreeNode) { this.selectedHierarchyTree = selectedItem; this.updateSelectedTreeUiData(); } @@ -145,7 +145,7 @@ export class Presenter { .setIsSimplifyNames(this.hierarchyUserOptions["simplifyNames"]?.enabled) .setIsFlatView(this.hierarchyUserOptions["flat"]?.enabled) .withUniqueNodeId(); - let tree: HierarchyTree | null; + let tree: HierarchyTreeNode | null; if (!this.hierarchyUserOptions["showDiff"]?.enabled) { tree = generator.generateTree(); } else { @@ -210,7 +210,7 @@ export class Presenter { } } - private getTreeWithTransformedProperties(selectedTree: HierarchyTree): PropertiesTree { + private getTreeWithTransformedProperties(selectedTree: HierarchyTreeNode): PropertiesTreeNode { const transformer = new TreeTransformer(selectedTree, this.propertiesFilter) .showOnlyProtoDump() .setIsShowDefaults(this.propertiesUserOptions["showDefaults"]?.enabled) @@ -225,13 +225,13 @@ export class Presenter { private readonly notifyViewCallback: NotifyViewCallbackType; private uiData: UiData; - private hierarchyFilter: FilterType = getFilter(""); - private propertiesFilter: FilterType = getFilter(""); + private hierarchyFilter: FilterType = TreeUtils.makeNodeFilter(""); + private propertiesFilter: FilterType = TreeUtils.makeNodeFilter(""); private highlightedItems: Array = []; private displayIds: Array = []; - private pinnedItems: Array = []; + private pinnedItems: Array = []; private pinnedIds: Array = []; - private selectedHierarchyTree: HierarchyTree | null = null; + private selectedHierarchyTree: HierarchyTreeNode | null = null; private selectedLayer: LayerTraceEntry | Layer | null = null; private previousEntry: LayerTraceEntry | null = null; private entry: LayerTraceEntry | null = null; diff --git a/tools/winscope-ng/src/viewers/viewer_surface_flinger/ui_data.ts b/tools/winscope-ng/src/viewers/viewer_surface_flinger/ui_data.ts index 0039fe774..fc93c67a0 100644 --- a/tools/winscope-ng/src/viewers/viewer_surface_flinger/ui_data.ts +++ b/tools/winscope-ng/src/viewers/viewer_surface_flinger/ui_data.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { HierarchyTree, PropertiesTree } from "viewers/common/tree_utils"; +import { HierarchyTreeNode, PropertiesTreeNode } from "viewers/common/tree_utils"; import { UserOptions } from "viewers/common/user_options"; import { Layer } from "common/trace/flickerlib/common"; import { TraceType } from "common/trace/trace_type"; @@ -25,10 +25,10 @@ export class UiData { displayIds: number[] = []; hasVirtualDisplays = false; highlightedItems: Array = []; - pinnedItems: Array = []; + pinnedItems: Array = []; hierarchyUserOptions: UserOptions = {}; propertiesUserOptions: UserOptions = {}; - tree: HierarchyTree | null = null; - propertiesTree: PropertiesTree | null = null; + tree: HierarchyTreeNode | null = null; + propertiesTree: PropertiesTreeNode | null = null; selectedLayer: Layer = {}; } diff --git a/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.spec.ts b/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.spec.ts index c07055ed5..d3697d31c 100644 --- a/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.spec.ts +++ b/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.spec.ts @@ -1,4 +1,4 @@ -9;/* +/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,7 @@ import { UiData } from "./ui_data"; import { UserOptions } from "viewers/common/user_options"; import { TraceType } from "common/trace/trace_type"; import { WindowManagerState } from "common/trace/flickerlib/common"; -import { PropertiesTree, Terminal, HierarchyTree } from "viewers/common/tree_utils"; +import { PropertiesTreeNode, Terminal, HierarchyTreeNode } from "viewers/common/tree_utils"; import { UnitTestUtils } from "test/unit/utils"; import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder"; import { VISIBLE_CHIP } from "viewers/common/chip"; @@ -27,7 +27,7 @@ describe("PresenterWindowManager", () => { let presenter: Presenter; let uiData: UiData; let entries: Map; - let selectedTree: HierarchyTree; + let selectedTree: HierarchyTreeNode; beforeAll(async () => { entries = new Map(); @@ -187,14 +187,14 @@ describe("PresenterWindowManager", () => { presenter.newPropertiesTree(selectedTree); let nonTerminalChildren = uiData.propertiesTree?.children?.filter( - (child: PropertiesTree) => typeof child.propertyKey === "string" + (child: PropertiesTreeNode) => typeof child.propertyKey === "string" ) ?? []; expect(nonTerminalChildren.length).toEqual(45); presenter.filterPropertiesTree("visible"); nonTerminalChildren = uiData.propertiesTree?.children?.filter( - (child: PropertiesTree) => typeof child.propertyKey === "string" + (child: PropertiesTreeNode) => typeof child.propertyKey === "string" ) ?? []; expect(nonTerminalChildren.length).toEqual(4); }); diff --git a/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.ts b/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.ts index 3826a5936..632adb19d 100644 --- a/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.ts +++ b/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.ts @@ -17,7 +17,7 @@ import { UiData } from "./ui_data"; import { Rectangle, RectMatrix, RectTransform } from "viewers/common/rectangle"; import { TraceType } from "common/trace/trace_type"; import { UserOptions } from "viewers/common/user_options"; -import { getFilter, FilterType, Tree, HierarchyTree, PropertiesTree, TreeFlickerItem } from "viewers/common/tree_utils"; +import { TreeUtils, FilterType, HierarchyTreeNode, PropertiesTreeNode, TreeNodeTrace } from "viewers/common/tree_utils"; import { TreeGenerator } from "viewers/common/tree_generator"; import { TreeTransformer } from "viewers/common/tree_transformer"; import DisplayContent from "common/trace/flickerlib/windows/DisplayContent"; @@ -31,7 +31,7 @@ export class Presenter { this.notifyViewCallback(this.uiData); } - public updatePinnedItems(pinnedItem: HierarchyTree) { + 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); @@ -62,7 +62,7 @@ export class Presenter { } public filterHierarchyTree(filterString: string) { - this.hierarchyFilter = getFilter(filterString); + this.hierarchyFilter = TreeUtils.makeNodeFilter(filterString); this.uiData.tree = this.generateTree(); this.notifyViewCallback(this.uiData); } @@ -74,11 +74,11 @@ export class Presenter { } public filterPropertiesTree(filterString: string) { - this.propertiesFilter = getFilter(filterString); + this.propertiesFilter = TreeUtils.makeNodeFilter(filterString); this.updateSelectedTreeUiData(); } - public newPropertiesTree(selectedTree: HierarchyTree) { + public newPropertiesTree(selectedTree: HierarchyTreeNode) { this.selectedHierarchyTree = selectedTree; this.updateSelectedTreeUiData(); } @@ -143,7 +143,7 @@ export class Presenter { .setIsSimplifyNames(this.hierarchyUserOptions["simplifyNames"]?.enabled) .setIsFlatView(this.hierarchyUserOptions["flat"]?.enabled) .withUniqueNodeId(); - let tree: HierarchyTree | null; + let tree: HierarchyTreeNode | null; if (!this.hierarchyUserOptions["showDiff"]?.enabled) { tree = generator.generateTree(); } else { @@ -208,7 +208,7 @@ export class Presenter { } } - private getTreeWithTransformedProperties(selectedTree: HierarchyTree): PropertiesTree { + private getTreeWithTransformedProperties(selectedTree: HierarchyTreeNode): PropertiesTreeNode { if (!this.entry) { return {}; } @@ -225,15 +225,15 @@ export class Presenter { private readonly notifyViewCallback: NotifyViewCallbackType; private uiData: UiData; - private hierarchyFilter: FilterType = getFilter(""); - private propertiesFilter: FilterType = getFilter(""); + private hierarchyFilter: FilterType = TreeUtils.makeNodeFilter(""); + private propertiesFilter: FilterType = TreeUtils.makeNodeFilter(""); private highlightedItems: Array = []; private displayIds: Array = []; - private pinnedItems: Array = []; + private pinnedItems: Array = []; private pinnedIds: Array = []; - private selectedHierarchyTree: HierarchyTree | null = null; - private previousEntry: TreeFlickerItem | null = null; - private entry: TreeFlickerItem | null = null; + private selectedHierarchyTree: HierarchyTreeNode | null = null; + private previousEntry: TreeNodeTrace | null = null; + private entry: TreeNodeTrace | null = null; private hierarchyUserOptions: UserOptions = { showDiff: { name: "Show diff", diff --git a/tools/winscope-ng/src/viewers/viewer_window_manager/ui_data.ts b/tools/winscope-ng/src/viewers/viewer_window_manager/ui_data.ts index e4b0bfc54..cb0518291 100644 --- a/tools/winscope-ng/src/viewers/viewer_window_manager/ui_data.ts +++ b/tools/winscope-ng/src/viewers/viewer_window_manager/ui_data.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { HierarchyTree, PropertiesTree } from "viewers/common/tree_utils"; +import { HierarchyTreeNode, PropertiesTreeNode } from "viewers/common/tree_utils"; import { UserOptions } from "viewers/common/user_options"; import { TraceType } from "common/trace/trace_type"; import { Rectangle } from "viewers/common/rectangle"; @@ -23,9 +23,9 @@ export class UiData { rects: Rectangle[] = []; displayIds: number[] = []; highlightedItems: Array = []; - pinnedItems: Array = []; + pinnedItems: Array = []; hierarchyUserOptions: UserOptions = {}; propertiesUserOptions: UserOptions = {}; - tree: HierarchyTree | null = null; - propertiesTree: PropertiesTree | null = null; + tree: HierarchyTreeNode | null = null; + propertiesTree: PropertiesTreeNode | null = null; }