Refactor Tree Generator/Transformer.
Properly type all the tree utils. Bug: b/246498545 Test: npm run test:all Change-Id: I715e5b1cdc103fda228aac492e7d4c368601803c
This commit is contained in:
@@ -88,7 +88,7 @@ export default class ObjectFormatter {
|
||||
* @param obj The raw object to format
|
||||
* @return The formatted object
|
||||
*/
|
||||
static format(obj: any): {} {
|
||||
static format(obj: any): any {
|
||||
const properties = this.getProperties(obj);
|
||||
const sortedProperties = properties.sort()
|
||||
|
||||
|
||||
162
tools/winscope-ng/src/test/unit/hierarchy_tree_builder.ts
Normal file
162
tools/winscope-ng/src/test/unit/hierarchy_tree_builder.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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 { HierarchyTree } from "viewers/common/tree_utils";
|
||||
import Chip from "viewers/common/chip";
|
||||
|
||||
class HierarchyTreeBuilder {
|
||||
stableId = "";
|
||||
name = "";
|
||||
kind = "";
|
||||
children: HierarchyTree[] = [];
|
||||
shortName?: string;
|
||||
type?: string;
|
||||
id?: string | number;
|
||||
layerId?: number;
|
||||
displayId?: number;
|
||||
stackId?: number;
|
||||
isVisible?: boolean;
|
||||
isMissing?: boolean;
|
||||
hwcCompositionType?: number;
|
||||
zOrderRelativeOfId?: number;
|
||||
zOrderRelativeOf?: any;
|
||||
zOrderRelativeParentOf?: any;
|
||||
isRootLayer?: boolean;
|
||||
showInFilteredView = true;
|
||||
showInOnlyVisibleView?: boolean;
|
||||
simplifyNames = false;
|
||||
chips: Chip[] = [];
|
||||
diffType?: string;
|
||||
skip?: any;
|
||||
|
||||
setId(id: number) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
setKind(kind: string) {
|
||||
this.kind = kind;
|
||||
return this;
|
||||
}
|
||||
|
||||
setStableId(stableId: string) {
|
||||
this.stableId = stableId;
|
||||
return this;
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
setShortName(shortName: string) {
|
||||
this.shortName = shortName;
|
||||
return this;
|
||||
}
|
||||
|
||||
setChips(chips: Chip[]) {
|
||||
this.chips = chips;
|
||||
return this;
|
||||
}
|
||||
|
||||
setDiffType(diffType: string) {
|
||||
this.diffType = diffType;
|
||||
return this;
|
||||
}
|
||||
|
||||
setChildren(children: HierarchyTree[]) {
|
||||
this.children = children;
|
||||
return this;
|
||||
}
|
||||
|
||||
setDisplayId(displayId: number) {
|
||||
this.displayId = displayId;
|
||||
return this;
|
||||
}
|
||||
|
||||
setLayerId(layerId: number) {
|
||||
this.layerId = layerId;
|
||||
return this;
|
||||
}
|
||||
|
||||
setStackId(stackId: number) {
|
||||
this.stackId = stackId;
|
||||
return this;
|
||||
}
|
||||
|
||||
setIsVisible(isVisible: boolean) {
|
||||
this.isVisible = isVisible;
|
||||
return this;
|
||||
}
|
||||
|
||||
setVisibleView(showInOnlyVisibleView: boolean) {
|
||||
this.showInOnlyVisibleView = showInOnlyVisibleView;
|
||||
return this;
|
||||
}
|
||||
|
||||
setFilteredView(showInFilteredView: boolean) {
|
||||
this.showInFilteredView = showInFilteredView;
|
||||
return this;
|
||||
}
|
||||
|
||||
setSimplifyNames(simplifyNames: boolean) {
|
||||
this.simplifyNames = simplifyNames;
|
||||
return this;
|
||||
}
|
||||
|
||||
build(): HierarchyTree {
|
||||
const node = new HierarchyTree(this.name, this.kind, this.stableId, this.children);
|
||||
|
||||
node.chips = this.chips;
|
||||
node.showInFilteredView = this.showInFilteredView;
|
||||
node.simplifyNames = this.simplifyNames;
|
||||
|
||||
if (this.id) {
|
||||
node.id = this.id;
|
||||
}
|
||||
|
||||
if (this.diffType) {
|
||||
node.diffType = this.diffType;
|
||||
}
|
||||
|
||||
if (this.displayId) {
|
||||
node.displayId = this.displayId;
|
||||
}
|
||||
|
||||
if (this.layerId) {
|
||||
node.layerId = this.layerId;
|
||||
}
|
||||
|
||||
if (this.stackId) {
|
||||
node.stackId = this.stackId;
|
||||
}
|
||||
|
||||
if (this.isVisible) {
|
||||
node.isVisible = this.isVisible;
|
||||
}
|
||||
|
||||
if (this.showInOnlyVisibleView) {
|
||||
node.showInOnlyVisibleView = this.showInOnlyVisibleView;
|
||||
}
|
||||
|
||||
if (this.shortName) {
|
||||
node.shortName = this.shortName;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
export {HierarchyTreeBuilder};
|
||||
@@ -13,237 +13,105 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { DiffType, getFilter } from "viewers/common/tree_utils";
|
||||
import { DiffType, getFilter, HierarchyTree, TreeFlickerItem } from "viewers/common/tree_utils";
|
||||
import { TreeGenerator } from "viewers/common/tree_generator";
|
||||
import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder";
|
||||
|
||||
describe("TreeGenerator", () => {
|
||||
it("generates tree", () => {
|
||||
const tree = {
|
||||
let entry: TreeFlickerItem;
|
||||
beforeAll(async () => {
|
||||
entry = {
|
||||
kind: "entry",
|
||||
name: "BaseLayerTraceEntry",
|
||||
shortName: "BLTE",
|
||||
stableId: "BaseLayerTraceEntry",
|
||||
id: 0,
|
||||
chips: [],
|
||||
children: [{
|
||||
kind: "3",
|
||||
id: "3",
|
||||
id: 3,
|
||||
name: "Child1",
|
||||
stableId: "3 Child1",
|
||||
children: [
|
||||
{
|
||||
kind: "2",
|
||||
id: "2",
|
||||
id: 2,
|
||||
name: "Child2",
|
||||
stableId: "2 Child2",
|
||||
children: []
|
||||
}
|
||||
]}]
|
||||
};
|
||||
const expected = {
|
||||
simplifyNames: false,
|
||||
name: "BaseLayerTraceEntry",
|
||||
id: 0,
|
||||
children: [
|
||||
{
|
||||
id: "3",
|
||||
name: "Child1",
|
||||
children: [{
|
||||
kind: "2",
|
||||
id: "2",
|
||||
name: "Child2",
|
||||
children: [],
|
||||
simplifyNames: false,
|
||||
showInFilteredView: true,
|
||||
stableId: undefined,
|
||||
shortName: undefined,
|
||||
chips: []
|
||||
}],
|
||||
kind: "3",
|
||||
simplifyNames: false,
|
||||
showInFilteredView: true,
|
||||
stableId: undefined,
|
||||
shortName: undefined,
|
||||
chips: [],
|
||||
}
|
||||
],
|
||||
kind: "entry",
|
||||
stableId: undefined,
|
||||
shortName: "BLTE",
|
||||
chips: [],
|
||||
showInFilteredView: true,
|
||||
};
|
||||
});
|
||||
it("generates tree", () => {
|
||||
const expected: HierarchyTree = 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 generator = new TreeGenerator(tree, filter);
|
||||
const generator = new TreeGenerator(entry, filter);
|
||||
expect(generator.generateTree()).toEqual(expected);
|
||||
});
|
||||
|
||||
it("generates diff tree with no diff", () => {
|
||||
const tree = {
|
||||
kind: "entry",
|
||||
name: "BaseLayerTraceEntry",
|
||||
shortName: "BLTE",
|
||||
stableId: "0",
|
||||
chips: [],
|
||||
id: 0,
|
||||
children: [{
|
||||
kind: "3",
|
||||
id: "3",
|
||||
stableId: "3",
|
||||
name: "Child1",
|
||||
children: [
|
||||
{
|
||||
kind: "2",
|
||||
id: "2",
|
||||
stableId: "2",
|
||||
name: "Child2",
|
||||
}
|
||||
]}]
|
||||
};
|
||||
const newTree = tree;
|
||||
const expected = {
|
||||
simplifyNames: false,
|
||||
name: "BaseLayerTraceEntry",
|
||||
id: 0,
|
||||
stableId: "0",
|
||||
children: [
|
||||
{
|
||||
id: "3",
|
||||
stableId: "3",
|
||||
name: "Child1",
|
||||
children: [{
|
||||
kind: "2",
|
||||
id: "2",
|
||||
name: "Child2",
|
||||
children: [],
|
||||
simplifyNames: false,
|
||||
showInFilteredView: true,
|
||||
stableId: "2",
|
||||
shortName: undefined,
|
||||
diffType: DiffType.NONE,
|
||||
chips: []
|
||||
}],
|
||||
kind: "3",
|
||||
shortName: undefined,
|
||||
simplifyNames: false,
|
||||
showInFilteredView: true,
|
||||
chips: [],
|
||||
diffType: DiffType.NONE
|
||||
}
|
||||
],
|
||||
kind: "entry",
|
||||
shortName: "BLTE",
|
||||
chips: [],
|
||||
diffType: DiffType.NONE,
|
||||
showInFilteredView: true,
|
||||
};
|
||||
const expected: HierarchyTree = 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 generator = new TreeGenerator(tree, filter);
|
||||
expect(generator.withUniqueNodeId((node: any) => {
|
||||
const tree = new TreeGenerator(entry, filter).withUniqueNodeId((node: any) => {
|
||||
if (node) return node.stableId;
|
||||
else return null;
|
||||
}).compareWith(newTree).generateFinalDiffTree()).toEqual(expected);
|
||||
}).compareWith(entry).generateFinalTreeWithDiff();
|
||||
expect(tree).toEqual(expected);
|
||||
});
|
||||
|
||||
it("generates diff tree with moved node", () => {
|
||||
const tree = {
|
||||
const prevEntry: TreeFlickerItem = {
|
||||
kind: "entry",
|
||||
name: "BaseLayerTraceEntry",
|
||||
shortName: "BLTE",
|
||||
stableId: "0",
|
||||
chips: [],
|
||||
id: 0,
|
||||
children: [{
|
||||
kind: "3",
|
||||
id: "3",
|
||||
stableId: "3",
|
||||
name: "Child1",
|
||||
children: [
|
||||
{
|
||||
kind: "2",
|
||||
id: "2",
|
||||
stableId: "2",
|
||||
name: "Child2",
|
||||
}
|
||||
]}]
|
||||
};
|
||||
const newTree = {
|
||||
kind: "entry",
|
||||
name: "BaseLayerTraceEntry",
|
||||
shortName: "BLTE",
|
||||
stableId: "0",
|
||||
stableId: "BaseLayerTraceEntry",
|
||||
chips: [],
|
||||
id: 0,
|
||||
|
||||
children: [
|
||||
{
|
||||
kind: "3",
|
||||
id: "3",
|
||||
stableId: "3",
|
||||
id: 3,
|
||||
stableId: "3 Child1",
|
||||
name: "Child1",
|
||||
children: []
|
||||
},
|
||||
{
|
||||
kind: "2",
|
||||
id: "2",
|
||||
stableId: "2",
|
||||
id: 2,
|
||||
stableId: "2 Child2",
|
||||
name: "Child2",
|
||||
children: [],
|
||||
}
|
||||
]
|
||||
};
|
||||
const expected = {
|
||||
simplifyNames: false,
|
||||
name: "BaseLayerTraceEntry",
|
||||
id: 0,
|
||||
stableId: "0",
|
||||
children: [
|
||||
{
|
||||
id: "3",
|
||||
stableId: "3",
|
||||
name: "Child1",
|
||||
children: [ {
|
||||
kind: "2",
|
||||
id: "2",
|
||||
name: "Child2",
|
||||
children: [],
|
||||
simplifyNames: false,
|
||||
showInFilteredView: true,
|
||||
stableId: "2",
|
||||
shortName: undefined,
|
||||
diffType: DiffType.ADDED_MOVE,
|
||||
chips: []
|
||||
}],
|
||||
kind: "3",
|
||||
shortName: undefined,
|
||||
simplifyNames: false,
|
||||
showInFilteredView: true,
|
||||
chips: [],
|
||||
diffType: DiffType.NONE
|
||||
},
|
||||
{
|
||||
kind: "2",
|
||||
id: "2",
|
||||
name: "Child2",
|
||||
children: [],
|
||||
simplifyNames: false,
|
||||
showInFilteredView: true,
|
||||
stableId: "2",
|
||||
shortName: undefined,
|
||||
chips: [],
|
||||
diffType: DiffType.DELETED_MOVE
|
||||
}
|
||||
],
|
||||
kind: "entry",
|
||||
shortName: "BLTE",
|
||||
chips: [],
|
||||
diffType: DiffType.NONE,
|
||||
showInFilteredView: true
|
||||
};
|
||||
|
||||
const expected: HierarchyTree = 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()
|
||||
]).setId(3).setDiffType(DiffType.NONE).build(),
|
||||
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 generator = new TreeGenerator(tree, filter);
|
||||
const generator = new TreeGenerator(entry, filter);
|
||||
const newDiffTree = generator.withUniqueNodeId((node: any) => {
|
||||
if (node) return node.stableId;
|
||||
else return null;
|
||||
}).compareWith(newTree).generateFinalDiffTree();
|
||||
}).compareWith(prevEntry).generateFinalTreeWithDiff();
|
||||
|
||||
expect(newDiffTree).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
*/
|
||||
import {
|
||||
FilterType,
|
||||
Tree,
|
||||
TreeFlickerItem,
|
||||
DiffType,
|
||||
isVisibleNode,
|
||||
isParentNode
|
||||
isParentNode,
|
||||
HierarchyTree
|
||||
} from "./tree_utils";
|
||||
import ObjectFormatter from "common/trace/flickerlib/ObjectFormatter";
|
||||
import {
|
||||
@@ -30,11 +31,9 @@ import {
|
||||
RELATIVE_Z_PARENT_CHIP
|
||||
} from "viewers/common/chip";
|
||||
|
||||
type GetNodeIdCallbackType = (node: Tree | null) => number | null;
|
||||
type IsModifiedCallbackType = (newTree: Tree | null, oldTree: Tree | null) => boolean;
|
||||
interface IdNodeMap {
|
||||
[key: string]: Tree
|
||||
}
|
||||
type GetNodeIdCallbackType = (node: TreeFlickerItem | null) => string | null;
|
||||
type IsModifiedCallbackType = (newTree: TreeFlickerItem | null, oldTree: TreeFlickerItem | null) => boolean;
|
||||
|
||||
const HwcCompositionType = {
|
||||
CLIENT: 1,
|
||||
DEVICE: 2,
|
||||
@@ -46,49 +45,49 @@ export class TreeGenerator {
|
||||
private isSimplifyNames = false;
|
||||
private isFlatView = false;
|
||||
private filter: FilterType;
|
||||
private tree: Tree;
|
||||
private diffWithTree: Tree | null = null;
|
||||
private inputEntry: TreeFlickerItem;
|
||||
private previousEntry: TreeFlickerItem | null = null;
|
||||
private getNodeId?: GetNodeIdCallbackType;
|
||||
private isModified?: IsModifiedCallbackType;
|
||||
private newMapping: IdNodeMap | null = null;
|
||||
private oldMapping: IdNodeMap | null = null;
|
||||
private newMapping: Map<string, TreeFlickerItem> | null = null;
|
||||
private oldMapping: Map<string, TreeFlickerItem> | null = null;
|
||||
private readonly pinnedIds: Array<string>;
|
||||
private pinnedItems: Array<Tree> = [];
|
||||
private relZParentIds: Array<number> = [];
|
||||
private flattenedChildren: Array<Tree> = [];
|
||||
private pinnedItems: Array<HierarchyTree> = [];
|
||||
private relZParentIds: Array<string> = [];
|
||||
private flattenedChildren: Array<HierarchyTree> = [];
|
||||
|
||||
constructor(tree: Tree, filter: FilterType, pinnedIds?: Array<string>) {
|
||||
this.tree = tree;
|
||||
constructor(inputEntry: TreeFlickerItem, filter: FilterType, pinnedIds?: Array<string>) {
|
||||
this.inputEntry = inputEntry;
|
||||
this.filter = filter;
|
||||
this.pinnedIds = pinnedIds ?? [];
|
||||
}
|
||||
|
||||
public setIsOnlyVisibleView(enabled: boolean) {
|
||||
public setIsOnlyVisibleView(enabled: boolean): TreeGenerator {
|
||||
this.isOnlyVisibleView = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setIsSimplifyNames(enabled: boolean) {
|
||||
public setIsSimplifyNames(enabled: boolean): TreeGenerator {
|
||||
this.isSimplifyNames = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setIsFlatView(enabled: boolean) {
|
||||
public setIsFlatView(enabled: boolean): TreeGenerator {
|
||||
this.isFlatView = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public generateTree(): Tree {
|
||||
return this.getCustomisedTree(this.tree);
|
||||
public generateTree(): HierarchyTree | null {
|
||||
return this.getCustomisedTree(this.inputEntry);
|
||||
}
|
||||
|
||||
public compareWith(tree: Tree | null): TreeGenerator {
|
||||
this.diffWithTree = tree;
|
||||
public compareWith(previousEntry: TreeFlickerItem | null): TreeGenerator {
|
||||
this.previousEntry = previousEntry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public withUniqueNodeId(getNodeId?: GetNodeIdCallbackType): TreeGenerator {
|
||||
this.getNodeId = (node: Tree | null) => {
|
||||
this.getNodeId = (node: TreeFlickerItem | null) => {
|
||||
const id = getNodeId ? getNodeId(node) : this.defaultNodeIdCallback(node);
|
||||
if (id === null || id === undefined) {
|
||||
console.error("Null node ID for node", node);
|
||||
@@ -104,11 +103,11 @@ export class TreeGenerator {
|
||||
return this;
|
||||
}
|
||||
|
||||
public generateFinalDiffTree(): Tree {
|
||||
this.newMapping = this.generateIdToNodeMapping(this.tree);
|
||||
this.oldMapping = this.diffWithTree ? this.generateIdToNodeMapping(this.diffWithTree) : null;
|
||||
public generateFinalTreeWithDiff(): HierarchyTree | null {
|
||||
this.newMapping = this.generateIdToNodeMapping(this.inputEntry);
|
||||
this.oldMapping = this.previousEntry ? this.generateIdToNodeMapping(this.previousEntry) : null;
|
||||
|
||||
const diffTrees = this.generateDiffTree(this.tree, this.diffWithTree, [], []);
|
||||
const diffTrees = this.generateDiffTree(this.inputEntry, this.previousEntry, [], []);
|
||||
|
||||
let diffTree;
|
||||
if (diffTrees.length > 1) {
|
||||
@@ -124,23 +123,24 @@ export class TreeGenerator {
|
||||
return this.getCustomisedTree(diffTree);
|
||||
}
|
||||
|
||||
private getCustomisedTree(tree: Tree | null) {
|
||||
private getCustomisedTree(tree: TreeFlickerItem | null): HierarchyTree | null {
|
||||
if (!tree) return null;
|
||||
tree = this.generateTreeWithUserOptions(tree, false);
|
||||
tree = this.updateTreeWithRelZParentChips(tree);
|
||||
let newTree = this.generateTreeWithUserOptions(tree, false);
|
||||
if (!newTree) return null;
|
||||
newTree = this.updateTreeWithRelZParentChips(newTree);
|
||||
|
||||
if (this.isFlatView && tree.children) {
|
||||
this.flattenChildren(tree.children);
|
||||
tree.children = this.flattenedChildren;
|
||||
if (this.isFlatView && newTree.children) {
|
||||
this.flattenChildren(newTree.children);
|
||||
newTree.children = this.flattenedChildren;
|
||||
}
|
||||
return Object.freeze(tree);
|
||||
return Object.freeze(newTree);
|
||||
}
|
||||
|
||||
public getPinnedItems() {
|
||||
public getPinnedItems(): Array<HierarchyTree> {
|
||||
return this.pinnedItems;
|
||||
}
|
||||
|
||||
private flattenChildren(children: Array<Tree>): Tree {
|
||||
private flattenChildren(children: Array<HierarchyTree>) {
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const child = children[i];
|
||||
const childIsVisibleNode = child.isVisible && isVisibleNode(child.kind, child.type);
|
||||
@@ -155,27 +155,26 @@ export class TreeGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
private filterMatches(item: Tree | null): boolean {
|
||||
private filterMatches(item: HierarchyTree | null): boolean {
|
||||
return this.filter(item) ?? false;
|
||||
}
|
||||
|
||||
private generateTreeWithUserOptions(
|
||||
tree: Tree | null,
|
||||
tree: TreeFlickerItem,
|
||||
parentFilterMatch: boolean
|
||||
): Tree | null {
|
||||
return tree ? this.applyChecks(
|
||||
): HierarchyTree | null {
|
||||
return this.applyChecks(
|
||||
tree,
|
||||
this.cloneNode(tree, true),
|
||||
parentFilterMatch
|
||||
) : null;
|
||||
);
|
||||
}
|
||||
|
||||
private updateTreeWithRelZParentChips(tree: Tree): Tree {
|
||||
private updateTreeWithRelZParentChips(tree: HierarchyTree): HierarchyTree {
|
||||
return this.applyRelZParentCheck(tree);
|
||||
}
|
||||
|
||||
private applyRelZParentCheck(tree: Tree) {
|
||||
if (this.relZParentIds.includes(tree.id)) {
|
||||
private applyRelZParentCheck(tree: HierarchyTree) {
|
||||
if (tree.id && tree.chips && this.relZParentIds.includes(`${tree.id}`)) {
|
||||
tree.chips.push(RELATIVE_Z_PARENT_CHIP);
|
||||
}
|
||||
|
||||
@@ -187,7 +186,7 @@ export class TreeGenerator {
|
||||
return tree;
|
||||
}
|
||||
|
||||
private addChips(tree: Tree) {
|
||||
private addChips(tree: HierarchyTree): HierarchyTree {
|
||||
tree.chips = [];
|
||||
if (tree.hwcCompositionType == HwcCompositionType.CLIENT) {
|
||||
tree.chips.push(GPU_CHIP);
|
||||
@@ -205,7 +204,7 @@ export class TreeGenerator {
|
||||
&& !tree.isRootLayer
|
||||
) {
|
||||
tree.chips.push(RELATIVE_Z_CHIP);
|
||||
this.relZParentIds.push(tree.zOrderRelativeOfId);
|
||||
this.relZParentIds.push(`${tree.zOrderRelativeOfId}`);
|
||||
}
|
||||
if (tree.isMissing) {
|
||||
tree.chips.push(MISSING_LAYER);
|
||||
@@ -214,16 +213,13 @@ export class TreeGenerator {
|
||||
}
|
||||
|
||||
private applyChecks(
|
||||
tree: Tree | null,
|
||||
newTree: Tree | null,
|
||||
tree: TreeFlickerItem,
|
||||
parentFilterMatch: boolean
|
||||
): Tree | null {
|
||||
if (!tree || !newTree) {
|
||||
return null;
|
||||
}
|
||||
): HierarchyTree | null {
|
||||
let newTree = this.getTreeNode(tree);
|
||||
|
||||
// add id field to tree if id does not exist (e.g. for WM traces)
|
||||
if (!newTree.id && newTree.layerId) {
|
||||
if (!newTree?.id && newTree?.layerId) {
|
||||
newTree.id = newTree.layerId;
|
||||
}
|
||||
|
||||
@@ -275,15 +271,15 @@ export class TreeGenerator {
|
||||
return newTree;
|
||||
}
|
||||
|
||||
private generateIdToNodeMapping(node: Tree, acc?: IdNodeMap): IdNodeMap {
|
||||
acc = acc || {};
|
||||
private generateIdToNodeMapping(node: TreeFlickerItem, acc?: Map<string, TreeFlickerItem>): Map<string, TreeFlickerItem> {
|
||||
acc = acc || new Map<string, TreeFlickerItem>();
|
||||
|
||||
const nodeId = this.getNodeId!(node)!;
|
||||
const nodeId: string = this.getNodeId!(node)!;
|
||||
|
||||
if (acc[nodeId]) {
|
||||
if (acc.get(nodeId)) {
|
||||
throw new Error(`Duplicate node id '${nodeId}' detected...`);
|
||||
}
|
||||
acc[nodeId] = node;
|
||||
acc.set(nodeId, node);
|
||||
|
||||
if (node.children) {
|
||||
for (const child of node.children) {
|
||||
@@ -293,7 +289,7 @@ export class TreeGenerator {
|
||||
return acc;
|
||||
}
|
||||
|
||||
private cloneNode(node: Tree | null, postDiff = false): Tree | null {
|
||||
private cloneDiffTreeNode(node: TreeFlickerItem | null): TreeFlickerItem | null {
|
||||
const clone = ObjectFormatter.cloneObject(node);
|
||||
if (node) {
|
||||
clone.children = node.children;
|
||||
@@ -301,22 +297,41 @@ export class TreeGenerator {
|
||||
clone.kind = node.kind;
|
||||
clone.stableId = node.stableId;
|
||||
clone.shortName = node.shortName;
|
||||
if ("chips" in node) {
|
||||
if (node.chips) {
|
||||
clone.chips = node.chips.slice();
|
||||
}
|
||||
if (postDiff && "diffType" in node) {
|
||||
clone.diffType = node.diffType;
|
||||
}
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
private getTreeNode(node: TreeFlickerItem): HierarchyTree {
|
||||
const clone = new HierarchyTree(
|
||||
node.name,
|
||||
node.kind,
|
||||
node.stableId,
|
||||
);
|
||||
if (node.shortName) clone.shortName = node.shortName;
|
||||
if (node.type) clone.type = node.type;
|
||||
if (node.id) clone.id = node.id;
|
||||
if (node.layerId) clone.layerId = node.layerId;
|
||||
if (node.isVisible) clone.isVisible = node.isVisible;
|
||||
if (node.isMissing) clone.isMissing = node.isMissing;
|
||||
if (node.hwcCompositionType) clone.hwcCompositionType = node.hwcCompositionType;
|
||||
if (node.zOrderRelativeOfId) clone.zOrderRelativeOfId = node.zOrderRelativeOfId;
|
||||
if (node.isRootLayer) clone.isRootLayer = node.isRootLayer;
|
||||
if (node.chips) clone.chips = node.chips.slice();
|
||||
if (node.diffType) clone.diffType = node.diffType;
|
||||
if (node.skip) clone.skip = node.skip;
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
private generateDiffTree(
|
||||
newTree: Tree | null,
|
||||
oldTree: Tree | null,
|
||||
newTreeSiblings: Array<Tree | null>,
|
||||
oldTreeSiblings: Array<Tree | null>
|
||||
): Array<Tree | null> {
|
||||
newTree: TreeFlickerItem | null,
|
||||
oldTree: TreeFlickerItem | null,
|
||||
newTreeSiblings: Array<TreeFlickerItem | null>,
|
||||
oldTreeSiblings: Array<TreeFlickerItem | null>
|
||||
): Array<TreeFlickerItem> {
|
||||
const diffTrees = [];
|
||||
// NOTE: A null ID represents a non existent node.
|
||||
if (!this.getNodeId) {
|
||||
@@ -330,24 +345,24 @@ export class TreeGenerator {
|
||||
|
||||
if (newTree) {
|
||||
// Clone is required because trees are frozen objects — we can't modify the original tree object.
|
||||
const diffTree = this.cloneNode(newTree)!;
|
||||
const diffTree = this.cloneDiffTreeNode(newTree)!;
|
||||
|
||||
// Default to no changes
|
||||
diffTree.diffType = DiffType.NONE;
|
||||
|
||||
if (!isParentNode(newTree.kind) && newId !== oldId) {
|
||||
// A move, addition, or deletion has occurred
|
||||
let nextOldTree = null;
|
||||
let nextOldTree: TreeFlickerItem | null = null;
|
||||
|
||||
// Check if newTree has been added or moved
|
||||
if (newId && !oldTreeSiblingIds.includes(newId)) {
|
||||
if (this.oldMapping && this.oldMapping[newId]) {
|
||||
if (this.oldMapping && this.oldMapping.get(newId)) {
|
||||
// Objected existed in old tree, so DELETED_MOVE will be/has been flagged and added to the
|
||||
// diffTree when visiting it in the oldTree.
|
||||
diffTree.diffType = DiffType.ADDED_MOVE;
|
||||
|
||||
// Switch out oldTree for new one to compare against
|
||||
nextOldTree = this.oldMapping[newId];
|
||||
nextOldTree = this.oldMapping.get(newId) ?? null;
|
||||
} else {
|
||||
diffTree.diffType = DiffType.ADDED;
|
||||
|
||||
@@ -358,9 +373,9 @@ export class TreeGenerator {
|
||||
|
||||
// Check if oldTree has been deleted of moved
|
||||
if (oldId && oldTree && !newTreeSiblingIds.includes(oldId)) {
|
||||
const deletedTreeDiff = this.cloneNode(oldTree)!;
|
||||
const deletedTreeDiff = this.cloneDiffTreeNode(oldTree)!;
|
||||
|
||||
if (this.newMapping![oldId]) {
|
||||
if (this.newMapping && this.newMapping.get(oldId)) {
|
||||
deletedTreeDiff.diffType = DiffType.DELETED_MOVE;
|
||||
|
||||
// Stop comparing against oldTree, will be/has been
|
||||
@@ -388,10 +403,10 @@ export class TreeGenerator {
|
||||
} else if (oldTree) {
|
||||
if (oldId && !newTreeSiblingIds.includes(oldId)) {
|
||||
// Deep clone oldTree omitting children field
|
||||
const diffTree = this.cloneNode(oldTree)!;
|
||||
const diffTree = this.cloneDiffTreeNode(oldTree)!;
|
||||
|
||||
// newTree doesn't exist, oldTree has either been moved or deleted.
|
||||
if (this.newMapping![oldId]) {
|
||||
if (this.newMapping && this.newMapping.get(oldId)) {
|
||||
diffTree.diffType = DiffType.DELETED_MOVE;
|
||||
} else {
|
||||
diffTree.diffType = DiffType.DELETED;
|
||||
@@ -407,39 +422,38 @@ export class TreeGenerator {
|
||||
return diffTrees;
|
||||
}
|
||||
|
||||
private visitChildren(newTree: Tree | null, oldTree: Tree | null) {
|
||||
private visitChildren(newTree: TreeFlickerItem | null, oldTree: TreeFlickerItem | null): Array<TreeFlickerItem> {
|
||||
// Recursively traverse all children of new and old tree.
|
||||
const diffChildren = [];
|
||||
|
||||
if (!newTree) newTree = {};
|
||||
if (!oldTree) oldTree = {};
|
||||
const numOfChildren = Math.max(newTree.children?.length ?? 0, oldTree.children?.length ?? 0);
|
||||
const numOfChildren = Math.max(newTree?.children?.length ?? 0, oldTree?.children?.length ?? 0);
|
||||
for (let i = 0; i < numOfChildren; i++) {
|
||||
const newChild = newTree.children ? newTree.children[i] : null;
|
||||
const oldChild = oldTree.children ? oldTree.children[i] : null;
|
||||
const newChild = newTree?.children ? newTree.children[i] : null;
|
||||
const oldChild = oldTree?.children ? oldTree.children[i] : null;
|
||||
|
||||
const childDiffTrees = this.generateDiffTree(
|
||||
newChild, oldChild,
|
||||
newTree.children ?? [], oldTree.children ?? [],
|
||||
);
|
||||
newTree?.children ?? [], oldTree?.children ?? [],
|
||||
).filter(tree => tree != null);
|
||||
diffChildren.push(...childDiffTrees);
|
||||
}
|
||||
|
||||
return diffChildren;
|
||||
}
|
||||
|
||||
private defaultNodeIdCallback(node: Tree | null): number | null {
|
||||
private defaultNodeIdCallback(node: TreeFlickerItem | null): string | null {
|
||||
return node ? node.stableId : null;
|
||||
}
|
||||
|
||||
private defaultModifiedCheck(newNode: Tree | null, oldNode: Tree | null): boolean {
|
||||
private defaultModifiedCheck(newNode: TreeFlickerItem | null, oldNode: TreeFlickerItem | null): boolean {
|
||||
if (!newNode && !oldNode) {
|
||||
return false;
|
||||
} else if (newNode && isParentNode(newNode.kind)) {
|
||||
return false;
|
||||
} else if ((newNode && !oldNode) || (!newNode && oldNode)) {
|
||||
return true;
|
||||
} else if (newNode?.equals) {
|
||||
return !newNode.equals(oldNode);
|
||||
}
|
||||
return !newNode.equals(oldNode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,21 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { TreeTransformer } from "viewers/common/tree_transformer";
|
||||
import { DiffType, getFilter, Terminal } from "viewers/common/tree_utils";
|
||||
import { DiffType, getFilter, HierarchyTree, Terminal, TreeFlickerItem } from "viewers/common/tree_utils";
|
||||
|
||||
describe("TreeTransformer", () => {
|
||||
it("creates ordinary properties tree without show diff enabled", () => {
|
||||
const selectedTree = {
|
||||
id: "3",
|
||||
let entry: TreeFlickerItem;
|
||||
let selectedTree: HierarchyTree;
|
||||
beforeAll(async () => {
|
||||
entry = {
|
||||
id: 3,
|
||||
name: "Child1",
|
||||
stackId: 0,
|
||||
isVisible: true,
|
||||
kind: "3",
|
||||
stableId: "3 Child1",
|
||||
shortName: undefined,
|
||||
simplifyNames: true,
|
||||
showInFilteredView: true,
|
||||
skip: null,
|
||||
proto: {
|
||||
barrierLayer: [],
|
||||
id: 3,
|
||||
@@ -37,14 +35,12 @@ describe("TreeTransformer", () => {
|
||||
},
|
||||
chips: [],
|
||||
children: [{
|
||||
id: "2",
|
||||
id: 2,
|
||||
name: "Child2",
|
||||
stackId: 0,
|
||||
children: [],
|
||||
kind: "2",
|
||||
stableId: "2 Child2",
|
||||
shortName: undefined,
|
||||
simplifyNames: true,
|
||||
proto: {
|
||||
barrierLayer: [],
|
||||
id: 2,
|
||||
@@ -52,10 +48,34 @@ describe("TreeTransformer", () => {
|
||||
type: "ContainerLayer",
|
||||
},
|
||||
isVisible: true,
|
||||
}],
|
||||
};
|
||||
|
||||
selectedTree = {
|
||||
id: 3,
|
||||
name: "Child1",
|
||||
stackId: 0,
|
||||
isVisible: true,
|
||||
kind: "3",
|
||||
stableId: "3 Child1",
|
||||
showInFilteredView: true,
|
||||
skip: null,
|
||||
chips: [],
|
||||
children: [{
|
||||
id: 2,
|
||||
name: "Child2",
|
||||
stackId: 0,
|
||||
children: [],
|
||||
kind: "2",
|
||||
stableId: "2 Child2",
|
||||
isVisible: true,
|
||||
showInFilteredView: true,
|
||||
chips: [],
|
||||
}],
|
||||
};
|
||||
});
|
||||
|
||||
it("creates ordinary properties tree without show diff enabled", () => {
|
||||
const expected = {
|
||||
kind: "",
|
||||
name: "Child1",
|
||||
@@ -63,88 +83,37 @@ describe("TreeTransformer", () => {
|
||||
children: [
|
||||
{
|
||||
kind: "",
|
||||
name: "proto",
|
||||
stableId: "3 Child1.proto",
|
||||
children: [
|
||||
{
|
||||
kind: "",
|
||||
name: "id: empty",
|
||||
stableId: "3 Child1.proto.id",
|
||||
children: [],
|
||||
combined: true,
|
||||
propertyKey: "id",
|
||||
propertyValue: "empty"},
|
||||
{
|
||||
kind: "",
|
||||
name: "type: ContainerLayer",
|
||||
stableId: "3 Child1.proto.type",
|
||||
children: [],
|
||||
combined: true,
|
||||
propertyKey: "type",
|
||||
propertyValue: "ContainerLayer"
|
||||
}
|
||||
],
|
||||
propertyKey: "proto",
|
||||
propertyValue: null,
|
||||
name: "id: empty",
|
||||
stableId: "3 Child1.id",
|
||||
children: [],
|
||||
combined: true,
|
||||
propertyKey: "id",
|
||||
propertyValue: "empty"
|
||||
},
|
||||
{
|
||||
kind: "",
|
||||
name: new Terminal(),
|
||||
stableId: "3 Child1.null",
|
||||
children: []
|
||||
}
|
||||
name: "type: ContainerLayer",
|
||||
stableId: "3 Child1.type",
|
||||
children: [],
|
||||
combined: true,
|
||||
propertyKey: "type",
|
||||
propertyValue: "ContainerLayer"
|
||||
},
|
||||
],
|
||||
propertyKey: "Child1",
|
||||
propertyValue: null
|
||||
};
|
||||
|
||||
const filter = getFilter("");
|
||||
const transformer = new TreeTransformer(selectedTree, filter);
|
||||
const transformer = new TreeTransformer(selectedTree, filter)
|
||||
.showOnlyProtoDump()
|
||||
.setProperties(entry);
|
||||
|
||||
const transformedTree = transformer.transform();
|
||||
|
||||
expect(transformedTree).toEqual(expected);
|
||||
});
|
||||
|
||||
it("creates properties tree with show diff enabled, comparing to a null previous entry", () => {
|
||||
const selectedTree = {
|
||||
id: "3",
|
||||
name: "Child1",
|
||||
stackId: 0,
|
||||
isVisible: true,
|
||||
kind: "3",
|
||||
stableId: "3 Child1",
|
||||
shortName: undefined,
|
||||
simplifyNames: true,
|
||||
showInFilteredView: true,
|
||||
skip: null,
|
||||
proto: {
|
||||
barrierLayer: [],
|
||||
id: 3,
|
||||
parent: 1,
|
||||
type: "ContainerLayer",
|
||||
},
|
||||
chips: [],
|
||||
children: [{
|
||||
id: "2",
|
||||
name: "Child2",
|
||||
stackId: 0,
|
||||
children: [],
|
||||
kind: "2",
|
||||
stableId: "2 Child2",
|
||||
shortName: undefined,
|
||||
simplifyNames: true,
|
||||
proto: {
|
||||
barrierLayer: [],
|
||||
id: 2,
|
||||
parent: 3,
|
||||
type: "ContainerLayer",
|
||||
},
|
||||
isVisible: true,
|
||||
showInFilteredView: true,
|
||||
chips: [],
|
||||
}],
|
||||
};
|
||||
const expected = {
|
||||
kind: "",
|
||||
name: "Child1",
|
||||
@@ -152,34 +121,24 @@ describe("TreeTransformer", () => {
|
||||
children: [
|
||||
{
|
||||
kind: "",
|
||||
name: "proto",
|
||||
stableId: "3 Child1.proto",
|
||||
children: [
|
||||
{
|
||||
kind: "",
|
||||
name: "id: empty",
|
||||
stableId: "3 Child1.proto.id",
|
||||
children: [],
|
||||
combined: true,
|
||||
diffType: DiffType.ADDED,
|
||||
propertyKey: "id",
|
||||
propertyValue: "empty",
|
||||
},
|
||||
{
|
||||
kind: "",
|
||||
name: "type: ContainerLayer",
|
||||
stableId: "3 Child1.proto.type",
|
||||
children: [],
|
||||
combined: true,
|
||||
diffType: DiffType.ADDED,
|
||||
propertyKey: "type",
|
||||
propertyValue: "ContainerLayer",
|
||||
}
|
||||
],
|
||||
name: "id: empty",
|
||||
diffType: DiffType.ADDED,
|
||||
propertyKey: "proto",
|
||||
propertyValue: null,
|
||||
}
|
||||
stableId: "3 Child1.id",
|
||||
children: [],
|
||||
combined: true,
|
||||
propertyKey: "id",
|
||||
propertyValue: "empty"
|
||||
},
|
||||
{
|
||||
kind: "",
|
||||
name: "type: ContainerLayer",
|
||||
diffType: DiffType.ADDED,
|
||||
stableId: "3 Child1.type",
|
||||
children: [],
|
||||
combined: true,
|
||||
propertyKey: "type",
|
||||
propertyValue: "ContainerLayer"
|
||||
},
|
||||
],
|
||||
diffType: DiffType.NONE,
|
||||
propertyKey: "Child1",
|
||||
@@ -189,6 +148,8 @@ describe("TreeTransformer", () => {
|
||||
const filter = getFilter("");
|
||||
const transformer = new TreeTransformer(selectedTree, filter)
|
||||
.setIsShowDiff(true)
|
||||
.showOnlyProtoDump()
|
||||
.setProperties(entry)
|
||||
.setDiffProperties(null);
|
||||
|
||||
const transformedTree = transformer.transform();
|
||||
|
||||
@@ -18,9 +18,11 @@ import ObjectFormatter from "common/trace/flickerlib/ObjectFormatter";
|
||||
import {
|
||||
FilterType,
|
||||
PropertiesTree,
|
||||
Tree,
|
||||
DiffType,
|
||||
Terminal
|
||||
Terminal,
|
||||
TreeFlickerItem,
|
||||
HierarchyTree,
|
||||
PropertiesDump
|
||||
} from "./tree_utils";
|
||||
|
||||
interface TransformOptions {
|
||||
@@ -32,10 +34,6 @@ interface TreeTransformerOptions {
|
||||
skip?: any;
|
||||
formatter?: any;
|
||||
}
|
||||
interface TransformedPropertiesObject {
|
||||
properties: any;
|
||||
diffType?: string;
|
||||
}
|
||||
|
||||
export class TreeTransformer {
|
||||
private stableId: string;
|
||||
@@ -43,32 +41,37 @@ export class TreeTransformer {
|
||||
private isShowDefaults = false;
|
||||
private isShowDiff = false;
|
||||
private filter: FilterType;
|
||||
private properties: PropertiesTree;
|
||||
private compareWithProperties: PropertiesTree | null = null;
|
||||
private properties: PropertiesDump | Terminal | null = null;
|
||||
private compareWithProperties: PropertiesDump | Terminal | null = null;
|
||||
private options?: TreeTransformerOptions;
|
||||
private onlyProtoDump = false;
|
||||
private transformOptions: TransformOptions = {
|
||||
keepOriginal: false, freeze: true, metadataKey: null,
|
||||
};
|
||||
|
||||
constructor(tree: Tree, filter: FilterType) {
|
||||
this.stableId = this.compatibleStableId(tree);
|
||||
this.rootName = tree.name;
|
||||
constructor(selectedTree: HierarchyTree, filter: FilterType) {
|
||||
this.stableId = this.compatibleStableId(selectedTree);
|
||||
this.rootName = selectedTree.name;
|
||||
this.filter = filter;
|
||||
this.setProperties(tree);
|
||||
this.setTransformerOptions({});
|
||||
}
|
||||
|
||||
public setIsShowDefaults(enabled: boolean) {
|
||||
public showOnlyProtoDump(): TreeTransformer {
|
||||
this.onlyProtoDump = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setIsShowDefaults(enabled: boolean): TreeTransformer {
|
||||
this.isShowDefaults = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setIsShowDiff(enabled: boolean) {
|
||||
public setIsShowDiff(enabled: boolean): TreeTransformer {
|
||||
this.isShowDiff = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setTransformerOptions(options: TreeTransformerOptions) {
|
||||
public setTransformerOptions(options: TreeTransformerOptions): TreeTransformer {
|
||||
this.options = options;
|
||||
if (!this.options.formatter) {
|
||||
this.options.formatter = this.formatProto;
|
||||
@@ -76,66 +79,97 @@ export class TreeTransformer {
|
||||
return this;
|
||||
}
|
||||
|
||||
public setProperties(tree: Tree) {
|
||||
const target = tree.obj ?? tree;
|
||||
public setProperties(currentEntry: TreeFlickerItem): TreeTransformer {
|
||||
const currFlickerItem = this.getOriginalFlickerItem(currentEntry, this.stableId);
|
||||
const target = currFlickerItem ? currFlickerItem.obj ?? currFlickerItem : null;
|
||||
ObjectFormatter.displayDefaults = this.isShowDefaults;
|
||||
this.properties = this.getPropertiesForDisplay(target);
|
||||
this.properties = this.onlyProtoDump ? this.getProtoDumpPropertiesForDisplay(target) : this.getPropertiesForDisplay(target);
|
||||
return this;
|
||||
}
|
||||
|
||||
public setDiffProperties(previousEntry: any) {
|
||||
public setDiffProperties(previousEntry: TreeFlickerItem | null): TreeTransformer {
|
||||
if (this.isShowDiff) {
|
||||
const tree = this.findTree(previousEntry, this.stableId);
|
||||
const target = tree ? tree.obj ?? tree : null;
|
||||
this.compareWithProperties = this.getPropertiesForDisplay(target);
|
||||
const prevFlickerItem = this.findFlickerItem(previousEntry, this.stableId);
|
||||
const target = prevFlickerItem ? prevFlickerItem.obj ?? prevFlickerItem : null;
|
||||
this.compareWithProperties = this.onlyProtoDump ? this.getProtoDumpPropertiesForDisplay(target) : this.getPropertiesForDisplay(target);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public getOriginalLayer(entry: any, stableId: string) {
|
||||
return this.findTree(entry, stableId);
|
||||
public getOriginalFlickerItem(entry: TreeFlickerItem, stableId: string): TreeFlickerItem | null {
|
||||
return this.findFlickerItem(entry, stableId);
|
||||
}
|
||||
|
||||
private getPropertiesForDisplay(entry: any): any {
|
||||
private getProtoDumpPropertiesForDisplay(entry: TreeFlickerItem): PropertiesDump | null {
|
||||
if (!entry) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let obj: any = {};
|
||||
obj.proto = Object.assign({}, entry.proto);
|
||||
if (obj.proto.children) delete obj.proto.children;
|
||||
if (obj.proto.childWindows) delete obj.proto.childWindows;
|
||||
if (obj.proto.childrenWindows) delete obj.proto.childrenWindows;
|
||||
if (obj.proto.childContainers) delete obj.proto.childContainers;
|
||||
if (obj.proto.windowToken) delete obj.proto.windowToken;
|
||||
if (obj.proto.rootDisplayArea) delete obj.proto.rootDisplayArea;
|
||||
if (obj.proto.rootWindowContainer) delete obj.proto.rootWindowContainer;
|
||||
if (obj.proto.windowContainer?.children) delete obj.proto.windowContainer.children;
|
||||
const obj: PropertiesDump = {};
|
||||
const proto = ObjectFormatter.format(entry.proto);
|
||||
if (proto) {
|
||||
Object.keys(proto).forEach((prop: string) => {
|
||||
obj[prop] = proto[prop] ?? "empty";
|
||||
|
||||
obj = ObjectFormatter.format(obj);
|
||||
if (Object.keys(obj[prop]).length === 0) {
|
||||
obj[prop]= "empty";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Object.keys(obj.proto).forEach((prop: string) => {
|
||||
if (Object.keys(obj.proto[prop]).length === 0) {
|
||||
obj.proto[prop] = "empty";
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
private findTree(tree: any, stableId: string) {
|
||||
if (!tree) {
|
||||
private getPropertiesForDisplay(entry: TreeFlickerItem): PropertiesDump | null {
|
||||
if (!entry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (tree.stableId && tree.stableId === stableId) {
|
||||
return tree;
|
||||
}
|
||||
let obj: PropertiesDump = {};
|
||||
|
||||
if (!tree.children) {
|
||||
const properties = ObjectFormatter.getProperties(entry);
|
||||
properties.forEach(prop => {
|
||||
if (entry.get) obj[prop] = entry.get(prop);
|
||||
});
|
||||
if (obj["children"]) delete obj["children"];
|
||||
if (obj["proto"]) delete obj["proto"];
|
||||
|
||||
obj["proto"] = Object.assign({}, entry.proto);
|
||||
if (obj["proto"].children) delete obj["proto"].children;
|
||||
if (obj["proto"].childWindows) delete obj["proto"].childWindows;
|
||||
if (obj["proto"].childrenWindows) delete obj["proto"].childrenWindows;
|
||||
if (obj["proto"].childContainers) delete obj["proto"].childContainers;
|
||||
if (obj["proto"].windowToken) delete obj["proto"].windowToken;
|
||||
if (obj["proto"].rootDisplayArea) delete obj["proto"].rootDisplayArea;
|
||||
if (obj["proto"].rootWindowContainer) delete obj["proto"].rootWindowContainer;
|
||||
if (obj["proto"].windowContainer?.children) delete obj["proto"].windowContainer.children;
|
||||
|
||||
obj = ObjectFormatter.format(obj);
|
||||
|
||||
Object.keys(obj["proto"]).forEach((prop: string) => {
|
||||
if (Object.keys(obj["proto"][prop]).length === 0) {
|
||||
obj["proto"][prop] = "empty";
|
||||
}
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private findFlickerItem(entryFlickerItem: TreeFlickerItem | null, stableId: string): TreeFlickerItem | null {
|
||||
if (!entryFlickerItem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const child of tree.children) {
|
||||
const foundEntry: any = this.findTree(child, stableId);
|
||||
if (entryFlickerItem.stableId && entryFlickerItem.stableId === stableId) {
|
||||
return entryFlickerItem;
|
||||
}
|
||||
|
||||
if (!entryFlickerItem.children) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const child of entryFlickerItem.children) {
|
||||
const foundEntry: any = this.findFlickerItem(child, stableId);
|
||||
if (foundEntry) {
|
||||
return foundEntry;
|
||||
}
|
||||
@@ -145,7 +179,7 @@ export class TreeTransformer {
|
||||
}
|
||||
|
||||
|
||||
public transform() {
|
||||
public transform(): PropertiesTree {
|
||||
const {formatter} = this.options!;
|
||||
if (!formatter) {
|
||||
throw new Error("Missing formatter, please set with setOptions()");
|
||||
@@ -154,18 +188,17 @@ export class TreeTransformer {
|
||||
const transformedTree = this.transformTree(this.properties, this.rootName,
|
||||
this.compareWithProperties, this.rootName,
|
||||
this.stableId, this.transformOptions);
|
||||
|
||||
return transformedTree;
|
||||
}
|
||||
|
||||
private transformTree(
|
||||
properties: PropertiesTree | Terminal,
|
||||
properties: PropertiesDump | null | Terminal,
|
||||
name: string | Terminal,
|
||||
compareWithProperties: PropertiesTree | Terminal,
|
||||
compareWithProperties: PropertiesDump | null | Terminal,
|
||||
compareWithName: string | Terminal,
|
||||
stableId: string,
|
||||
transformOptions: TransformOptions,
|
||||
) {
|
||||
): PropertiesTree {
|
||||
const originalProperties = properties;
|
||||
const metadata = this.getMetadata(
|
||||
originalProperties, transformOptions.metadataKey
|
||||
@@ -173,12 +206,12 @@ export class TreeTransformer {
|
||||
|
||||
const children: any[] = [];
|
||||
|
||||
if (!this.isTerminal(properties)) {
|
||||
if (properties && !this.isTerminal(properties)) {
|
||||
const transformedProperties = this.transformProperties(properties, transformOptions.metadataKey);
|
||||
properties = transformedProperties.properties;
|
||||
}
|
||||
|
||||
if (!this.isTerminal(compareWithProperties)) {
|
||||
if (compareWithProperties && !this.isTerminal(compareWithProperties)) {
|
||||
const transformedProperties = this.transformProperties(
|
||||
compareWithProperties,
|
||||
transformOptions.metadataKey
|
||||
@@ -187,10 +220,10 @@ export class TreeTransformer {
|
||||
}
|
||||
|
||||
for (const key in properties) {
|
||||
if (properties[key]) {
|
||||
if (!(properties instanceof Terminal) && properties[key]) {
|
||||
let compareWithChild = new Terminal();
|
||||
let compareWithChildName = new Terminal();
|
||||
if (compareWithProperties[key]) {
|
||||
if (compareWithProperties && !(compareWithProperties instanceof Terminal) && compareWithProperties[key]) {
|
||||
compareWithChild = compareWithProperties[key];
|
||||
compareWithChildName = key;
|
||||
}
|
||||
@@ -204,7 +237,8 @@ export class TreeTransformer {
|
||||
|
||||
// Takes care of adding deleted items to final tree
|
||||
for (const key in compareWithProperties) {
|
||||
if (!properties[key] && compareWithProperties[key]) {
|
||||
if (properties && !(properties instanceof Terminal) && !properties[key] &&
|
||||
!(compareWithProperties instanceof Terminal) && compareWithProperties[key]) {
|
||||
const child = this.transformTree(new Terminal(), new Terminal(),
|
||||
compareWithProperties[key], key,
|
||||
`${stableId}.${key}`, transformOptions);
|
||||
@@ -268,11 +302,10 @@ export class TreeTransformer {
|
||||
!this.hasChildMatchingFilter(transformedProperties?.children)) {
|
||||
transformedProperties.propertyKey = new Terminal();
|
||||
}
|
||||
|
||||
return transformOptions.freeze ? Object.freeze(transformedProperties) : transformedProperties;
|
||||
}
|
||||
|
||||
private hasChildMatchingFilter(children: PropertiesTree[] | null | undefined) {
|
||||
private hasChildMatchingFilter(children: PropertiesTree[] | null | undefined): boolean {
|
||||
if (!children || children.length === 0) return false;
|
||||
|
||||
let match = false;
|
||||
@@ -285,8 +318,11 @@ export class TreeTransformer {
|
||||
return match;
|
||||
}
|
||||
|
||||
private getMetadata(obj: PropertiesTree, metadataKey: string | null) {
|
||||
if (metadataKey && obj[metadataKey]) {
|
||||
private getMetadata(obj: PropertiesDump | null | Terminal, metadataKey: string | null): any {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
if (metadataKey && !(obj instanceof Terminal) && obj[metadataKey]) {
|
||||
const metadata = obj[metadataKey];
|
||||
obj[metadataKey] = undefined;
|
||||
return metadata;
|
||||
@@ -295,28 +331,28 @@ export class TreeTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
private getPropertyKey(item: PropertiesTree) {
|
||||
if (!item.children || item.children.length === 0) {
|
||||
return item.name.split(": ")[0];
|
||||
private getPropertyKey(item: PropertiesDump): string {
|
||||
if (item["name"] && (!item["children"] || item["children"].length === 0)) {
|
||||
return item["name"].split(": ")[0];
|
||||
}
|
||||
return item.name;
|
||||
return item["name"];
|
||||
}
|
||||
|
||||
private getPropertyValue(item: PropertiesTree) {
|
||||
if (!item.children || item.children.length === 0) {
|
||||
return item.name.split(": ").slice(1).join(": ");
|
||||
private getPropertyValue(item: PropertiesDump): string | null {
|
||||
if (item["name"] && (!item["children"] || item["children"].length === 0)) {
|
||||
return item["name"].split(": ").slice(1).join(": ");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private filterMatches(item: PropertiesTree | null): boolean {
|
||||
private filterMatches(item: PropertiesDump | null): boolean {
|
||||
return this.filter(item) ?? false;
|
||||
}
|
||||
|
||||
private transformProperties(properties: PropertiesTree, metadataKey: string | null) {
|
||||
private transformProperties(properties: PropertiesDump, metadataKey: string | null): PropertiesTree {
|
||||
const {skip, formatter} = this.options!;
|
||||
const transformedProperties: TransformedPropertiesObject = {
|
||||
const transformedProperties: PropertiesTree = {
|
||||
properties: {},
|
||||
};
|
||||
let formatted = undefined;
|
||||
@@ -351,7 +387,7 @@ export class TreeTransformer {
|
||||
return transformedProperties;
|
||||
}
|
||||
|
||||
private getDiff(val: string | Terminal, compareVal: string | Terminal) {
|
||||
private getDiff(val: string | Terminal, compareVal: string | Terminal): string {
|
||||
if (val && this.isTerminal(compareVal)) {
|
||||
return DiffType.ADDED;
|
||||
} else if (this.isTerminal(val) && compareVal) {
|
||||
@@ -363,7 +399,7 @@ export class TreeTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
private compatibleStableId(item: Tree) {
|
||||
private compatibleStableId(item: HierarchyTree): string {
|
||||
// For backwards compatibility
|
||||
// (the only item that doesn't have a unique stable ID in the tree)
|
||||
if (item.stableId === "winToken|-|") {
|
||||
@@ -378,7 +414,7 @@ export class TreeTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
private isTerminal(item: any) {
|
||||
private isTerminal(item: any): boolean {
|
||||
return item instanceof Terminal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,87 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Layer, BaseLayerTraceEntry } from "common/trace/flickerlib/common";
|
||||
|
||||
export type FilterType = (item: Tree | null) => boolean;
|
||||
export type Tree = Layer | BaseLayerTraceEntry;
|
||||
export type PropertiesTree = any; //TODO: make specific
|
||||
export type TreeSummary = Array<{key: string, value: string}>
|
||||
import Chip from "./chip";
|
||||
|
||||
export type FilterType = (item: HierarchyTree | PropertiesTree | null) => boolean;
|
||||
|
||||
export type Tree = HierarchyTree | PropertiesTree;
|
||||
|
||||
export class HierarchyTree {
|
||||
constructor(
|
||||
public name: string,
|
||||
public kind: string,
|
||||
public stableId: string,
|
||||
children?: HierarchyTree[]
|
||||
) {
|
||||
this.children = children ?? [];
|
||||
}
|
||||
|
||||
children: HierarchyTree[];
|
||||
shortName?: string;
|
||||
type?: string;
|
||||
id?: string | number;
|
||||
layerId?: number;
|
||||
displayId?: number;
|
||||
stackId?: number;
|
||||
isVisible?: boolean;
|
||||
isMissing?: boolean;
|
||||
hwcCompositionType?: number;
|
||||
zOrderRelativeOfId?: number;
|
||||
zOrderRelativeOf?: any;
|
||||
zOrderRelativeParentOf?: any;
|
||||
isRootLayer?: boolean;
|
||||
showInFilteredView?: boolean;
|
||||
showInOnlyVisibleView?: boolean;
|
||||
simplifyNames?: boolean;
|
||||
chips?: Chip[] = [];
|
||||
diffType?: string;
|
||||
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 {
|
||||
properties?: any;
|
||||
kind?: string;
|
||||
stableId?: string;
|
||||
children?: PropertiesTree[];
|
||||
propertyKey?: string | Terminal | null;
|
||||
propertyValue?: string | Terminal | null;
|
||||
name?: string | Terminal;
|
||||
diffType?: string;
|
||||
combined?: boolean;
|
||||
} //TODO: make specific
|
||||
|
||||
export const DiffType = {
|
||||
NONE: "none",
|
||||
@@ -32,18 +107,18 @@ export const DiffType = {
|
||||
export class Terminal {}
|
||||
|
||||
export function diffClass(item: Tree): string {
|
||||
const diffType = item!.diffType;
|
||||
const diffType = item.diffType;
|
||||
return diffType ?? "";
|
||||
}
|
||||
|
||||
export function isHighlighted(item: Tree, highlightedItems: Array<string>) {
|
||||
return highlightedItems.includes(`${item.id}`);
|
||||
return item instanceof HierarchyTree && highlightedItems.includes(`${item.id}`);
|
||||
}
|
||||
|
||||
export function getFilter(filterString: string): FilterType {
|
||||
const filterStrings = filterString.split(",");
|
||||
const positive: Tree | null[] = [];
|
||||
const negative: Tree | null[] = [];
|
||||
const positive: any[] = [];
|
||||
const negative: any[] = [];
|
||||
filterStrings.forEach((f) => {
|
||||
f = f.trim();
|
||||
if (f.startsWith("!")) {
|
||||
|
||||
@@ -22,6 +22,8 @@ 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 { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder";
|
||||
|
||||
describe("HierarchyComponent", () => {
|
||||
let fixture: ComponentFixture<HierarchyComponent>;
|
||||
@@ -51,14 +53,11 @@ describe("HierarchyComponent", () => {
|
||||
fixture = TestBed.createComponent(HierarchyComponent);
|
||||
component = fixture.componentInstance;
|
||||
htmlElement = fixture.nativeElement;
|
||||
component.tree = {
|
||||
simplifyNames: false,
|
||||
kind: "entry",
|
||||
name: "BaseLayerTraceEntry",
|
||||
shortName: "BLTE",
|
||||
chips: [],
|
||||
children: [{kind: "3", id: "3", name: "Child1"}]
|
||||
};
|
||||
|
||||
component.tree = new HierarchyTreeBuilder().setName("BaseLayerTraceEntry").setKind("entry").setStableId("BaseEntry")
|
||||
.setChildren([new HierarchyTreeBuilder().setName("Child1").setStableId("3 Child1").build()])
|
||||
.build();
|
||||
|
||||
component.store = new PersistentStore();
|
||||
component.userOptions = {
|
||||
onlyVisible: {
|
||||
@@ -66,14 +65,7 @@ describe("HierarchyComponent", () => {
|
||||
enabled: false
|
||||
},
|
||||
};
|
||||
component.pinnedItems = [{
|
||||
simplifyNames: false,
|
||||
kind: "entry",
|
||||
name: "BaseLayerTraceEntry",
|
||||
shortName: "BLTE",
|
||||
chips: [],
|
||||
children: [{kind: "3", id: "3", name: "Child1"}]
|
||||
}];
|
||||
component.pinnedItems = [component.tree];
|
||||
component.diffClass = jasmine.createSpy().and.returnValue("none");
|
||||
});
|
||||
|
||||
|
||||
@@ -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 { Tree, diffClass, isHighlighted } from "viewers/common/tree_utils";
|
||||
import { HierarchyTree, diffClass, isHighlighted, Tree } 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";
|
||||
@@ -56,7 +56,7 @@ import { TraceType } from "common/trace/trace_type";
|
||||
[isPinned]="true"
|
||||
[isInPinnedSection]="true"
|
||||
(pinNodeChange)="pinnedItemChange($event)"
|
||||
(click)="onPinnedNodeClick($event, pinnedItem.id, pinnedItem)"
|
||||
(click)="onPinnedNodeClick($event, pinnedItem)"
|
||||
></tree-node>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
@@ -150,10 +150,10 @@ export class HierarchyComponent {
|
||||
diffClass = diffClass;
|
||||
isHighlighted = isHighlighted;
|
||||
|
||||
@Input() tree!: Tree | null;
|
||||
@Input() tree!: HierarchyTree | null;
|
||||
@Input() dependencies: Array<TraceType> = [];
|
||||
@Input() highlightedItems: Array<string> = [];
|
||||
@Input() pinnedItems: Array<Tree> = [];
|
||||
@Input() pinnedItems: Array<HierarchyTree> = [];
|
||||
@Input() store!: PersistentStore;
|
||||
@Input() userOptions: UserOptions = {};
|
||||
|
||||
@@ -172,12 +172,12 @@ export class HierarchyComponent {
|
||||
};
|
||||
}
|
||||
|
||||
public onPinnedNodeClick(event: MouseEvent, pinnedItemId: string, pinnedItem: Tree) {
|
||||
public onPinnedNodeClick(event: MouseEvent, pinnedItem: HierarchyTree) {
|
||||
event.preventDefault();
|
||||
if (window.getSelection()?.type === "range") {
|
||||
return;
|
||||
}
|
||||
this.highlightedItemChange(`${pinnedItemId}`);
|
||||
if (pinnedItem.id) this.highlightedItemChange(`${pinnedItem.id}`);
|
||||
this.selectedTreeChange(pinnedItem);
|
||||
}
|
||||
|
||||
@@ -212,6 +212,9 @@ export class HierarchyComponent {
|
||||
}
|
||||
|
||||
public selectedTreeChange(item: Tree) {
|
||||
if (!(item instanceof HierarchyTree)) {
|
||||
return;
|
||||
}
|
||||
const event: CustomEvent = new CustomEvent(
|
||||
ViewerEvents.SelectedTreeChange,
|
||||
{
|
||||
@@ -222,6 +225,9 @@ export class HierarchyComponent {
|
||||
}
|
||||
|
||||
public pinnedItemChange(item: Tree) {
|
||||
if (!(item instanceof HierarchyTree)) {
|
||||
return;
|
||||
}
|
||||
const event: CustomEvent = new CustomEvent(
|
||||
ViewerEvents.HierarchyPinnedChange,
|
||||
{
|
||||
|
||||
@@ -54,9 +54,8 @@ describe("PropertiesComponent", () => {
|
||||
fixture = TestBed.createComponent(PropertiesComponent);
|
||||
component = fixture.componentInstance;
|
||||
htmlElement = fixture.nativeElement;
|
||||
component.selectedTree = {};
|
||||
component.selectedLayer = {};
|
||||
component.summary = [];
|
||||
component.propertiesTree = {};
|
||||
component.selectedFlickerItem = null;
|
||||
component.userOptions = {
|
||||
showDefaults: {
|
||||
name: "Show defaults",
|
||||
|
||||
@@ -16,8 +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, TreeSummary, Terminal } from "viewers/common/tree_utils";
|
||||
import { Layer } from "common/trace/flickerlib/common";
|
||||
import { PropertiesTree, Terminal, TreeFlickerItem } from "viewers/common/tree_utils";
|
||||
|
||||
@Component({
|
||||
selector: "properties-view",
|
||||
@@ -44,22 +43,21 @@ import { Layer } from "common/trace/flickerlib/common";
|
||||
[matTooltip]="userOptions[option].tooltip ?? ''"
|
||||
>{{userOptions[option].name}}</mat-checkbox>
|
||||
</div>
|
||||
<div *ngIf="objectKeys(selectedLayer).length > 0 && propertyGroups" class="element-summary">
|
||||
<div *ngIf="itemIsSelected() && propertyGroups" class="element-summary">
|
||||
<property-groups
|
||||
[item]="selectedLayer"
|
||||
[summary]="summary"
|
||||
[item]="selectedFlickerItem"
|
||||
></property-groups>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="properties-content" [style]="maxPropertiesHeight()">
|
||||
<span *ngIf="objectKeys(propertiesTree).length > 0" class="properties-title"> Properties - Proto Dump </span>
|
||||
<div class="tree-wrapper">
|
||||
<tree-view
|
||||
class="tree-view"
|
||||
[item]="selectedTree"
|
||||
[item]="propertiesTree"
|
||||
[showNode]="showNode"
|
||||
[isLeaf]="isLeaf"
|
||||
*ngIf="objectKeys(selectedTree).length > 0"
|
||||
[isPropertiesTree]="true"
|
||||
*ngIf="objectKeys(propertiesTree).length > 0"
|
||||
[isAlwaysCollapsed]="true"
|
||||
></tree-view>
|
||||
</div>
|
||||
@@ -136,10 +134,9 @@ export class PropertiesComponent {
|
||||
filterString = "";
|
||||
|
||||
@Input() userOptions: UserOptions = {};
|
||||
@Input() selectedTree: PropertiesTree = {};
|
||||
@Input() selectedLayer: Layer = {};
|
||||
@Input() propertiesTree: PropertiesTree = {};
|
||||
@Input() selectedFlickerItem: TreeFlickerItem | null = null;
|
||||
@Input() propertyGroups = false;
|
||||
@Input() summary?: TreeSummary = [];
|
||||
|
||||
constructor(
|
||||
@Inject(ElementRef) private elementRef: ElementRef,
|
||||
@@ -182,4 +179,8 @@ export class PropertiesComponent {
|
||||
return !item.children || item.children.length === 0
|
||||
|| item.children.filter((c: any) => !(c instanceof Terminal)).length === 0;
|
||||
}
|
||||
|
||||
public itemIsSelected() {
|
||||
return this.selectedFlickerItem && Object.keys(this.selectedFlickerItem).length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,28 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Component, Input } from "@angular/core";
|
||||
import { TreeSummary } from "viewers/common/tree_utils";
|
||||
import { Layer } from "common/trace/flickerlib/common";
|
||||
|
||||
@Component({
|
||||
selector: "property-groups",
|
||||
template: `
|
||||
<div>
|
||||
<div class="group">
|
||||
<span class="group-header">
|
||||
<span class="group-heading">Visibility</span>
|
||||
</span>
|
||||
<div class="left-column">
|
||||
<span class="key">Flags:</span>
|
||||
<span class="value">{{ item.flags }}</span>
|
||||
<div></div>
|
||||
<div *ngIf="summary().length > 0">
|
||||
<div *ngFor="let reason of summary()">
|
||||
<span class="key">{{ reason.key }}:</span>
|
||||
<span class="value">{{ reason.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group">
|
||||
<span class="group-header">Geometry</span>
|
||||
<div class="left-column">
|
||||
@@ -76,24 +91,24 @@ import { Layer } from "common/trace/flickerlib/common";
|
||||
<span
|
||||
class="key"
|
||||
matTooltip="Scales buffer to the frame by overriding the requested transform
|
||||
for this layer."
|
||||
for this item."
|
||||
>Destination Frame:</span>
|
||||
<span class="value">{{ getDestinationFrame() }}</span>
|
||||
<div></div>
|
||||
<span
|
||||
*ngIf="hasIgnoreDestinationFrame()"
|
||||
class="value"
|
||||
>Destination Frame ignored because layer has eIgnoreDestinationFrame
|
||||
>Destination Frame ignored because item has eIgnoreDestinationFrame
|
||||
flag set.
|
||||
</span>
|
||||
</div>
|
||||
<div *ngIf="item.isContainerLayer" class="left-column">
|
||||
<span class="key"></span>
|
||||
<span class="value">Container layer</span>
|
||||
<span class="value">Container item</span>
|
||||
</div>
|
||||
<div *ngIf="item.isEffectLayer" class="left-column">
|
||||
<span class="key"></span>
|
||||
<span class="value">Effect layer</span>
|
||||
<span class="value">Effect item</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group">
|
||||
@@ -107,7 +122,7 @@ import { Layer } from "common/trace/flickerlib/common";
|
||||
<div></div>
|
||||
<span
|
||||
class="key"
|
||||
matTooltip="Layer is z-ordered relative to its relative parents but its bounds
|
||||
matTooltip="item is z-ordered relative to its relative parents but its bounds
|
||||
and other properties are inherited from its parents."
|
||||
>relative parent:</span>
|
||||
<span class="value">
|
||||
@@ -133,7 +148,7 @@ import { Layer } from "common/trace/flickerlib/common";
|
||||
<span
|
||||
class="key"
|
||||
matTooltip="Crop used to define the bounds of the corner radii. If the bounds
|
||||
are greater than the layer bounds then the rounded corner will not
|
||||
are greater than the item bounds then the rounded corner will not
|
||||
be visible."
|
||||
>Corner Radius Crop:</span>
|
||||
<span class="value">{{ item.cornerRadiusCrop }}</span>
|
||||
@@ -175,21 +190,21 @@ import { Layer } from "common/trace/flickerlib/common";
|
||||
<span class="group-header">
|
||||
<span class="group-heading">Input</span>
|
||||
</span>
|
||||
<div *ngIf="item.proto?.inputWindowInfo" class="left-column">
|
||||
<div *ngIf="hasInputChannel()" class="left-column">
|
||||
<span class="key">To Display Transform:</span>
|
||||
<transform-matrix [transform]="item.inputTransform" [formatFloat]="formatFloat"></transform-matrix>
|
||||
<div></div>
|
||||
<span class="key">Touchable Region:</span>
|
||||
<span class="value">{{ item.inputRegion }}</span>
|
||||
</div>
|
||||
<div *ngIf="item.proto?.inputWindowInfo" class="right-column">
|
||||
<div *ngIf="hasInputChannel()" class="right-column">
|
||||
<span class="key">Config:</span>
|
||||
<span class="value"></span>
|
||||
<div></div>
|
||||
<span class="key">Focusable:</span>
|
||||
<span class="value">{{ item.proto?.inputWindowInfo.focusable }}</span>
|
||||
<div></div>
|
||||
<span class="key">Crop touch region with layer:</span>
|
||||
<span class="key">Crop touch region with item:</span>
|
||||
<span class="value">
|
||||
{{
|
||||
item.proto?.inputWindowInfo.cropLayerId <= 0
|
||||
@@ -205,28 +220,11 @@ import { Layer } from "common/trace/flickerlib/common";
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div *ngIf="!item.proto?.inputWindowInfo" class="left-column">
|
||||
<div *ngIf="!hasInputChannel()" class="left-column">
|
||||
<span class="key"></span>
|
||||
<span class="value">No input channel set</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="group">
|
||||
<span class="group-header">
|
||||
<span class="group-heading">Visibility</span>
|
||||
</span>
|
||||
<div class="left-column">
|
||||
<span class="key">Flags:</span>
|
||||
<span class="value">{{ item.flags }}</span>
|
||||
<div></div>
|
||||
<div *ngIf="summary">
|
||||
<div *ngFor="let reason of summary">
|
||||
<span class="key">{{ reason.key }}:</span>
|
||||
<span class="value">{{ reason.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
styles: [
|
||||
@@ -285,7 +283,10 @@ import { Layer } from "common/trace/flickerlib/common";
|
||||
|
||||
export class PropertyGroupsComponent {
|
||||
@Input() item!: Layer;
|
||||
@Input() summary?: TreeSummary | null = null;
|
||||
|
||||
public hasInputChannel() {
|
||||
return this.item.proto?.inputWindowInfo;
|
||||
}
|
||||
|
||||
public getDestinationFrame() {
|
||||
const frame = this.item.proto?.destinationFrame;
|
||||
@@ -302,4 +303,41 @@ export class PropertyGroupsComponent {
|
||||
public formatFloat(num: number) {
|
||||
return Math.round(num * 100) / 100;
|
||||
}
|
||||
|
||||
|
||||
public summary(): TreeSummary {
|
||||
const summary = [];
|
||||
|
||||
if (this.item?.visibilityReason?.length > 0) {
|
||||
let reason = "";
|
||||
if (Array.isArray(this.item.visibilityReason)) {
|
||||
reason = this.item.visibilityReason.join(", ");
|
||||
} else {
|
||||
reason = this.item.visibilityReason;
|
||||
}
|
||||
|
||||
summary.push({key: "Invisible due to", value: reason});
|
||||
}
|
||||
|
||||
if (this.item?.occludedBy?.length > 0) {
|
||||
summary.push({key: "Occluded by", value: this.item.occludedBy.map((it: any) => it.id).join(", ")});
|
||||
}
|
||||
|
||||
if (this.item?.partiallyOccludedBy?.length > 0) {
|
||||
summary.push({
|
||||
key: "Partially occluded by",
|
||||
value: this.item.partiallyOccludedBy.map((it: any) => it.id).join(", "),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.item?.coveredBy?.length > 0) {
|
||||
summary.push({key: "Covered by", value: this.item.coveredBy.map((it: any) => it.id).join(", ")});
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
type TreeSummary = Array<{key: string, value: string}>
|
||||
@@ -23,11 +23,11 @@ export class CanvasGraphics {
|
||||
constructor() {
|
||||
//set up camera
|
||||
const left = -this.CAMERA_HALF_WIDTH,
|
||||
right = this.CAMERA_HALF_WIDTH,
|
||||
top = this.CAMERA_HALF_HEIGHT,
|
||||
bottom = -this.CAMERA_HALF_HEIGHT,
|
||||
near = 0.001,
|
||||
far = 100;
|
||||
right = this.CAMERA_HALF_WIDTH,
|
||||
top = this.CAMERA_HALF_HEIGHT,
|
||||
bottom = -this.CAMERA_HALF_HEIGHT,
|
||||
near = 0.001,
|
||||
far = 100;
|
||||
this.camera = new THREE.OrthographicCamera(
|
||||
left, right, top, bottom, near, far
|
||||
);
|
||||
|
||||
@@ -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 } from "viewers/common/tree_utils";
|
||||
import { Tree, diffClass, isHighlighted, PropertiesTree, Terminal, isParentNode, HierarchyTree } from "viewers/common/tree_utils";
|
||||
import { TraceType } from "common/trace/trace_type";
|
||||
|
||||
@Component({
|
||||
@@ -39,7 +39,6 @@ import { TraceType } from "common/trace/trace_type";
|
||||
[flattened]="isFlattened"
|
||||
[isLeaf]="isLeaf(this.item)"
|
||||
[isCollapsed]="isAlwaysCollapsed ?? isCollapsed()"
|
||||
[isPropertiesTreeNode]="isPropertiesTree"
|
||||
[hasChildren]="hasChildren()"
|
||||
[isPinned]="isPinned()"
|
||||
(toggleTreeChange)="toggleTree()"
|
||||
@@ -58,7 +57,6 @@ import { TraceType } from "common/trace/trace_type";
|
||||
[isLeaf]="isLeaf"
|
||||
[dependencies]="dependencies"
|
||||
[isFlattened]="isFlattened"
|
||||
[isPropertiesTree]="isPropertiesTree"
|
||||
[isShaded]="!isShaded"
|
||||
[useGlobalCollapsedState]="useGlobalCollapsedState"
|
||||
[initialDepth]="initialDepth + 1"
|
||||
@@ -82,17 +80,16 @@ export class TreeComponent {
|
||||
diffClass = diffClass;
|
||||
isHighlighted = isHighlighted;
|
||||
|
||||
@Input() item!: Tree | PropertiesTree | Terminal;
|
||||
@Input() item!: Tree;
|
||||
@Input() dependencies: Array<TraceType> = [];
|
||||
@Input() store!: PersistentStore;
|
||||
@Input() isFlattened? = false;
|
||||
@Input() isShaded? = false;
|
||||
@Input() initialDepth = 0;
|
||||
@Input() highlightedItems: Array<string> = [];
|
||||
@Input() pinnedItems?: Array<Tree> = [];
|
||||
@Input() pinnedItems?: Array<HierarchyTree> = [];
|
||||
@Input() itemsClickable?: boolean;
|
||||
@Input() useGlobalCollapsedState?: boolean;
|
||||
@Input() isPropertiesTree?: boolean;
|
||||
@Input() isAlwaysCollapsed?: boolean;
|
||||
@Input() showNode: (item?: any) => boolean = () => true;
|
||||
@Input() isLeaf: (item: any) => boolean = (item: any) => !item.children || item.children.length === 0;
|
||||
@@ -126,7 +123,7 @@ export class TreeComponent {
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
if (isHighlighted(this.item, this.highlightedItems)) {
|
||||
if (this.item instanceof HierarchyTree && isHighlighted(this.item, this.highlightedItems)) {
|
||||
this.selectedTreeChange.emit(this.item);
|
||||
}
|
||||
}
|
||||
@@ -162,16 +159,18 @@ export class TreeComponent {
|
||||
}
|
||||
|
||||
private updateHighlightedItems() {
|
||||
if (this.item && this.item.id) {
|
||||
this.highlightedItemChange.emit(`${this.item.id}`);
|
||||
} else if (!this.item.id) {
|
||||
this.selectedTreeChange.emit(this.item);
|
||||
if (this.item instanceof HierarchyTree) {
|
||||
if (this.item && this.item.id) {
|
||||
this.highlightedItemChange.emit(`${this.item.id}`);
|
||||
} else if (!this.item.id) {
|
||||
this.selectedTreeChange.emit(this.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public isPinned() {
|
||||
if (this.item) {
|
||||
return this.pinnedItems?.map((item: Tree) => `${item.id}`).includes(`${this.item.id}`);
|
||||
if (this.item instanceof HierarchyTree) {
|
||||
return this.pinnedItems?.map(item => `${item.id}`).includes(`${this.item.id}`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -206,18 +205,18 @@ export class TreeComponent {
|
||||
}
|
||||
|
||||
if (this.useGlobalCollapsedState) {
|
||||
return this.store.getFromStore(`collapsedState.item.${this.dependencies}.${this.item.id}`)==="true"
|
||||
return this.store.getFromStore(`collapsedState.item.${this.dependencies}.${this.item.stableId}`)==="true"
|
||||
?? this.isCollapsedByDefault;
|
||||
}
|
||||
return this.localCollapsedState;
|
||||
}
|
||||
|
||||
public children() {
|
||||
return this.item.children;
|
||||
public children(): Tree[] {
|
||||
return this.item.children ?? [];
|
||||
}
|
||||
|
||||
public hasChildren() {
|
||||
const isParentEntryInFlatView = isParentNode(this.item.kind) && this.isFlattened;
|
||||
const isParentEntryInFlatView = isParentNode(this.item.kind ?? "") && this.isFlattened;
|
||||
return (!this.isFlattened || isParentEntryInFlatView) && !this.isLeaf(this.item);
|
||||
}
|
||||
|
||||
@@ -241,7 +240,7 @@ export class TreeComponent {
|
||||
|
||||
private setCollapseValue(isCollapsed: boolean) {
|
||||
if (this.useGlobalCollapsedState) {
|
||||
this.store.addToStore(`collapsedState.item.${this.dependencies}.${this.item.id}`, `${isCollapsed}`);
|
||||
this.store.addToStore(`collapsedState.item.${this.dependencies}.${this.item.stableId}`, `${isCollapsed}`);
|
||||
} else {
|
||||
this.localCollapsedState = isCollapsed;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,6 @@ describe("TreeNodeComponent", () => {
|
||||
[isPinned]="false"
|
||||
[isInPinnedSection]="false"
|
||||
[hasChildren]="false"
|
||||
[isPropertiesTreeNode]="false"
|
||||
></tree-node>
|
||||
`
|
||||
})
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
import { Component, Input, Output, EventEmitter } from "@angular/core";
|
||||
import { nodeInnerItemStyles } from "viewers/components/styles/node.styles";
|
||||
import { PropertiesTree, Tree, DiffType, isParentNode } from "viewers/common/tree_utils";
|
||||
import { Tree, DiffType, isParentNode, HierarchyTree } from "viewers/common/tree_utils";
|
||||
|
||||
@Component({
|
||||
selector: "tree-node",
|
||||
@@ -50,11 +50,11 @@ import { PropertiesTree, Tree, DiffType, isParentNode } from "viewers/common/tre
|
||||
<div class="description">
|
||||
<tree-node-data-view
|
||||
[item]="item"
|
||||
*ngIf="!isPropertiesTreeNode"
|
||||
*ngIf="!isPropertiesTreeNode()"
|
||||
></tree-node-data-view>
|
||||
<tree-node-properties-data-view
|
||||
[item]="item"
|
||||
*ngIf="isPropertiesTreeNode"
|
||||
*ngIf="isPropertiesTreeNode()"
|
||||
></tree-node-properties-data-view>
|
||||
</div>
|
||||
|
||||
@@ -76,14 +76,13 @@ import { PropertiesTree, Tree, DiffType, isParentNode } from "viewers/common/tre
|
||||
})
|
||||
|
||||
export class TreeNodeComponent {
|
||||
@Input() item!: Tree | PropertiesTree;
|
||||
@Input() item!: Tree;
|
||||
@Input() isLeaf?: boolean;
|
||||
@Input() flattened?: boolean;
|
||||
@Input() isCollapsed?: boolean;
|
||||
@Input() hasChildren?: boolean = false;
|
||||
@Input() isPinned?: boolean = false;
|
||||
@Input() isInPinnedSection?: boolean = false;
|
||||
@Input() isPropertiesTreeNode?: boolean;
|
||||
@Input() isAlwaysCollapsed?: boolean;
|
||||
|
||||
@Output() toggleTreeChange = new EventEmitter<void>();
|
||||
@@ -96,8 +95,12 @@ export class TreeNodeComponent {
|
||||
this.collapseDiffClass = this.updateCollapseDiffClass();
|
||||
}
|
||||
|
||||
public isPropertiesTreeNode() {
|
||||
return !(this.item instanceof HierarchyTree);
|
||||
}
|
||||
|
||||
public showPinNodeIcon() {
|
||||
return (!this.isPropertiesTreeNode && !isParentNode(this.item.kind)) ?? false;
|
||||
return (!this.isPropertiesTreeNode() && !isParentNode(this.item.kind ?? "")) ?? false;
|
||||
}
|
||||
|
||||
public toggleTree(event: MouseEvent) {
|
||||
@@ -145,7 +148,7 @@ export class TreeNodeComponent {
|
||||
return DiffType.MODIFIED;
|
||||
}
|
||||
|
||||
private getAllDiffTypesOfChildren(item: Tree | PropertiesTree) {
|
||||
private getAllDiffTypesOfChildren(item: Tree) {
|
||||
if (!item.children) {
|
||||
return new Set();
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
import { Component, Input } from "@angular/core";
|
||||
import { treeNodeDataViewStyles } from "viewers/components/styles/tree_node_data_view.styles";
|
||||
import { Tree } from "viewers/common/tree_utils";
|
||||
import { Terminal, HierarchyTree, Tree } from "viewers/common/tree_utils";
|
||||
import Chip from "viewers/common/chip";
|
||||
|
||||
@Component({
|
||||
@@ -24,10 +24,10 @@ import Chip from "viewers/common/chip";
|
||||
<span>
|
||||
<span class="kind">{{item.kind}}</span>
|
||||
<span *ngIf="item.kind && item.name">-</span>
|
||||
<span *ngIf="showShortName()" [matTooltip]="item.name">{{ item.shortName }}</span>
|
||||
<span *ngIf="showShortName()" [matTooltip]="itemTooltip()">{{ itemShortName() }}</span>
|
||||
<span *ngIf="!showShortName()">{{item.name}}</span>
|
||||
<div
|
||||
*ngFor="let chip of item.chips"
|
||||
*ngFor="let chip of chips()"
|
||||
[class]="chipClass(chip)"
|
||||
[matTooltip]="chip.long"
|
||||
>{{chip.short}}</div>
|
||||
@@ -39,8 +39,23 @@ import Chip from "viewers/common/chip";
|
||||
export class TreeNodeDataViewComponent {
|
||||
@Input() item!: Tree;
|
||||
|
||||
public chips() {
|
||||
return (this.item instanceof HierarchyTree) ? this.item.chips : [];
|
||||
}
|
||||
|
||||
public itemShortName() {
|
||||
return (this.item instanceof HierarchyTree)? this.item.shortName : "";
|
||||
}
|
||||
|
||||
public itemTooltip() {
|
||||
if (this.item.name instanceof Terminal) {
|
||||
return "";
|
||||
}
|
||||
return this.item.name ?? "";
|
||||
}
|
||||
|
||||
public showShortName() {
|
||||
return this.item.simplifyNames && this.item.shortName !== this.item.name;
|
||||
return (this.item instanceof HierarchyTree) && this.item.simplifyNames && this.item.shortName !== this.item.name;
|
||||
}
|
||||
|
||||
public chipClass(chip: Chip) {
|
||||
|
||||
@@ -49,7 +49,7 @@ export class TreeNodePropertiesDataViewComponent {
|
||||
return "false";
|
||||
}
|
||||
|
||||
if (!isNaN(this.item.propertyValue)) {
|
||||
if (!isNaN(Number(this.item.propertyValue))) {
|
||||
return "number";
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -17,57 +17,25 @@ import { Presenter } from "./presenter";
|
||||
import { UiData } from "./ui_data";
|
||||
import { UserOptions } from "viewers/common/user_options";
|
||||
import { TraceType } from "common/trace/trace_type";
|
||||
import { RELATIVE_Z_CHIP, VISIBLE_CHIP } from "viewers/common/chip";
|
||||
import { LayerTraceEntry } from "common/trace/flickerlib/common";
|
||||
import { DiffType, PropertiesTree, Terminal, Tree } from "viewers/common/tree_utils";
|
||||
import { HierarchyTree, PropertiesTree } from "viewers/common/tree_utils";
|
||||
import { UnitTestUtils } from "test/unit/utils";
|
||||
import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder";
|
||||
|
||||
describe("PresenterSurfaceFlinger", () => {
|
||||
let presenter: Presenter;
|
||||
let uiData: UiData;
|
||||
let entries: Map<TraceType, any>;
|
||||
let selectedItem: Tree;
|
||||
let selectedTree: HierarchyTree;
|
||||
|
||||
beforeAll(async () => {
|
||||
entries = new Map<TraceType, any>();
|
||||
const entry: LayerTraceEntry = await UnitTestUtils.getLayerTraceEntry();
|
||||
selectedItem = {
|
||||
id: "3",
|
||||
name: "Child1",
|
||||
stackId: 0,
|
||||
isVisible: true,
|
||||
kind: "3",
|
||||
stableId: "3 Child1",
|
||||
shortName: undefined,
|
||||
simplifyNames: true,
|
||||
showInFilteredView: true,
|
||||
proto: {
|
||||
barrierLayer: [],
|
||||
id: 3,
|
||||
parent: 1,
|
||||
type: "ContainerLayer",
|
||||
},
|
||||
chips: [ VISIBLE_CHIP, RELATIVE_Z_CHIP ],
|
||||
children: [{
|
||||
id: "2",
|
||||
name: "Child2",
|
||||
stackId: 0,
|
||||
children: [],
|
||||
kind: "2",
|
||||
stableId: "2 Child2",
|
||||
shortName: undefined,
|
||||
simplifyNames: true,
|
||||
proto: {
|
||||
barrierLayer: [],
|
||||
id: 2,
|
||||
parent: 3,
|
||||
type: "ContainerLayer",
|
||||
},
|
||||
isVisible: true,
|
||||
showInFilteredView: true,
|
||||
chips: [ VISIBLE_CHIP, RELATIVE_Z_CHIP ],
|
||||
}],
|
||||
};
|
||||
|
||||
|
||||
selectedTree = new HierarchyTreeBuilder().setName("Dim layer#53").setStableId("EffectLayer 53 Dim layer#53")
|
||||
.setFilteredView(true).setKind("53").setDiffType("EffectLayer").setId(53).build();
|
||||
|
||||
entries.set(TraceType.SURFACE_FLINGER, [entry, null]);
|
||||
});
|
||||
|
||||
@@ -92,12 +60,12 @@ describe("PresenterSurfaceFlinger", () => {
|
||||
expect(propertyOpts).toBeTruthy();
|
||||
|
||||
// does not check specific tree values as tree generation method may change
|
||||
expect(Object.keys(uiData.tree).length > 0).toBeTrue();
|
||||
expect(Object.keys(uiData.tree!).length > 0).toBeTrue();
|
||||
});
|
||||
|
||||
it("can handle unavailable trace entry", () => {
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
expect(Object.keys(uiData.tree).length > 0).toBeTrue();
|
||||
expect(Object.keys(uiData.tree!).length > 0).toBeTrue();
|
||||
const emptyEntries = new Map<TraceType, any>();
|
||||
presenter.notifyCurrentTraceEntries(emptyEntries);
|
||||
expect(uiData.tree).toBeFalsy();
|
||||
@@ -105,13 +73,8 @@ describe("PresenterSurfaceFlinger", () => {
|
||||
|
||||
it("can update pinned items", () => {
|
||||
expect(uiData.pinnedItems).toEqual([]);
|
||||
const pinnedItem = {
|
||||
name: "FirstPinnedItem",
|
||||
kind: "4",
|
||||
id: 4,
|
||||
type: "TestItem",
|
||||
stableId: "TestItem 4 FirstPinnedItem"
|
||||
};
|
||||
const pinnedItem = new HierarchyTreeBuilder().setName("FirstPinnedItem")
|
||||
.setStableId("TestItem 4").setLayerId(4).build();
|
||||
presenter.updatePinnedItems(pinnedItem);
|
||||
expect(uiData.pinnedItems).toContain(pinnedItem);
|
||||
});
|
||||
@@ -145,12 +108,12 @@ describe("PresenterSurfaceFlinger", () => {
|
||||
};
|
||||
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
expect(uiData.tree.children.length).toEqual(3);
|
||||
expect(uiData.tree?.children.length).toEqual(3);
|
||||
|
||||
presenter.updateHierarchyTree(userOptions);
|
||||
expect(uiData.hierarchyUserOptions).toEqual(userOptions);
|
||||
// nested children should now be on same level as initial parents
|
||||
expect(uiData.tree.children.length).toEqual(94);
|
||||
expect(uiData.tree?.children.length).toEqual(94);
|
||||
});
|
||||
|
||||
it("can filter hierarchy tree", () => {
|
||||
@@ -171,21 +134,21 @@ describe("PresenterSurfaceFlinger", () => {
|
||||
name: "Flat",
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
};
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
presenter.updateHierarchyTree(userOptions);
|
||||
expect(uiData.tree.children.length).toEqual(94);
|
||||
expect(uiData.tree?.children.length).toEqual(94);
|
||||
presenter.filterHierarchyTree("Wallpaper");
|
||||
// All but four layers should be filtered out
|
||||
expect(uiData.tree.children.length).toEqual(4);
|
||||
expect(uiData.tree?.children.length).toEqual(4);
|
||||
});
|
||||
|
||||
|
||||
it("can set new properties tree and associated ui data", () => {
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
presenter.newPropertiesTree(selectedItem);
|
||||
presenter.newPropertiesTree(selectedTree);
|
||||
// does not check specific tree values as tree transformation method may change
|
||||
expect(Object.keys(uiData.selectedTree).length > 0).toBeTrue();
|
||||
expect(uiData.propertiesTree).toBeTruthy();
|
||||
});
|
||||
|
||||
it("can update properties tree", () => {
|
||||
@@ -207,33 +170,27 @@ describe("PresenterSurfaceFlinger", () => {
|
||||
};
|
||||
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
presenter.newPropertiesTree(selectedItem);
|
||||
presenter.newPropertiesTree(selectedTree);
|
||||
expect(uiData.propertiesTree?.diffType).toBeFalsy();
|
||||
presenter.updatePropertiesTree(userOptions);
|
||||
expect(uiData.propertiesUserOptions).toEqual(userOptions);
|
||||
//check that diff type added
|
||||
expect(uiData.selectedTree.diffType).toEqual(DiffType.NONE);
|
||||
expect(uiData.propertiesTree?.diffType).toBeTruthy();
|
||||
});
|
||||
|
||||
it("can filter properties tree", () => {
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
presenter.newPropertiesTree(selectedItem);
|
||||
presenter.newPropertiesTree(selectedTree);
|
||||
let nonTerminalChildren = uiData.propertiesTree?.children?.filter(
|
||||
(child: PropertiesTree) => typeof child.propertyKey === "string"
|
||||
) ?? [];
|
||||
|
||||
let nonTerminalChildren = uiData.selectedTree
|
||||
.children[0]
|
||||
.children.filter(
|
||||
(child: PropertiesTree) => !(child.propertyKey instanceof Terminal)
|
||||
);
|
||||
expect(nonTerminalChildren.length).toEqual(55);
|
||||
presenter.filterPropertiesTree("bound");
|
||||
|
||||
expect(nonTerminalChildren.length).toEqual(2);
|
||||
|
||||
presenter.filterPropertiesTree("ContainerLayer");
|
||||
|
||||
// one child should be filtered out
|
||||
nonTerminalChildren = uiData.selectedTree
|
||||
.children[0]
|
||||
.children.filter(
|
||||
(child: PropertiesTree) => !(child.propertyKey instanceof Terminal)
|
||||
);
|
||||
expect(nonTerminalChildren.length).toEqual(1);
|
||||
nonTerminalChildren = uiData.propertiesTree?.children?.filter(
|
||||
(child: PropertiesTree) => typeof child.propertyKey === "string"
|
||||
) ?? [];
|
||||
expect(nonTerminalChildren.length).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,9 +18,10 @@ 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, TreeSummary } from "viewers/common/tree_utils";
|
||||
import { getFilter, FilterType, HierarchyTree, Tree, TreeFlickerItem, PropertiesTree } 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";
|
||||
|
||||
type NotifyViewCallbackType = (uiData: UiData) => void;
|
||||
|
||||
@@ -31,7 +32,7 @@ export class Presenter {
|
||||
this.notifyViewCallback(this.uiData);
|
||||
}
|
||||
|
||||
public updatePinnedItems(pinnedItem: Tree) {
|
||||
public updatePinnedItems(pinnedItem: HierarchyTree) {
|
||||
const pinnedId = `${pinnedItem.id}`;
|
||||
if (this.pinnedItems.map(item => `${item.id}`).includes(pinnedId)) {
|
||||
this.pinnedItems = this.pinnedItems.filter(pinned => `${pinned.id}` != pinnedId);
|
||||
@@ -47,7 +48,7 @@ export class Presenter {
|
||||
if (this.highlightedItems.includes(id)) {
|
||||
this.highlightedItems = this.highlightedItems.filter(hl => hl != id);
|
||||
} else {
|
||||
this.highlightedItems = []; //if multi-select implemented, remove this line
|
||||
this.highlightedItems = []; //if multi-select surfaces implemented, remove this line
|
||||
this.highlightedItems.push(id);
|
||||
}
|
||||
this.uiData.highlightedItems = this.highlightedItems;
|
||||
@@ -78,12 +79,12 @@ export class Presenter {
|
||||
this.updateSelectedTreeUiData();
|
||||
}
|
||||
|
||||
public newPropertiesTree(selectedItem: any) {
|
||||
this.selectedTree = selectedItem;
|
||||
public newPropertiesTree(selectedItem: HierarchyTree) {
|
||||
this.selectedHierarchyTree = selectedItem;
|
||||
this.updateSelectedTreeUiData();
|
||||
}
|
||||
|
||||
public notifyCurrentTraceEntries(entries: Map<TraceType, any>) {
|
||||
public notifyCurrentTraceEntries(entries: Map<TraceType, [any, any]>) {
|
||||
this.uiData = new UiData();
|
||||
this.uiData.hierarchyUserOptions = this.hierarchyUserOptions;
|
||||
this.uiData.propertiesUserOptions = this.propertiesUserOptions;
|
||||
@@ -127,49 +128,13 @@ export class Presenter {
|
||||
}
|
||||
|
||||
private updateSelectedTreeUiData() {
|
||||
if (this.selectedTree) {
|
||||
this.uiData.selectedTree = this.getTreeWithTransformedProperties(this.selectedTree);
|
||||
this.uiData.selectedTreeSummary = this.getSelectedTreeSummary(this.selectedTree);
|
||||
if (this.selectedHierarchyTree) {
|
||||
this.uiData.propertiesTree = this.getTreeWithTransformedProperties(this.selectedHierarchyTree);
|
||||
this.uiData.selectedLayer = this.selectedLayer;
|
||||
}
|
||||
this.notifyViewCallback(this.uiData);
|
||||
}
|
||||
|
||||
private getSelectedTreeSummary(layer: Tree): TreeSummary | undefined {
|
||||
const summary = [];
|
||||
|
||||
if (layer?.visibilityReason?.length > 0) {
|
||||
let reason = "";
|
||||
if (Array.isArray(layer.visibilityReason)) {
|
||||
reason = layer.visibilityReason.join(", ");
|
||||
} else {
|
||||
reason = layer.visibilityReason;
|
||||
}
|
||||
|
||||
summary.push({key: "Invisible due to", value: reason});
|
||||
}
|
||||
|
||||
if (layer?.occludedBy?.length > 0) {
|
||||
summary.push({key: "Occluded by", value: layer.occludedBy.map((it:Tree) => it.id).join(", ")});
|
||||
}
|
||||
|
||||
if (layer?.partiallyOccludedBy?.length > 0) {
|
||||
summary.push({
|
||||
key: "Partially occluded by",
|
||||
value: layer.partiallyOccludedBy.map((it:Tree) => it.id).join(", "),
|
||||
});
|
||||
}
|
||||
|
||||
if (layer?.coveredBy?.length > 0) {
|
||||
summary.push({key: "Covered by", value: layer.coveredBy.map((it:Tree) => it.id).join(", ")});
|
||||
}
|
||||
|
||||
if (summary.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
private generateTree() {
|
||||
if (!this.entry) {
|
||||
return null;
|
||||
@@ -180,13 +145,13 @@ export class Presenter {
|
||||
.setIsSimplifyNames(this.hierarchyUserOptions["simplifyNames"]?.enabled)
|
||||
.setIsFlatView(this.hierarchyUserOptions["flat"]?.enabled)
|
||||
.withUniqueNodeId();
|
||||
let tree: Tree;
|
||||
let tree: HierarchyTree | null;
|
||||
if (!this.hierarchyUserOptions["showDiff"]?.enabled) {
|
||||
tree = generator.generateTree();
|
||||
} else {
|
||||
tree = generator.compareWith(this.previousEntry)
|
||||
.withModifiedCheck()
|
||||
.generateFinalDiffTree();
|
||||
.generateFinalTreeWithDiff();
|
||||
}
|
||||
this.pinnedItems = generator.getPinnedItems();
|
||||
this.uiData.pinnedItems = this.pinnedItems;
|
||||
@@ -245,13 +210,15 @@ export class Presenter {
|
||||
}
|
||||
}
|
||||
|
||||
private getTreeWithTransformedProperties(selectedTree: Tree) {
|
||||
private getTreeWithTransformedProperties(selectedTree: HierarchyTree): PropertiesTree {
|
||||
const transformer = new TreeTransformer(selectedTree, this.propertiesFilter)
|
||||
.showOnlyProtoDump()
|
||||
.setIsShowDefaults(this.propertiesUserOptions["showDefaults"]?.enabled)
|
||||
.setIsShowDiff(this.propertiesUserOptions["showDiff"]?.enabled)
|
||||
.setTransformerOptions({skip: selectedTree.skip})
|
||||
.setProperties(this.entry)
|
||||
.setDiffProperties(this.previousEntry);
|
||||
this.uiData.selectedLayer = transformer.getOriginalLayer(this.entry, selectedTree.stableId);
|
||||
this.selectedLayer = transformer.getOriginalFlickerItem(this.entry, selectedTree.stableId);
|
||||
const transformedTree = transformer.transform();
|
||||
return transformedTree;
|
||||
}
|
||||
@@ -262,11 +229,12 @@ export class Presenter {
|
||||
private propertiesFilter: FilterType = getFilter("");
|
||||
private highlightedItems: Array<string> = [];
|
||||
private displayIds: Array<number> = [];
|
||||
private pinnedItems: Array<Tree> = [];
|
||||
private pinnedItems: Array<HierarchyTree> = [];
|
||||
private pinnedIds: Array<string> = [];
|
||||
private selectedTree: any = null;
|
||||
private previousEntry: any = null;
|
||||
private entry: any = null;
|
||||
private selectedHierarchyTree: HierarchyTree | null = null;
|
||||
private selectedLayer: LayerTraceEntry | Layer | null = null;
|
||||
private previousEntry: LayerTraceEntry | null = null;
|
||||
private entry: LayerTraceEntry | null = null;
|
||||
private hierarchyUserOptions: UserOptions = {
|
||||
showDiff: {
|
||||
name: "Show diff",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Tree, TreeSummary } from "viewers/common/tree_utils";
|
||||
import { HierarchyTree, PropertiesTree } 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";
|
||||
@@ -21,15 +21,14 @@ import { Rectangle } from "viewers/common/rectangle";
|
||||
|
||||
export class UiData {
|
||||
dependencies: Array<TraceType> = [TraceType.SURFACE_FLINGER];
|
||||
rects?: Rectangle[] = [];
|
||||
displayIds?: number[] = [];
|
||||
hasVirtualDisplays? = false;
|
||||
highlightedItems?: Array<string> = [];
|
||||
pinnedItems?: Array<Tree> = [];
|
||||
hierarchyUserOptions?: UserOptions = {};
|
||||
propertiesUserOptions?: UserOptions = {};
|
||||
tree?: Tree | null = null;
|
||||
selectedTree?: any = {};
|
||||
selectedLayer?: Layer = {};
|
||||
selectedTreeSummary?: TreeSummary = [];
|
||||
rects: Rectangle[] = [];
|
||||
displayIds: number[] = [];
|
||||
hasVirtualDisplays = false;
|
||||
highlightedItems: Array<string> = [];
|
||||
pinnedItems: Array<HierarchyTree> = [];
|
||||
hierarchyUserOptions: UserOptions = {};
|
||||
propertiesUserOptions: UserOptions = {};
|
||||
tree: HierarchyTree | null = null;
|
||||
propertiesTree: PropertiesTree | null = null;
|
||||
selectedLayer: Layer = {};
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ import { PersistentStore } from "common/persistent_store";
|
||||
<div fxLayout="row wrap" fxLayoutGap="10px grid" class="card-grid">
|
||||
<mat-card id="sf-hierarchy-view" class="hierarchy-view">
|
||||
<hierarchy-view
|
||||
[tree]="inputData?.tree"
|
||||
[tree]="inputData?.tree ?? null"
|
||||
[dependencies]="inputData?.dependencies ?? []"
|
||||
[highlightedItems]="inputData?.highlightedItems ?? []"
|
||||
[pinnedItems]="inputData?.pinnedItems ?? []"
|
||||
@@ -49,9 +49,8 @@ import { PersistentStore } from "common/persistent_store";
|
||||
<mat-card id="sf-properties-view" class="properties-view">
|
||||
<properties-view
|
||||
[userOptions]="inputData?.propertiesUserOptions ?? {}"
|
||||
[selectedTree]="inputData?.selectedTree ?? {}"
|
||||
[selectedLayer]="inputData?.selectedLayer ?? {}"
|
||||
[summary]="inputData?.selectedTreeSummary ?? []"
|
||||
[propertiesTree]="inputData?.propertiesTree ?? {}"
|
||||
[selectedFlickerItem]="inputData?.selectedLayer ?? {}"
|
||||
[propertyGroups]="true"
|
||||
></properties-view>
|
||||
</mat-card>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
9/*
|
||||
9;/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -18,64 +18,26 @@ 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 { DiffType, PropertiesTree, Terminal, Tree } from "viewers/common/tree_utils";
|
||||
import { PropertiesTree, Terminal, HierarchyTree } 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";
|
||||
|
||||
describe("PresenterWindowManager", () => {
|
||||
let presenter: Presenter;
|
||||
let uiData: UiData;
|
||||
let entries: Map<TraceType, any>;
|
||||
let selectedItem: Tree;
|
||||
let selectedTree: HierarchyTree;
|
||||
|
||||
beforeAll(async () => {
|
||||
entries = new Map<TraceType, any>();
|
||||
const entry: WindowManagerState = await UnitTestUtils.getWindowManagerState();
|
||||
selectedItem = {
|
||||
layerId: "3",
|
||||
name: "Child1",
|
||||
displayId: 0,
|
||||
isVisible: true,
|
||||
stableId: "3 Child1",
|
||||
shortName: undefined,
|
||||
simplifyNames: true,
|
||||
showInFilteredView: true,
|
||||
proto: {
|
||||
name: "KeepInFilter",
|
||||
},
|
||||
chips: [],
|
||||
children: [
|
||||
{
|
||||
layerId: "2",
|
||||
name: "Child2",
|
||||
displayId: 0,
|
||||
children: [],
|
||||
stableId: "2 Child2",
|
||||
shortName: undefined,
|
||||
simplifyNames: true,
|
||||
proto: {
|
||||
name: "KeepInFilter",
|
||||
},
|
||||
isVisible: true,
|
||||
showInFilteredView: true,
|
||||
chips: [],
|
||||
},
|
||||
{
|
||||
layerId: "8",
|
||||
name: "Child8",
|
||||
displayId: 0,
|
||||
children: [],
|
||||
stableId: "8 Child8",
|
||||
shortName: undefined,
|
||||
simplifyNames: true,
|
||||
proto: {
|
||||
name: "RejectFromFilter",
|
||||
},
|
||||
isVisible: true,
|
||||
showInFilteredView: true,
|
||||
chips: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
selectedTree = new HierarchyTreeBuilder().setName("ScreenDecorOverlayBottom")
|
||||
.setStableId("WindowState 2088ac1 ScreenDecorOverlayBottom").setKind("WindowState")
|
||||
.setSimplifyNames(true).setShortName("ScreenDecorOverlayBottom").setLayerId(61)
|
||||
.setFilteredView(true).setIsVisible(true).setChips([VISIBLE_CHIP]).build();
|
||||
|
||||
entries.set(TraceType.WINDOW_MANAGER, [entry, null]);
|
||||
});
|
||||
|
||||
@@ -100,12 +62,12 @@ describe("PresenterWindowManager", () => {
|
||||
expect(propertyOpts).toBeTruthy();
|
||||
|
||||
// does not check specific tree values as tree generation method may change
|
||||
expect(Object.keys(uiData.tree).length > 0).toBeTrue();
|
||||
expect(Object.keys(uiData.tree!).length > 0).toBeTrue();
|
||||
});
|
||||
|
||||
it("can handle unavailable trace entry", () => {
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
expect(Object.keys(uiData.tree).length > 0).toBeTrue();
|
||||
expect(Object.keys(uiData.tree!).length > 0).toBeTrue();
|
||||
const emptyEntries = new Map<TraceType, any>();
|
||||
presenter.notifyCurrentTraceEntries(emptyEntries);
|
||||
expect(uiData.tree).toBeFalsy();
|
||||
@@ -114,11 +76,10 @@ describe("PresenterWindowManager", () => {
|
||||
it("can update pinned items", () => {
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
expect(uiData.pinnedItems).toEqual([]);
|
||||
const pinnedItem = {
|
||||
name: "FirstPinnedItem",
|
||||
layerId: 4,
|
||||
stableId: "TestItem 4 FirstPinnedItem"
|
||||
};
|
||||
|
||||
const pinnedItem = new HierarchyTreeBuilder().setName("FirstPinnedItem")
|
||||
.setStableId("TestItem 4").setLayerId(4).build();
|
||||
|
||||
presenter.updatePinnedItems(pinnedItem);
|
||||
expect(uiData.pinnedItems).toContain(pinnedItem);
|
||||
});
|
||||
@@ -152,12 +113,11 @@ describe("PresenterWindowManager", () => {
|
||||
};
|
||||
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
expect(uiData.tree.children.length).toEqual(1);
|
||||
|
||||
expect(uiData.tree?.children.length).toEqual(1);
|
||||
presenter.updateHierarchyTree(userOptions);
|
||||
expect(uiData.hierarchyUserOptions).toEqual(userOptions);
|
||||
// nested children should now be on same level initial parent
|
||||
expect(uiData.tree.children.length).toEqual(72);
|
||||
expect(uiData.tree?.children.length).toEqual(72);
|
||||
});
|
||||
|
||||
it("can filter hierarchy tree", () => {
|
||||
@@ -178,21 +138,21 @@ describe("PresenterWindowManager", () => {
|
||||
name: "Flat",
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
};
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
presenter.updateHierarchyTree(userOptions);
|
||||
expect(uiData.tree.children.length).toEqual(72);
|
||||
expect(uiData.tree?.children.length).toEqual(72);
|
||||
presenter.filterHierarchyTree("ScreenDecor");
|
||||
// All but two window states should be filtered out
|
||||
expect(uiData.tree.children.length).toEqual(2);
|
||||
expect(uiData.tree?.children.length).toEqual(2);
|
||||
});
|
||||
|
||||
|
||||
it("can set new properties tree and associated ui data", () => {
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
presenter.newPropertiesTree(selectedItem);
|
||||
presenter.newPropertiesTree(selectedTree);
|
||||
// does not check specific tree values as tree transformation method may change
|
||||
expect(Object.keys(uiData.selectedTree).length > 0).toBeTrue();
|
||||
expect(uiData.propertiesTree).toBeTruthy();
|
||||
});
|
||||
|
||||
it("can update properties tree", () => {
|
||||
@@ -214,31 +174,28 @@ describe("PresenterWindowManager", () => {
|
||||
};
|
||||
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
presenter.newPropertiesTree(selectedItem);
|
||||
presenter.newPropertiesTree(selectedTree);
|
||||
expect(uiData.propertiesTree?.diffType).toBeFalsy();
|
||||
presenter.updatePropertiesTree(userOptions);
|
||||
expect(uiData.propertiesUserOptions).toEqual(userOptions);
|
||||
//check that diff type added
|
||||
expect(uiData.selectedTree.diffType).toEqual(DiffType.NONE);
|
||||
expect(uiData.propertiesTree?.diffType).toBeTruthy();
|
||||
});
|
||||
|
||||
it("can filter properties tree", () => {
|
||||
presenter.notifyCurrentTraceEntries(entries);
|
||||
presenter.newPropertiesTree(selectedItem);
|
||||
presenter.newPropertiesTree(selectedTree);
|
||||
|
||||
let nonTerminalChildren = uiData.selectedTree
|
||||
.children.filter(
|
||||
(child: PropertiesTree) => !(child.propertyKey instanceof Terminal)
|
||||
);
|
||||
let nonTerminalChildren = uiData.propertiesTree?.children?.filter(
|
||||
(child: PropertiesTree) => typeof child.propertyKey === "string"
|
||||
) ?? [];
|
||||
|
||||
expect(nonTerminalChildren.length).toEqual(2);
|
||||
expect(nonTerminalChildren.length).toEqual(45);
|
||||
presenter.filterPropertiesTree("visible");
|
||||
|
||||
presenter.filterPropertiesTree("KeepInFilter");
|
||||
|
||||
// one child should be filtered out
|
||||
nonTerminalChildren = uiData.selectedTree
|
||||
.children.filter(
|
||||
(child: PropertiesTree) => !(child.propertyKey instanceof Terminal)
|
||||
);
|
||||
expect(nonTerminalChildren.length).toEqual(1);
|
||||
nonTerminalChildren = uiData.propertiesTree?.children?.filter(
|
||||
(child: PropertiesTree) => typeof child.propertyKey === "string"
|
||||
) ?? [];
|
||||
expect(nonTerminalChildren.length).toEqual(4);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 } from "viewers/common/tree_utils";
|
||||
import { getFilter, FilterType, Tree, HierarchyTree, PropertiesTree, TreeFlickerItem } 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: Tree) {
|
||||
public updatePinnedItems(pinnedItem: HierarchyTree) {
|
||||
const pinnedId = `${pinnedItem.id}`;
|
||||
if (this.pinnedItems.map(item => `${item.id}`).includes(pinnedId)) {
|
||||
this.pinnedItems = this.pinnedItems.filter(pinned => `${pinned.id}` != pinnedId);
|
||||
@@ -78,8 +78,8 @@ export class Presenter {
|
||||
this.updateSelectedTreeUiData();
|
||||
}
|
||||
|
||||
public newPropertiesTree(selectedItem: any) {
|
||||
this.selectedTree = selectedItem;
|
||||
public newPropertiesTree(selectedTree: HierarchyTree) {
|
||||
this.selectedHierarchyTree = selectedTree;
|
||||
this.updateSelectedTreeUiData();
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ export class Presenter {
|
||||
}
|
||||
|
||||
private generateRects(): Rectangle[] {
|
||||
const displayRects = this.entry.displays.map((display: DisplayContent) => {
|
||||
const displayRects = this.entry?.displays?.map((display: DisplayContent) => {
|
||||
const rect = display.displayRect;
|
||||
rect.label = display.title;
|
||||
rect.id = display.layerId;
|
||||
@@ -113,7 +113,7 @@ export class Presenter {
|
||||
return rect;
|
||||
}) ?? [];
|
||||
this.displayIds = [];
|
||||
const rects = this.entry.windowStates.reverse()
|
||||
const rects = this.entry?.windowStates?.reverse()
|
||||
.map((it: any) => {
|
||||
const rect = it.rect;
|
||||
rect.id = it.layerId;
|
||||
@@ -122,13 +122,13 @@ export class Presenter {
|
||||
this.displayIds.push(it.displayId);
|
||||
}
|
||||
return rect;
|
||||
});
|
||||
}) ?? [];
|
||||
return this.rectsToUiData(rects.concat(displayRects));
|
||||
}
|
||||
|
||||
private updateSelectedTreeUiData() {
|
||||
if (this.selectedTree) {
|
||||
this.uiData.selectedTree = this.getTreeWithTransformedProperties(this.selectedTree);
|
||||
if (this.selectedHierarchyTree) {
|
||||
this.uiData.propertiesTree = this.getTreeWithTransformedProperties(this.selectedHierarchyTree);
|
||||
}
|
||||
this.notifyViewCallback(this.uiData);
|
||||
}
|
||||
@@ -143,13 +143,13 @@ export class Presenter {
|
||||
.setIsSimplifyNames(this.hierarchyUserOptions["simplifyNames"]?.enabled)
|
||||
.setIsFlatView(this.hierarchyUserOptions["flat"]?.enabled)
|
||||
.withUniqueNodeId();
|
||||
let tree: Tree;
|
||||
let tree: HierarchyTree | null;
|
||||
if (!this.hierarchyUserOptions["showDiff"]?.enabled) {
|
||||
tree = generator.generateTree();
|
||||
} else {
|
||||
tree = generator.compareWith(this.previousEntry)
|
||||
.withModifiedCheck()
|
||||
.generateFinalDiffTree();
|
||||
.generateFinalTreeWithDiff();
|
||||
}
|
||||
this.pinnedItems = generator.getPinnedItems();
|
||||
this.uiData.pinnedItems = this.pinnedItems;
|
||||
@@ -208,11 +208,16 @@ export class Presenter {
|
||||
}
|
||||
}
|
||||
|
||||
private getTreeWithTransformedProperties(selectedTree: Tree) {
|
||||
private getTreeWithTransformedProperties(selectedTree: HierarchyTree): PropertiesTree {
|
||||
if (!this.entry) {
|
||||
return {};
|
||||
}
|
||||
const transformer = new TreeTransformer(selectedTree, this.propertiesFilter)
|
||||
.showOnlyProtoDump()
|
||||
.setIsShowDefaults(this.propertiesUserOptions["showDefaults"]?.enabled)
|
||||
.setIsShowDiff(this.propertiesUserOptions["showDiff"]?.enabled)
|
||||
.setTransformerOptions({skip: selectedTree.skip})
|
||||
.setProperties(this.entry)
|
||||
.setDiffProperties(this.previousEntry);
|
||||
const transformedTree = transformer.transform();
|
||||
return transformedTree;
|
||||
@@ -224,11 +229,11 @@ export class Presenter {
|
||||
private propertiesFilter: FilterType = getFilter("");
|
||||
private highlightedItems: Array<string> = [];
|
||||
private displayIds: Array<number> = [];
|
||||
private pinnedItems: Array<Tree> = [];
|
||||
private pinnedItems: Array<HierarchyTree> = [];
|
||||
private pinnedIds: Array<string> = [];
|
||||
private selectedTree: any = null;
|
||||
private previousEntry: any = null;
|
||||
private entry: any = null;
|
||||
private selectedHierarchyTree: HierarchyTree | null = null;
|
||||
private previousEntry: TreeFlickerItem | null = null;
|
||||
private entry: TreeFlickerItem | null = null;
|
||||
private hierarchyUserOptions: UserOptions = {
|
||||
showDiff: {
|
||||
name: "Show diff",
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Tree } from "viewers/common/tree_utils";
|
||||
import { HierarchyTree, PropertiesTree } 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";
|
||||
|
||||
export class UiData {
|
||||
dependencies: Array<TraceType> = [TraceType.WINDOW_MANAGER];
|
||||
rects?: Rectangle[] = [];
|
||||
displayIds?: number[] = [];
|
||||
highlightedItems?: Array<string> = [];
|
||||
pinnedItems?: Array<Tree> = [];
|
||||
hierarchyUserOptions?: UserOptions = {};
|
||||
propertiesUserOptions?: UserOptions = {};
|
||||
tree?: Tree | null = null;
|
||||
selectedTree?: any = {};
|
||||
rects: Rectangle[] = [];
|
||||
displayIds: number[] = [];
|
||||
highlightedItems: Array<string> = [];
|
||||
pinnedItems: Array<HierarchyTree> = [];
|
||||
hierarchyUserOptions: UserOptions = {};
|
||||
propertiesUserOptions: UserOptions = {};
|
||||
tree: HierarchyTree | null = null;
|
||||
propertiesTree: PropertiesTree | null = null;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ import { PersistentStore } from "common/persistent_store";
|
||||
<div fxLayout="row wrap" fxLayoutGap="10px grid" class="card-grid">
|
||||
<mat-card id="wm-hierarchy-view" class="hierarchy-view">
|
||||
<hierarchy-view
|
||||
[tree]="inputData?.tree"
|
||||
[tree]="inputData?.tree ?? null"
|
||||
[dependencies]="inputData?.dependencies ?? []"
|
||||
[highlightedItems]="inputData?.highlightedItems ?? []"
|
||||
[pinnedItems]="inputData?.pinnedItems ?? []"
|
||||
@@ -48,7 +48,7 @@ import { PersistentStore } from "common/persistent_store";
|
||||
<mat-card id="wm-properties-view" class="properties-view">
|
||||
<properties-view
|
||||
[userOptions]="inputData?.propertiesUserOptions ?? {}"
|
||||
[selectedTree]="inputData?.selectedTree ?? {}"
|
||||
[propertiesTree]="inputData?.propertiesTree ?? {}"
|
||||
></properties-view>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user