diff --git a/tools/winscope-ng/src/app/app.module.ts b/tools/winscope-ng/src/app/app.module.ts index 5aa92634b..bb20e1833 100644 --- a/tools/winscope-ng/src/app/app.module.ts +++ b/tools/winscope-ng/src/app/app.module.ts @@ -42,6 +42,9 @@ import { PropertyGroupsComponent } from "viewers/components/property_groups.comp import { TransformMatrixComponent } from "viewers/components/transform_matrix.component"; import { ParserErrorSnackBarComponent } from "./components/parser_error_snack_bar_component"; import { ViewerInputMethodComponent } from "viewers/components/viewer_input_method.component"; +import { PropertiesTableComponent } from "viewers/components/properties_table.component"; +import { ImeAdditionalPropertiesComponent } from "viewers/components/ime_additional_properties.component"; +import { CoordinatesTableComponent } from "viewers/components/coordinates_table.component"; @NgModule({ declarations: [ @@ -64,7 +67,10 @@ import { ViewerInputMethodComponent } from "viewers/components/viewer_input_meth TreeNodePropertiesDataViewComponent, PropertyGroupsComponent, TransformMatrixComponent, - ParserErrorSnackBarComponent + ParserErrorSnackBarComponent, + PropertiesTableComponent, + ImeAdditionalPropertiesComponent, + CoordinatesTableComponent, ], imports: [ BrowserModule, @@ -89,7 +95,7 @@ import { ViewerInputMethodComponent } from "viewers/components/viewer_input_meth MatTooltipModule, MatToolbarModule, MatTabsModule, - MatSnackBarModule + MatSnackBarModule, ], bootstrap: [AppComponent] }) diff --git a/tools/winscope-ng/src/viewers/common/ime_additional_properties.ts b/tools/winscope-ng/src/viewers/common/ime_additional_properties.ts new file mode 100644 index 000000000..52e7610f7 --- /dev/null +++ b/tools/winscope-ng/src/viewers/common/ime_additional_properties.ts @@ -0,0 +1,23 @@ +/* + * 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 { ImeLayers, ProcessedWindowManagerState } from "./ime_utils"; + +export class ImeAdditionalProperties { + constructor( + public wm: ProcessedWindowManagerState | undefined, + public sf: ImeLayers | undefined, + ) {} +} diff --git a/tools/winscope-ng/src/viewers/common/ime_presenter_clients.spec.ts b/tools/winscope-ng/src/viewers/common/ime_presenter_clients.spec.ts deleted file mode 100644 index 17013f4b0..000000000 --- a/tools/winscope-ng/src/viewers/common/ime_presenter_clients.spec.ts +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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 { ImePresenter } from "./ime_presenter"; -import { ImeUiData } from "./ime_ui_data"; -import { UserOptions } from "viewers/common/user_options"; -import { TraceType } from "common/trace/trace_type"; -import { HierarchyTreeNode, PropertiesTreeNode } from "viewers/common/ui_tree_utils"; -import { UnitTestUtils } from "test/unit/utils"; -import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder"; - -describe("ImePresenterInputMethodClients", () => { - let presenter: ImePresenter; - let uiData: ImeUiData; - let entries: Map; - let selectedTree: HierarchyTreeNode; - - beforeAll(async () => { - entries = new Map(); - const entry: any = await UnitTestUtils.getInputMethodClientsEntry(); - entries.set(TraceType.INPUT_METHOD_CLIENTS, [entry, null]); - - selectedTree = new HierarchyTreeBuilder().setName("8m23s29ms - InputMethodManager#showSoftInput") - .setFilteredView(true).setKind("InputMethodClient entry").setId("entry").setStableId("entry") - .setChildren([ - new HierarchyTreeBuilder().setKind("Client").setId("client").setFilteredView(true) - .setStableId("client").build() - ]).build(); - }); - - beforeEach(async () => { - presenter = new ImePresenter((newData: ImeUiData) => { - uiData = newData; - }, [TraceType.INPUT_METHOD_CLIENTS]); - }); - - it("can notify current trace entries", () => { - presenter.notifyCurrentTraceEntries(entries); - expect(uiData.highlightedItems?.length).toEqual(0); - expect(uiData.hierarchyUserOptions).toBeTruthy(); - expect(uiData.propertiesUserOptions).toBeTruthy(); - - // does not check specific tree values as tree generation method may change - 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(); - const emptyEntries = new Map(); - presenter.notifyCurrentTraceEntries(emptyEntries); - expect(uiData.tree).toBeFalsy(); - }); - - it("can update pinned items", () => { - expect(uiData.pinnedItems).toEqual([]); - const pinnedItem = new HierarchyTreeBuilder().setName("FirstPinnedItem") - .setStableId("TestItem 4").setLayerId(4).build(); - presenter.updatePinnedItems(pinnedItem); - expect(uiData.pinnedItems).toContain(pinnedItem); - }); - - it("can update highlighted items", () => { - expect(uiData.highlightedItems).toEqual([]); - const id = "entry"; - presenter.updateHighlightedItems(id); - expect(uiData.highlightedItems).toContain(id); - }); - - it("can update hierarchy tree", () => { - //change flat view to true - const userOptions: UserOptions = { - onlyVisible: { - name: "Only visible", - enabled: true - }, - simplifyNames: { - name: "Simplify names", - enabled: true - }, - flat: { - name: "Flat", - enabled: false - } - }; - - presenter.notifyCurrentTraceEntries(entries); - expect(uiData.tree?.children.length).toEqual(1); - - presenter.updateHierarchyTree(userOptions); - expect(uiData.hierarchyUserOptions).toEqual(userOptions); - // non visible child filtered out - expect(uiData.tree?.children.length).toEqual(0); - }); - - it("can filter hierarchy tree", () => { - const userOptions: UserOptions = { - onlyVisible: { - name: "Only visible", - enabled: false - }, - simplifyNames: { - name: "Simplify names", - enabled: true - }, - flat: { - name: "Flat", - enabled: true - } - }; - presenter.notifyCurrentTraceEntries(entries); - presenter.updateHierarchyTree(userOptions); - expect(uiData.tree?.children.length).toEqual(1); - presenter.filterHierarchyTree("Reject all"); - // All children should be filtered out - expect(uiData.tree?.children.length).toEqual(0); - }); - - - it("can set new properties tree and associated ui data", () => { - presenter.notifyCurrentTraceEntries(entries); - presenter.newPropertiesTree(selectedTree); - // does not check specific tree values as tree transformation method may change - expect(uiData.propertiesTree).toBeTruthy(); - }); - - it("can filter properties tree", () => { - presenter.notifyCurrentTraceEntries(entries); - presenter.newPropertiesTree(selectedTree); - let nonTerminalChildren = uiData.propertiesTree?.children?.filter( - (child: PropertiesTreeNode) => typeof child.propertyKey === "string" - ) ?? []; - - expect(nonTerminalChildren.length).toEqual(3); - presenter.filterPropertiesTree("elapsed"); - - nonTerminalChildren = uiData.propertiesTree?.children?.filter( - (child: PropertiesTreeNode) => typeof child.propertyKey === "string" - ) ?? []; - expect(nonTerminalChildren.length).toEqual(1); - }); -}); diff --git a/tools/winscope-ng/src/viewers/common/ime_presenter_manager_service.spec.ts b/tools/winscope-ng/src/viewers/common/ime_presenter_manager_service.spec.ts deleted file mode 100644 index acd3ff79a..000000000 --- a/tools/winscope-ng/src/viewers/common/ime_presenter_manager_service.spec.ts +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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 { ImePresenter } from "./ime_presenter"; -import { ImeUiData } from "./ime_ui_data"; -import { UserOptions } from "viewers/common/user_options"; -import { TraceType } from "common/trace/trace_type"; -import { HierarchyTreeNode, PropertiesTreeNode } from "viewers/common/ui_tree_utils"; -import { UnitTestUtils } from "test/unit/utils"; -import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder"; - -describe("ImePresenterInputMethodManagerService", () => { - let presenter: ImePresenter; - let uiData: ImeUiData; - let entries: Map; - let selectedTree: HierarchyTreeNode; - - beforeAll(async () => { - entries = new Map(); - const entry: any = await UnitTestUtils.getInputMethodManagerServiceEntry(); - entries.set(TraceType.INPUT_METHOD_MANAGER_SERVICE, [entry, null]); - - selectedTree = new HierarchyTreeBuilder() - .setFilteredView(true).setKind("InputMethodManagerService").setId("managerservice") - .setStableId("managerservice").build(); - }); - - beforeEach(async () => { - presenter = new ImePresenter((newData: ImeUiData) => { - uiData = newData; - }, [TraceType.INPUT_METHOD_MANAGER_SERVICE]); - }); - - it("can notify current trace entries", () => { - presenter.notifyCurrentTraceEntries(entries); - expect(uiData.hierarchyUserOptions).toBeTruthy(); - expect(uiData.propertiesUserOptions).toBeTruthy(); - - // does not check specific tree values as tree generation method may change - 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(); - const emptyEntries = new Map(); - presenter.notifyCurrentTraceEntries(emptyEntries); - expect(uiData.tree).toBeFalsy(); - }); - - it("can update pinned items", () => { - expect(uiData.pinnedItems).toEqual([]); - const pinnedItem = new HierarchyTreeBuilder().setName("FirstPinnedItem") - .setStableId("TestItem 4").setLayerId(4).build(); - presenter.updatePinnedItems(pinnedItem); - expect(uiData.pinnedItems).toContain(pinnedItem); - }); - - it("can update highlighted items", () => { - expect(uiData.highlightedItems).toEqual([]); - const id = "entry"; - presenter.updateHighlightedItems(id); - expect(uiData.highlightedItems).toContain(id); - }); - - it("can update hierarchy tree", () => { - //change flat view to true - const userOptions: UserOptions = { - onlyVisible: { - name: "Only visible", - enabled: true - }, - simplifyNames: { - name: "Simplify names", - enabled: true - }, - flat: { - name: "Flat", - enabled: false - } - }; - - presenter.notifyCurrentTraceEntries(entries); - expect(uiData.tree?.children.length).toEqual(1); - - presenter.updateHierarchyTree(userOptions); - expect(uiData.hierarchyUserOptions).toEqual(userOptions); - // non visible child filtered out - expect(uiData.tree?.children.length).toEqual(0); - }); - - it("can filter hierarchy tree", () => { - const userOptions: UserOptions = { - onlyVisible: { - name: "Only visible", - enabled: false - }, - simplifyNames: { - name: "Simplify names", - enabled: true - }, - flat: { - name: "Flat", - enabled: true - } - }; - presenter.notifyCurrentTraceEntries(entries); - presenter.updateHierarchyTree(userOptions); - expect(uiData.tree?.children.length).toEqual(1); - presenter.filterHierarchyTree("Reject all"); - // All children should be filtered out - expect(uiData.tree?.children.length).toEqual(0); - }); - - - it("can set new properties tree and associated ui data", () => { - presenter.notifyCurrentTraceEntries(entries); - presenter.newPropertiesTree(selectedTree); - // does not check specific tree values as tree transformation method may change - expect(uiData.propertiesTree).toBeTruthy(); - }); - - it("can filter properties tree", () => { - presenter.notifyCurrentTraceEntries(entries); - presenter.newPropertiesTree(selectedTree); - let nonTerminalChildren = uiData.propertiesTree?.children?.filter( - (child: PropertiesTreeNode) => typeof child.propertyKey === "string" - ) ?? []; - - expect(nonTerminalChildren.length).toEqual(13); - presenter.filterPropertiesTree("cur"); - - nonTerminalChildren = uiData.propertiesTree?.children?.filter( - (child: PropertiesTreeNode) => typeof child.propertyKey === "string" - ) ?? []; - expect(nonTerminalChildren.length).toEqual(8); - }); -}); diff --git a/tools/winscope-ng/src/viewers/common/ime_presenter_service.spec.ts b/tools/winscope-ng/src/viewers/common/ime_presenter_service.spec.ts deleted file mode 100644 index 270867c65..000000000 --- a/tools/winscope-ng/src/viewers/common/ime_presenter_service.spec.ts +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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 { ImePresenter } from "./ime_presenter"; -import { ImeUiData } from "./ime_ui_data"; -import { UserOptions } from "viewers/common/user_options"; -import { TraceType } from "common/trace/trace_type"; -import { HierarchyTreeNode, PropertiesTreeNode } from "viewers/common/ui_tree_utils"; -import { UnitTestUtils } from "test/unit/utils"; -import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder"; - -describe("ImePresenterInputMethodService", () => { - let presenter: ImePresenter; - let uiData: ImeUiData; - let entries: Map; - let selectedTree: HierarchyTreeNode; - - beforeAll(async () => { - entries = new Map(); - const entry: any = await UnitTestUtils.getInputMethodServiceEntry(); - entries.set(TraceType.INPUT_METHOD_SERVICE, [entry, null]); - - selectedTree = new HierarchyTreeBuilder().setKind("InputMethodService") - .setId("service").setFilteredView(true).setStableId("service").build(); - }); - - beforeEach(async () => { - presenter = new ImePresenter((newData: ImeUiData) => { - uiData = newData; - }, [TraceType.INPUT_METHOD_SERVICE]); - }); - - it("can notify current trace entries", () => { - presenter.notifyCurrentTraceEntries(entries); - expect(uiData.hierarchyUserOptions).toBeTruthy(); - expect(uiData.propertiesUserOptions).toBeTruthy(); - - // does not check specific tree values as tree generation method may change - 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(); - const emptyEntries = new Map(); - presenter.notifyCurrentTraceEntries(emptyEntries); - expect(uiData.tree).toBeFalsy(); - }); - - it("can update pinned items", () => { - expect(uiData.pinnedItems).toEqual([]); - const pinnedItem = new HierarchyTreeBuilder().setName("FirstPinnedItem") - .setStableId("TestItem 4").setLayerId(4).build(); - presenter.updatePinnedItems(pinnedItem); - expect(uiData.pinnedItems).toContain(pinnedItem); - }); - - it("can update highlighted items", () => { - expect(uiData.highlightedItems).toEqual([]); - const id = "entry"; - presenter.updateHighlightedItems(id); - expect(uiData.highlightedItems).toContain(id); - }); - - it("can update hierarchy tree", () => { - //change flat view to true - const userOptions: UserOptions = { - onlyVisible: { - name: "Only visible", - enabled: true - }, - simplifyNames: { - name: "Simplify names", - enabled: true - }, - flat: { - name: "Flat", - enabled: false - } - }; - - presenter.notifyCurrentTraceEntries(entries); - expect(uiData.tree?.children.length).toEqual(1); - - presenter.updateHierarchyTree(userOptions); - expect(uiData.hierarchyUserOptions).toEqual(userOptions); - // non visible child filtered out - expect(uiData.tree?.children.length).toEqual(0); - }); - - it("can filter hierarchy tree", () => { - const userOptions: UserOptions = { - onlyVisible: { - name: "Only visible", - enabled: false - }, - simplifyNames: { - name: "Simplify names", - enabled: true - }, - flat: { - name: "Flat", - enabled: true - } - }; - presenter.notifyCurrentTraceEntries(entries); - presenter.updateHierarchyTree(userOptions); - expect(uiData.tree?.children.length).toEqual(1); - presenter.filterHierarchyTree("Reject all"); - // All children should be filtered out - expect(uiData.tree?.children.length).toEqual(0); - }); - - - it("can set new properties tree and associated ui data", () => { - presenter.notifyCurrentTraceEntries(entries); - presenter.newPropertiesTree(selectedTree); - // does not check specific tree values as tree transformation method may change - expect(uiData.propertiesTree).toBeTruthy(); - }); - - it("can filter properties tree", () => { - presenter.notifyCurrentTraceEntries(entries); - presenter.newPropertiesTree(selectedTree); - let nonTerminalChildren = uiData.propertiesTree?.children?.filter( - (child: PropertiesTreeNode) => typeof child.propertyKey === "string" - ) ?? []; - - expect(nonTerminalChildren.length).toEqual(13); - presenter.filterPropertiesTree("visib"); - - nonTerminalChildren = uiData.propertiesTree?.children?.filter( - (child: PropertiesTreeNode) => typeof child.propertyKey === "string" - ) ?? []; - expect(nonTerminalChildren.length).toEqual(3); - }); -}); diff --git a/tools/winscope-ng/src/viewers/common/ime_ui_data.ts b/tools/winscope-ng/src/viewers/common/ime_ui_data.ts index 925fa8aef..f0e6849b9 100644 --- a/tools/winscope-ng/src/viewers/common/ime_ui_data.ts +++ b/tools/winscope-ng/src/viewers/common/ime_ui_data.ts @@ -13,9 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { HierarchyTreeNode, PropertiesTreeNode } from "./ui_tree_utils"; +import { HierarchyTreeNode, PropertiesTreeNode } from "viewers/common/ui_tree_utils"; import { UserOptions } from "viewers/common/user_options"; import { TraceType } from "common/trace/trace_type"; +import { TableProperties } from "viewers/common/table_properties"; +import { ImeAdditionalProperties } from "viewers/common/ime_additional_properties"; export class ImeUiData { dependencies: Array; @@ -25,6 +27,8 @@ export class ImeUiData { propertiesUserOptions: UserOptions = {}; tree: HierarchyTreeNode | null = null; propertiesTree: PropertiesTreeNode | null = null; + hierarchyTableProperties: TableProperties | null = null; + additionalProperties: ImeAdditionalProperties | null = null; constructor(dependencies?: Array) { this.dependencies = dependencies ?? []; diff --git a/tools/winscope-ng/src/viewers/common/ime_utils.ts b/tools/winscope-ng/src/viewers/common/ime_utils.ts index b7d93a67d..99386124c 100644 --- a/tools/winscope-ng/src/viewers/common/ime_utils.ts +++ b/tools/winscope-ng/src/viewers/common/ime_utils.ts @@ -23,6 +23,7 @@ import {TreeUtils, FilterType} from "common/utils/tree_utils"; class ProcessedWindowManagerState { constructor( + public name: string, public stableId: string, public focusedApp: string, public focusedWindow: WindowState, @@ -31,17 +32,20 @@ class ProcessedWindowManagerState { public protoImeControlTarget: any, public protoImeInputTarget: any, public protoImeLayeringTarget: any, - public protoImeInsetsSourceProvider: any) { - } + public protoImeInsetsSourceProvider: any, + public proto: any + ) {} } class ImeLayers { constructor( + public name: string, public imeContainer: Layer, public inputMethodSurface: Layer, public focusedWindow: Layer|undefined, public taskOfImeContainer: Layer|undefined, - public taskOfImeSnapshot: Layer|undefined) { + public taskOfImeSnapshot: Layer|undefined + ) { } } @@ -50,6 +54,7 @@ class ImeUtils { const displayContent = entry.root.children[0]; return new ProcessedWindowManagerState( + entry.name, entry.stableId, entry.focusedApp, entry.focusedWindow, @@ -58,7 +63,8 @@ class ImeUtils { this.getImeControlTargetProperty(displayContent.proto), this.getImeInputTargetProperty(displayContent.proto), this.getImeLayeringTargetProperty(displayContent.proto), - displayContent.proto.imeInsetsSourceProvider + displayContent.proto.imeInsetsSourceProvider, + entry.proto, ); } @@ -91,6 +97,7 @@ class ImeUtils { this.findAncestorTaskLayerOfImeLayer(entry, TreeUtils.makeNodeFilter("IME-snapshot")); return new ImeLayers( + entry.name, imeContainer, inputMethodSurface, focusedWindowLayer, @@ -154,4 +161,4 @@ class ImeUtils { } } -export {ImeUtils}; +export {ImeUtils, ProcessedWindowManagerState, ImeLayers}; diff --git a/tools/winscope-ng/src/viewers/common/ime_presenter.ts b/tools/winscope-ng/src/viewers/common/presenter_input_method.ts similarity index 66% rename from tools/winscope-ng/src/viewers/common/ime_presenter.ts rename to tools/winscope-ng/src/viewers/common/presenter_input_method.ts index 5513c6426..facc5e77a 100644 --- a/tools/winscope-ng/src/viewers/common/ime_presenter.ts +++ b/tools/winscope-ng/src/viewers/common/presenter_input_method.ts @@ -14,17 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImeUiData } from "./ime_ui_data"; +import { ImeUiData } from "viewers/common/ime_ui_data"; import { TraceType } from "common/trace/trace_type"; import { UserOptions } from "viewers/common/user_options"; import { HierarchyTreeNode, PropertiesTreeNode } from "viewers/common/ui_tree_utils"; import { TreeGenerator } from "viewers/common/tree_generator"; import { TreeTransformer } from "viewers/common/tree_transformer"; import { TreeUtils, FilterType } from "common/utils/tree_utils"; +import { TraceTreeNode } from "common/trace/trace_tree_node"; +import { ImeLayers, ImeUtils, ProcessedWindowManagerState } from "viewers/common/ime_utils"; +import { ImeAdditionalProperties } from "viewers/common/ime_additional_properties"; +import { TableProperties } from "viewers/common/table_properties"; -export type NotifyImeViewCallbackType = (uiData: ImeUiData) => void; +type NotifyImeViewCallbackType = (uiData: ImeUiData) => void; -export class ImePresenter { +export abstract class PresenterInputMethod { constructor( notifyViewCallback: NotifyImeViewCallbackType, dependencies: Array @@ -83,34 +87,71 @@ export class ImePresenter { } public newPropertiesTree(selectedItem: HierarchyTreeNode) { + this.additionalPropertyEntry = null; this.selectedHierarchyTree = selectedItem; this.updateSelectedTreeUiData(); } + public newAdditionalPropertiesTree(selectedItem: any) { + this.selectedHierarchyTree = new HierarchyTreeNode(selectedItem.name, "AdditionalProperty", "AdditionalProperty"); + this.additionalPropertyEntry = { + name: selectedItem.name, + kind: "AdditionalProperty", + children: [], + stableId: "AdditionalProperty", + proto: selectedItem.proto, + }; + this.updateSelectedTreeUiData(); + } + public notifyCurrentTraceEntries(entries: Map) { this.uiData = new ImeUiData(this.dependencies); this.uiData.hierarchyUserOptions = this.hierarchyUserOptions; this.uiData.propertiesUserOptions = this.propertiesUserOptions; - const imeEntries = entries.get(this.dependencies[0]); - if (imeEntries) { - this.entry = imeEntries[0]; - if (this.entry) { - this.uiData.highlightedItems = this.highlightedItems; - this.uiData.tree = this.generateTree(); - } + const imEntries = entries.get(this.dependencies[0]); + if (imEntries && imEntries[0]) { + this.entry = imEntries[0]; + this.uiData.highlightedItems = this.highlightedItems; + + const wmEntries = entries.get(TraceType.WINDOW_MANAGER); + const sfEntries = entries.get(TraceType.SURFACE_FLINGER); + + this.uiData.additionalProperties = this.getAdditionalProperties( + wmEntries ? wmEntries[0] : undefined, + sfEntries ? sfEntries[0] : undefined + ); + + this.uiData.tree = this.generateTree(); + this.uiData.hierarchyTableProperties = this.updateHierarchyTableProperties(); } this.notifyViewCallback(this.uiData); } - private updateSelectedTreeUiData() { - if (this.selectedHierarchyTree) { - this.uiData.propertiesTree = this.getTreeWithTransformedProperties(this.selectedHierarchyTree); + protected getAdditionalProperties(wmEntry: TraceTreeNode | undefined, sfEntry: TraceTreeNode | undefined) { + let wmProperties: ProcessedWindowManagerState | undefined; + let sfProperties: ImeLayers | undefined; + let sfSubtrees: any[]; + if (wmEntry) { + wmProperties = ImeUtils.processWindowManagerTraceEntry(wmEntry); + sfProperties = ImeUtils.getImeLayers(sfEntry, wmProperties); + sfSubtrees = [sfProperties?.taskOfImeContainer, sfProperties?.taskOfImeSnapshot] + .filter((node) => node) // filter away null values + .map((node) => { + node.kind = "SF subtree - " + node.id; + return node; + }); + this.entry?.children.push(...sfSubtrees); } - this.notifyViewCallback(this.uiData); + + return new ImeAdditionalProperties( + wmProperties, + sfProperties, + ); } - private generateTree() { + + protected generateTree() { if (!this.entry) { return null; } @@ -126,6 +167,12 @@ export class ImePresenter { return tree; } + private updateSelectedTreeUiData() { + if (this.selectedHierarchyTree) { + this.uiData.propertiesTree = this.getTreeWithTransformedProperties(this.selectedHierarchyTree); + } + this.notifyViewCallback(this.uiData); + } private updatePinnedIds(newId: string) { if (this.pinnedIds.includes(newId)) { this.pinnedIds = this.pinnedIds.filter(pinned => pinned != newId); @@ -136,24 +183,27 @@ export class ImePresenter { private getTreeWithTransformedProperties(selectedTree: HierarchyTreeNode): PropertiesTreeNode { const transformer = new TreeTransformer(selectedTree, this.propertiesFilter) + .setOnlyProtoDump(this.additionalPropertyEntry != null) .setIsShowDefaults(this.propertiesUserOptions["showDefaults"]?.enabled) .setTransformerOptions({skip: selectedTree.skip}) - .setProperties(this.entry); + .setProperties(this.additionalPropertyEntry ?? this.entry); const transformedTree = transformer.transform(); return transformedTree; } - readonly notifyViewCallback: NotifyImeViewCallbackType; - readonly dependencies: Array; - uiData: ImeUiData; private hierarchyFilter: FilterType = TreeUtils.makeNodeFilter(""); private propertiesFilter: FilterType = TreeUtils.makeNodeFilter(""); - private highlightedItems: Array = []; private pinnedItems: Array = []; private pinnedIds: Array = []; private selectedHierarchyTree: HierarchyTreeNode | null = null; - private entry: any = null; - private hierarchyUserOptions: UserOptions = { + + readonly notifyViewCallback: NotifyImeViewCallbackType; + protected readonly dependencies: Array; + protected uiData: ImeUiData; + protected highlightedItems: Array = []; + protected entry: TraceTreeNode | null = null; + protected additionalPropertyEntry: TraceTreeNode | null = null; + protected hierarchyUserOptions: UserOptions = { simplifyNames: { name: "Simplify names", enabled: true @@ -167,8 +217,7 @@ export class ImePresenter { enabled: false } }; - - private propertiesUserOptions: UserOptions = { + protected propertiesUserOptions: UserOptions = { showDefaults: { name: "Show defaults", enabled: true, @@ -179,4 +228,6 @@ export class ImePresenter { ` }, }; + + protected abstract updateHierarchyTableProperties(): TableProperties; } diff --git a/tools/winscope-ng/src/viewers/common/presenter_input_method_test_utils.ts b/tools/winscope-ng/src/viewers/common/presenter_input_method_test_utils.ts new file mode 100644 index 000000000..be3993bbe --- /dev/null +++ b/tools/winscope-ng/src/viewers/common/presenter_input_method_test_utils.ts @@ -0,0 +1,157 @@ +/* + * 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.d + */ +import { ImeUiData } from "viewers/common/ime_ui_data"; +import { UserOptions } from "viewers/common/user_options"; +import { TraceType } from "common/trace/trace_type"; +import { HierarchyTreeNode, PropertiesTreeNode } from "viewers/common/ui_tree_utils"; +import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder"; +import { PresenterInputMethod } from "./presenter_input_method"; +import { PresenterInputMethodClients } from "viewers/viewer_input_method_clients/presenter_input_method_clients"; +import { PresenterInputMethodService } from "viewers/viewer_input_method_service/presenter_input_method_service"; +import { PresenterInputMethodManagerService } from "viewers/viewer_input_method_manager_service/presenter_input_method_manager_service"; + +export function executePresenterInputMethodTests( + getEntry: () => any, + selected: HierarchyTreeNode, + propertiesTreeFilterString: string, + expectedChildren: [number, number], + PresenterInputMethod: typeof PresenterInputMethodClients | typeof PresenterInputMethodService | typeof PresenterInputMethodManagerService, + traceType: TraceType, +) { + describe("PresenterInputMethod", () => { + let presenter: PresenterInputMethod; + let uiData: ImeUiData; + let entries: Map; + let selectedTree: HierarchyTreeNode; + + beforeAll(async () => { + const entry = await getEntry(); + entries = new Map(); + entries.set(traceType, [entry, null]); + selectedTree = selected; + }); + + beforeEach(async () => { + presenter = new PresenterInputMethod((newData: ImeUiData) => { + uiData = newData; + }, [traceType]); + }); + + it("can notify current trace entries", () => { + presenter.notifyCurrentTraceEntries(entries); + expect(uiData.hierarchyUserOptions).toBeTruthy(); + expect(uiData.propertiesUserOptions).toBeTruthy(); + + // does not check specific tree values as tree generation method may change + 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(); + const emptyEntries = new Map(); + presenter.notifyCurrentTraceEntries(emptyEntries); + expect(uiData.tree).toBeFalsy(); + }); + + it("can update pinned items", () => { + expect(uiData.pinnedItems).toEqual([]); + const pinnedItem = new HierarchyTreeBuilder().setName("FirstPinnedItem") + .setStableId("TestItem 4").setLayerId(4).build(); + presenter.updatePinnedItems(pinnedItem); + expect(uiData.pinnedItems).toContain(pinnedItem); + }); + + it("can update highlighted items", () => { + expect(uiData.highlightedItems).toEqual([]); + const id = "entry"; + presenter.updateHighlightedItems(id); + expect(uiData.highlightedItems).toContain(id); + }); + + it("can update hierarchy tree", () => { + //change flat view to true + const userOptions: UserOptions = { + onlyVisible: { + name: "Only visible", + enabled: true + }, + simplifyNames: { + name: "Simplify names", + enabled: true + }, + flat: { + name: "Flat", + enabled: false + } + }; + + presenter.notifyCurrentTraceEntries(entries); + expect(uiData.tree?.children.length).toEqual(1); + + presenter.updateHierarchyTree(userOptions); + expect(uiData.hierarchyUserOptions).toEqual(userOptions); + // non visible child filtered out + expect(uiData.tree?.children.length).toEqual(0); + }); + + it("can filter hierarchy tree", () => { + const userOptions: UserOptions = { + onlyVisible: { + name: "Only visible", + enabled: false + }, + simplifyNames: { + name: "Simplify names", + enabled: true + }, + flat: { + name: "Flat", + enabled: true + } + }; + presenter.notifyCurrentTraceEntries(entries); + presenter.updateHierarchyTree(userOptions); + expect(uiData.tree?.children.length).toEqual(1); + presenter.filterHierarchyTree("Reject all"); + // All children should be filtered out + expect(uiData.tree?.children.length).toEqual(0); + }); + + it("can set new properties tree and associated ui data", () => { + presenter.notifyCurrentTraceEntries(entries); + presenter.newPropertiesTree(selectedTree); + // does not check specific tree values as tree transformation method may change + expect(uiData.propertiesTree).toBeTruthy(); + }); + + it("can filter properties tree", () => { + presenter.notifyCurrentTraceEntries(entries); + presenter.newPropertiesTree(selectedTree); + let nonTerminalChildren = uiData.propertiesTree?.children?.filter( + (child: PropertiesTreeNode) => typeof child.propertyKey === "string" + ) ?? []; + + expect(nonTerminalChildren.length).toEqual(expectedChildren[0]); + presenter.filterPropertiesTree(propertiesTreeFilterString); + + nonTerminalChildren = uiData.propertiesTree?.children?.filter( + (child: PropertiesTreeNode) => typeof child.propertyKey === "string" + ) ?? []; + expect(nonTerminalChildren.length).toEqual(expectedChildren[1]); + }); + }); +} diff --git a/tools/winscope-ng/src/viewers/common/table_properties.ts b/tools/winscope-ng/src/viewers/common/table_properties.ts new file mode 100644 index 000000000..1c44acdb8 --- /dev/null +++ b/tools/winscope-ng/src/viewers/common/table_properties.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ +export type TableProperties = { + [key: string]: string | boolean | undefined; +} diff --git a/tools/winscope-ng/src/viewers/common/tree_transformer.spec.ts b/tools/winscope-ng/src/viewers/common/tree_transformer.spec.ts index a25cf5144..876eb5837 100644 --- a/tools/winscope-ng/src/viewers/common/tree_transformer.spec.ts +++ b/tools/winscope-ng/src/viewers/common/tree_transformer.spec.ts @@ -109,7 +109,7 @@ describe("TreeTransformer", () => { const filter = TreeUtils.makeNodeFilter(""); const transformer = new TreeTransformer(selectedTree, filter) - .showOnlyProtoDump() + .setOnlyProtoDump(true) .setProperties(entry); const transformedTree = transformer.transform(); @@ -151,7 +151,7 @@ describe("TreeTransformer", () => { const filter = TreeUtils.makeNodeFilter(""); const transformer = new TreeTransformer(selectedTree, filter) .setIsShowDiff(true) - .showOnlyProtoDump() + .setOnlyProtoDump(true) .setProperties(entry) .setDiffProperties(null); diff --git a/tools/winscope-ng/src/viewers/common/tree_transformer.ts b/tools/winscope-ng/src/viewers/common/tree_transformer.ts index c382de086..d47fc7d4e 100644 --- a/tools/winscope-ng/src/viewers/common/tree_transformer.ts +++ b/tools/winscope-ng/src/viewers/common/tree_transformer.ts @@ -56,8 +56,8 @@ export class TreeTransformer { this.setTransformerOptions({}); } - public showOnlyProtoDump(): TreeTransformer { - this.onlyProtoDump = true; + public setOnlyProtoDump(onlyProto: boolean): TreeTransformer { + this.onlyProtoDump = onlyProto; return this; } @@ -79,7 +79,7 @@ export class TreeTransformer { return this; } - public setProperties(currentEntry: TraceTreeNode): TreeTransformer { + public setProperties(currentEntry: TraceTreeNode | null): TreeTransformer { const currFlickerItem = this.getOriginalFlickerItem(currentEntry, this.stableId); const target = currFlickerItem ? currFlickerItem.obj ?? currFlickerItem : null; ObjectFormatter.displayDefaults = this.isShowDefaults; @@ -96,7 +96,7 @@ export class TreeTransformer { return this; } - public getOriginalFlickerItem(entry: TraceTreeNode, stableId: string): TraceTreeNode | null { + public getOriginalFlickerItem(entry: TraceTreeNode | null, stableId: string): TraceTreeNode | null { return this.findFlickerItem(entry, stableId); } diff --git a/tools/winscope-ng/src/viewers/common/viewer_events.ts b/tools/winscope-ng/src/viewers/common/viewer_events.ts index 68040e29d..d7265da8c 100644 --- a/tools/winscope-ng/src/viewers/common/viewer_events.ts +++ b/tools/winscope-ng/src/viewers/common/viewer_events.ts @@ -20,5 +20,6 @@ export const ViewerEvents = { HierarchyFilterChange: "HierarchyFilterChange", SelectedTreeChange: "SelectedTreeChange", PropertiesUserOptionsChange: "PropertiesUserOptionsChange", - PropertiesFilterChange: "PropertiesFilterChange" + PropertiesFilterChange: "PropertiesFilterChange", + AdditionalPropertySelected: "AdditionalPropertySelected" }; diff --git a/tools/winscope-ng/src/viewers/common/viewer_input_method.ts b/tools/winscope-ng/src/viewers/common/viewer_input_method.ts index 7e4ebcc69..561eb6253 100644 --- a/tools/winscope-ng/src/viewers/common/viewer_input_method.ts +++ b/tools/winscope-ng/src/viewers/common/viewer_input_method.ts @@ -16,26 +16,14 @@ import {TraceType} from "common/trace/trace_type"; import {Viewer} from "viewers/viewer"; import {ViewerEvents} from "viewers/common/viewer_events"; -import { ImePresenter } from "viewers/common/ime_presenter"; +import { PresenterInputMethod } from "viewers/common/presenter_input_method"; import { ImeUiData } from "viewers/common/ime_ui_data"; -class ViewerInputMethod implements Viewer { +abstract class ViewerInputMethod implements Viewer { constructor() { this.view = document.createElement("viewer-input-method"); - this.presenter = new ImePresenter((uiData: ImeUiData) => { - // Angular does not deep watch @Input properties. Clearing inputData to null before repopulating - // automatically ensures that the UI will change via the Angular change detection cycle. Without - // resetting, Angular does not auto-detect that inputData has changed. - (this.view as any).inputData = null; - (this.view as any).inputData = uiData; - }, this.getDependencies()); - this.view.addEventListener(ViewerEvents.HierarchyPinnedChange, (event) => this.presenter.updatePinnedItems(((event as CustomEvent).detail.pinnedItem))); - this.view.addEventListener(ViewerEvents.HighlightedChange, (event) => this.presenter.updateHighlightedItems(`${(event as CustomEvent).detail.id}`)); - this.view.addEventListener(ViewerEvents.HierarchyUserOptionsChange, (event) => this.presenter.updateHierarchyTree((event as CustomEvent).detail.userOptions)); - this.view.addEventListener(ViewerEvents.HierarchyFilterChange, (event) => this.presenter.filterHierarchyTree((event as CustomEvent).detail.filterString)); - this.view.addEventListener(ViewerEvents.PropertiesUserOptionsChange, (event) => this.presenter.updatePropertiesTree((event as CustomEvent).detail.userOptions)); - this.view.addEventListener(ViewerEvents.PropertiesFilterChange, (event) => this.presenter.filterPropertiesTree((event as CustomEvent).detail.filterString)); - this.view.addEventListener(ViewerEvents.SelectedTreeChange, (event) => this.presenter.newPropertiesTree((event as CustomEvent).detail.selectedItem)); + this.presenter = this.initialisePresenter(); + this.addViewerEventListeners(); } public notifyCurrentTraceEntries(entries: Map): void { @@ -46,17 +34,32 @@ class ViewerInputMethod implements Viewer { return this.view; } - public getTitle(): string { - return ""; + + protected imeUiCallback = (uiData: ImeUiData) => { + // Angular does not deep watch @Input properties. Clearing inputData to null before repopulating + // automatically ensures that the UI will change via the Angular change detection cycle. Without + // resetting, Angular does not auto-detect that inputData has changed. + (this.view as any).inputData = null; + (this.view as any).inputData = uiData; + }; + + protected addViewerEventListeners() { + this.view.addEventListener(ViewerEvents.HierarchyPinnedChange, (event) => this.presenter.updatePinnedItems(((event as CustomEvent).detail.pinnedItem))); + this.view.addEventListener(ViewerEvents.HighlightedChange, (event) => this.presenter.updateHighlightedItems(`${(event as CustomEvent).detail.id}`)); + this.view.addEventListener(ViewerEvents.HierarchyUserOptionsChange, (event) => this.presenter.updateHierarchyTree((event as CustomEvent).detail.userOptions)); + this.view.addEventListener(ViewerEvents.HierarchyFilterChange, (event) => this.presenter.filterHierarchyTree((event as CustomEvent).detail.filterString)); + this.view.addEventListener(ViewerEvents.PropertiesUserOptionsChange, (event) => this.presenter.updatePropertiesTree((event as CustomEvent).detail.userOptions)); + this.view.addEventListener(ViewerEvents.PropertiesFilterChange, (event) => this.presenter.filterPropertiesTree((event as CustomEvent).detail.filterString)); + this.view.addEventListener(ViewerEvents.SelectedTreeChange, (event) => this.presenter.newPropertiesTree((event as CustomEvent).detail.selectedItem)); + this.view.addEventListener(ViewerEvents.AdditionalPropertySelected, (event) => this.presenter.newAdditionalPropertiesTree((event as CustomEvent).detail.selectedItem)); } - public getDependencies(): TraceType[] { - return ViewerInputMethod.DEPENDENCIES; - } + abstract getDependencies(): TraceType[]; + abstract getTitle(): string; + protected abstract initialisePresenter(): PresenterInputMethod; - public static readonly DEPENDENCIES: TraceType[] = []; - private view: HTMLElement; - private presenter: ImePresenter; + protected view: HTMLElement; + protected presenter: PresenterInputMethod; } export {ViewerInputMethod}; diff --git a/tools/winscope-ng/src/viewers/components/coordinates_table.component.spec.ts b/tools/winscope-ng/src/viewers/components/coordinates_table.component.spec.ts new file mode 100644 index 000000000..10f9c61c3 --- /dev/null +++ b/tools/winscope-ng/src/viewers/components/coordinates_table.component.spec.ts @@ -0,0 +1,42 @@ +/* + * 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 {ComponentFixture, TestBed} from "@angular/core/testing"; +import { CoordinatesTableComponent } from "./coordinates_table.component"; + +describe("CoordinatesTableComponent", () => { + let fixture: ComponentFixture; + let component: CoordinatesTableComponent; + let htmlElement: HTMLElement; + + beforeAll(async () => { + await TestBed.configureTestingModule({ + declarations: [ + CoordinatesTableComponent + ], + schemas: [] + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CoordinatesTableComponent); + component = fixture.componentInstance; + htmlElement = fixture.nativeElement; + }); + + it("can be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/tools/winscope-ng/src/viewers/components/coordinates_table.component.ts b/tools/winscope-ng/src/viewers/components/coordinates_table.component.ts new file mode 100644 index 000000000..c9274f065 --- /dev/null +++ b/tools/winscope-ng/src/viewers/components/coordinates_table.component.ts @@ -0,0 +1,71 @@ +/* + * 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 { Component, Input } from "@angular/core"; + +@Component({ + selector: "coordinates-table", + template: ` + null +
+ + + + + + + + + + + + + +
LeftTopRightBottom
{{ coordinates.left }}{{ coordinates.top }}{{ coordinates.right }}{{ coordinates.bottom }}
+
+ `, + styles: [ + ` + .coord-null-value { + color: rgba(0, 0, 0, 0.75); + } + + .coord-table-wrapper { + margin-left: 10px; + display: inline-flex; + padding: 3px 0px; + } + + .coord-table-wrapper td, .coord-table-wrapper th { + height: auto; + border: 1px solid ar(--default-border); + } + + .coord-table-wrapper .header-row td { + color: gray; + font-weight: 600; + } + ` + ], +}) + +export class CoordinatesTableComponent { + @Input() coordinates!: any; + + hasCoordinates() { + return this.coordinates.left || this.coordinates.top || + this.coordinates.right || this.coordinates.bottom; + } +} diff --git a/tools/winscope-ng/src/viewers/components/hierarchy.component.ts b/tools/winscope-ng/src/viewers/components/hierarchy.component.ts index f4485487c..1090a2a6d 100644 --- a/tools/winscope-ng/src/viewers/components/hierarchy.component.ts +++ b/tools/winscope-ng/src/viewers/components/hierarchy.component.ts @@ -20,6 +20,7 @@ import { UiTreeUtils, HierarchyTreeNode, UiTreeNode } from "viewers/common/ui_tr import { nodeStyles } from "viewers/components/styles/node.styles"; import { ViewerEvents } from "viewers/common/viewer_events"; import { TraceType } from "common/trace/trace_type"; +import { TableProperties } from "viewers/common/table_properties"; @Component({ selector: "hierarchy-view", @@ -45,6 +46,11 @@ import { TraceType } from "common/trace/trace_type"; (ngModelChange)="updateTree()" >{{userOptions[option].name}} +
= []; @Input() highlightedItems: Array = []; @Input() pinnedItems: Array = []; @@ -167,8 +181,9 @@ export class HierarchyComponent { public maxHierarchyHeight() { const headerHeight = this.elementRef.nativeElement.querySelector(".view-header").clientHeight; + const max = this.tableProperties ? 400 : 800; return { - height: `${800 - headerHeight}px` + height: `${max - headerHeight}px` }; } diff --git a/tools/winscope-ng/src/viewers/components/ime_additional_properties.component.spec.ts b/tools/winscope-ng/src/viewers/components/ime_additional_properties.component.spec.ts new file mode 100644 index 000000000..8ce2e2a52 --- /dev/null +++ b/tools/winscope-ng/src/viewers/components/ime_additional_properties.component.spec.ts @@ -0,0 +1,46 @@ +/* + * 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 {ComponentFixture, TestBed} from "@angular/core/testing"; +import { ImeAdditionalPropertiesComponent } from "./ime_additional_properties.component"; +import { MatCardModule } from "@angular/material/card"; + +describe("ImeAdditionalPropertiesComponent", () => { + let fixture: ComponentFixture; + let component: ImeAdditionalPropertiesComponent; + let htmlElement: HTMLElement; + + beforeAll(async () => { + await TestBed.configureTestingModule({ + imports: [ + MatCardModule, + ], + declarations: [ + ImeAdditionalPropertiesComponent + ], + schemas: [] + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ImeAdditionalPropertiesComponent); + component = fixture.componentInstance; + htmlElement = fixture.nativeElement; + }); + + it("can be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/tools/winscope-ng/src/viewers/components/ime_additional_properties.component.ts b/tools/winscope-ng/src/viewers/components/ime_additional_properties.component.ts new file mode 100644 index 000000000..1e3ec34d6 --- /dev/null +++ b/tools/winscope-ng/src/viewers/components/ime_additional_properties.component.ts @@ -0,0 +1,513 @@ +/* + * 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 { Component, ElementRef, Inject, Input } from "@angular/core"; +import { ImeAdditionalProperties } from "viewers/common/ime_additional_properties"; +import { UiTreeUtils } from "viewers/common/ui_tree_utils"; +import { ViewerEvents } from "viewers/common/viewer_events"; + +@Component({ + selector: "ime-additional-properties", + template: ` + +
+ WM & SF Properties +
+
+ +
+ There is no corresponding WM / SF additionalProperties for this IME entry – + no WM / SF entry is recorded before this IME entry in time. + View later frames for WM & SF properties. +
+ +
+
+ + WMState +
+ {{ + additionalProperties.wm.name }} + There is no corresponding WMState entry. +
+
+
+ +
+
+ Source Frame: + +
+ Source Visible: + {{ + wmInsetsSourceProviderSourceVisibleOrNull() }} +
+ Source Visible Frame: + +
+ Position: + {{ wmInsetsSourceProviderPositionOrNull() }} +
+ IsLeashReadyForDispatching: + {{ + wmInsetsSourceProviderIsLeashReadyOrNull() }} +
+ Controllable: + {{ + wmInsetsSourceProviderControllableOrNull() }} +
+
+
+
+ +
+ Title: + {{ + wmImeControlTargetTitleOrNull() }} +
+
+
+ +
+ Title: + {{ + wmImeInputTargetTitleOrNull() }} +
+
+
+ +
+ Title: + {{ + wmImeLayeringTargetTitleOrNull() }} +
+
+
+ +
+ +
+ + WMState +
+ {{ + additionalProperties.wm.name }} + There is no corresponding WMState entry. +
+
+
+ SFLayer +
+ {{ + additionalProperties.sf.name }} + There is no corresponding SFLayer entry. +
+
+
+ Focus +
+ Focused App: + {{ additionalProperties.wm.focusedApp }} +
+ Focused Activity: + {{ additionalProperties.wm.focusedActivity }} +
+ Focused Window: + {{ additionalProperties.wm.focusedWindow }} +
+ Focused Window Color: + {{ + additionalProperties.sf.focusedWindow.color + }} +
+ Input Control Target Frame: + +
+
+
+
+ Visibility +
+ InputMethod Window: + {{ + additionalProperties.wm.isInputMethodWindowVisible + }} +
+ InputMethod Surface: + {{ + additionalProperties.sf.inputMethodSurface.isInputMethodSurfaceVisible }} +
+
+
+
+ +
+ ZOrderRelativeOfId: + {{ + additionalProperties.sf.imeContainer.zOrderRelativeOfId + }} +
+ Z: + {{ additionalProperties.sf.imeContainer.z }} +
+
+
+
+ +
+ ScreenBounds: + +
+ Rect: + +
+
+
+
+
+ `, + styles: [ + ` + .view-header { + width: 100%; + height: 2.5rem; + border-bottom: 1px solid var(--default-border); + } + + .title-filter { + position: relative; + display: flex; + align-items: center; + width: 100%; + margin-bottom: 12px; + } + + .additional-properties-title { + font-weight: medium; + font-size: 16px; + } + + .additional-properties-content { + display: flex; + flex-direction: column; + height: 375px; + overflow-y: auto; + overflow-x: hidden; + } + + .container { + overflow: auto; + } + + .group { + padding: 0.5rem; + border-bottom: thin solid rgba(0, 0, 0, 0.12); + flex-direction: row; + display: flex; + } + + .group .key { + font-weight: bold; + } + + .group .value { + color: rgba(0, 0, 0, 0.75); + word-break: break-all !important; + } + + .group-header { + justify-content: center; + text-align: left; + padding: 0px 5px; + width: 95px; + display: inline-block; + font-size: bigger; + color: grey; + word-break: break-word; + } + + .left-column { + width: 320px; + max-width: 100%; + display: inline-block; + vertical-align: top; + overflow: auto; + padding-right: 20px; + } + + .right-column { + width: 320px; + max-width: 100%; + display: inline-block; + vertical-align: top; + overflow: auto; + } + + .full-width { + width: 100%; + display: inline-block; + vertical-align: top; + overflow: auto; + } + + .column-header { + font-weight: medium; + font-size: smaller; + } + + .element-summary { + padding-top: 1rem; + } + + .element-summary .key { + font-weight: bold; + } + + .element-summary .value { + color: rgba(0, 0, 0, 0.75); + } + + .tree-view { + overflow: auto; + } + + .text-button { + border: none; + cursor: pointer; + font-size: 14px; + font-family: roboto; + color: blue; + text-decoration: underline; + text-decoration-color: blue; + background-color: inherit; + } + + .text-button:focus { + color: purple; + } + + .text-button.selected { + color: purple; + } + + + ` + ], +}) + +export class ImeAdditionalPropertiesComponent { + @Input() additionalProperties!: ImeAdditionalProperties; + @Input() isImeManagerService?: boolean; + @Input() highlightedItems: Array = []; + + constructor( + @Inject(ElementRef) private elementRef: ElementRef, + ) {} + + public isHighlighted(item: any) { + return UiTreeUtils.isHighlighted(item, this.highlightedItems); + } + + public formatProto(item: any) { + if (item?.prettyPrint) { + return item.prettyPrint(); + } + } + + public wmProtoOrNull() { + return this.additionalProperties.wm?.proto; + } + + public wmInsetsSourceProviderOrNull() { + return this.additionalProperties.wm?.protoImeInsetsSourceProvider ? + Object.assign({ "name": "Ime Insets Source Provider" }, + this.additionalProperties.wm.protoImeInsetsSourceProvider) : + null; + } + + public wmControlTargetFrameOrNull() { + return this.additionalProperties.wm?.protoImeInsetsSourceProvider + ?.insetsSourceProvider?.controlTarget?.windowFrames?.frame || "null"; + } + + public wmInsetsSourceProviderPositionOrNull() { + return this.additionalProperties.wm?.protoImeInsetsSourceProvider + ?.insetsSourceProvider?.control?.position || "null"; + } + + public wmInsetsSourceProviderIsLeashReadyOrNull() { + return this.additionalProperties.wm?.protoImeInsetsSourceProvider + ?.insetsSourceProvider?.isLeashReadyForDispatching || "null"; + } + + public wmInsetsSourceProviderControllableOrNull() { + return this.additionalProperties.wm?.protoImeInsetsSourceProvider + ?.insetsSourceProvider?.controllable || "null"; + } + + public wmInsetsSourceProviderSourceFrameOrNull() { + return this.additionalProperties.wm?.protoImeInsetsSourceProvider + ?.insetsSourceProvider?.source?.frame || "null"; + } + + public wmInsetsSourceProviderSourceVisibleOrNull() { + return this.additionalProperties.wm?.protoImeInsetsSourceProvider + ?.insetsSourceProvider?.source?.visible || "null"; + } + + public wmInsetsSourceProviderSourceVisibleFrameOrNull() { + return this.additionalProperties.wm?.protoImeInsetsSourceProvider + ?.insetsSourceProvider?.source?.visibleFrame || "null"; + } + + public wmImeControlTargetOrNull() { + return this.additionalProperties?.wm?.protoImeControlTarget ? + Object.assign({ "name": "IME Control Target" }, + this.additionalProperties.wm.protoImeControlTarget) : + null; + } + + public wmImeControlTargetTitleOrNull() { + return this.additionalProperties?.wm?.protoImeControlTarget?.windowContainer + ?.identifier?.title || "null"; + } + + public wmImeInputTargetOrNull() { + return this.additionalProperties?.wm?.protoImeInputTarget ? + Object.assign({ "name": "IME Input Target" }, + this.additionalProperties.wm.protoImeInputTarget) : + null; + } + + public wmImeInputTargetTitleOrNull() { + return this.additionalProperties?.wm?.protoImeInputTarget?.windowContainer + ?.identifier?.title || "null"; + } + public wmImeLayeringTargetOrNull() { + return this.additionalProperties?.wm?.protoImeLayeringTarget ? + Object.assign({ "name": "IME Layering Target" }, + this.additionalProperties.wm.protoImeLayeringTarget) : + null; + } + + public wmImeLayeringTargetTitleOrNull() { + return this.additionalProperties?.wm?.protoImeLayeringTarget?.windowContainer + ?.identifier?.title || "null"; + } + + public sfImeContainerScreenBoundsOrNull() { + return this.additionalProperties.sf?.inputMethodSurface.screenBounds || "null"; + } + + public sfImeContainerRectOrNull() { + return this.additionalProperties.sf?.inputMethodSurface.rect || "null"; + } + + public isAllPropertiesNull() { + if (this.isImeManagerService) { + return !this.additionalProperties.wm; + } else { + return !(this.additionalProperties.wm || + this.additionalProperties.sf); + } + } + + public onClickShowInPropertiesPanel(item: any, name?: string) { + if (item.id) { + this.updateHighlightedItems(item.id); + } else { + this.updateAdditionalPropertySelected(item, name); + } + } + + private updateHighlightedItems(newId: string) { + const event: CustomEvent = new CustomEvent( + ViewerEvents.HighlightedChange, + { + bubbles: true, + detail: { id: newId } + }); + this.elementRef.nativeElement.dispatchEvent(event); + } + + private updateAdditionalPropertySelected(item: any, name?: string) { + const itemWrapper = { + name: name, + proto: item, + }; + const event: CustomEvent = new CustomEvent( + ViewerEvents.AdditionalPropertySelected, + { + bubbles: true, + detail: { selectedItem: itemWrapper } + }); + this.elementRef.nativeElement.dispatchEvent(event); + } +} diff --git a/tools/winscope-ng/src/viewers/components/properties_table.component.spec.ts b/tools/winscope-ng/src/viewers/components/properties_table.component.spec.ts new file mode 100644 index 000000000..21dbb10ba --- /dev/null +++ b/tools/winscope-ng/src/viewers/components/properties_table.component.spec.ts @@ -0,0 +1,42 @@ +/* + * 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 {ComponentFixture, TestBed} from "@angular/core/testing"; +import { PropertiesTableComponent } from "./properties_table.component"; + +describe("PropertiesTableComponent", () => { + let fixture: ComponentFixture; + let component: PropertiesTableComponent; + let htmlElement: HTMLElement; + + beforeAll(async () => { + await TestBed.configureTestingModule({ + declarations: [ + PropertiesTableComponent + ], + schemas: [] + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PropertiesTableComponent); + component = fixture.componentInstance; + htmlElement = fixture.nativeElement; + }); + + it("can be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/tools/winscope-ng/src/viewers/components/properties_table.component.ts b/tools/winscope-ng/src/viewers/components/properties_table.component.ts new file mode 100644 index 000000000..7aa66ef87 --- /dev/null +++ b/tools/winscope-ng/src/viewers/components/properties_table.component.ts @@ -0,0 +1,75 @@ +/* + * 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 { Component, Input } from "@angular/core"; +import { TableProperties } from "viewers/common/table_properties"; + +@Component({ + selector: "properties-table", + template: ` +
+ + + + + +
+ {{ entry[0] }} + + {{ entry[1] != undefined ? entry[1] : 'undefined' }} +
+
+ `, + styles: [ + ` + .properties-table-wrapper { + border-bottom: 1px solid var(--default-border); + } + + .properties-table-wrapper .table-cell-name { + background-color: rgba(158, 192, 200, 0.281); + border: 1px solid var(--default-border); + height: 20px; + padding: 0; + width: 20%; + } + + .properties-table-wrapper .table-cell-value { + overflow-wrap: anywhere; + border: 1px solid var(--default-border); + height: 20px; + padding: 0; + width: 80%; + } + + .properties-table-wrapper table { + height: auto; + border-collapse: collapse; + width: 100%; + } + + .properties-table-wrapper span { + padding: 5px; + } + ` + ], +}) + +export class PropertiesTableComponent { + objectEntries = Object.entries; + + @Input() properties!: TableProperties; + +} diff --git a/tools/winscope-ng/src/viewers/components/viewer_input_method.component.ts b/tools/winscope-ng/src/viewers/components/viewer_input_method.component.ts index 647a24647..3c75648cd 100644 --- a/tools/winscope-ng/src/viewers/components/viewer_input_method.component.ts +++ b/tools/winscope-ng/src/viewers/components/viewer_input_method.component.ts @@ -26,16 +26,24 @@ import { ImeUiData } from "viewers/common/ime_ui_data"; selector: "viewer-input-method", template: `
- - - +
+ + + + + + +
{ + async function getEntry() { + return await UnitTestUtils.getInputMethodClientsEntry(); + } + + describe("PresenterInputMethod tests:", () => { + const selectedTree = new HierarchyTreeBuilder().setName("8m23s29ms - InputMethodManager#showSoftInput") + .setFilteredView(true).setKind("InputMethodClient entry").setId("entry").setStableId("entry") + .setChildren([ + new HierarchyTreeBuilder().setKind("Client").setId("client").setFilteredView(true) + .setStableId("client").build() + ]).build(); + + executePresenterInputMethodTests( + getEntry, + selectedTree, + "elapsed", + [3, 1], + PresenterInputMethodClients, + TraceType.INPUT_METHOD_CLIENTS, + ); + }); +}); diff --git a/tools/winscope-ng/src/viewers/viewer_input_method_clients/presenter_input_method_clients.ts b/tools/winscope-ng/src/viewers/viewer_input_method_clients/presenter_input_method_clients.ts new file mode 100644 index 000000000..219c5863a --- /dev/null +++ b/tools/winscope-ng/src/viewers/viewer_input_method_clients/presenter_input_method_clients.ts @@ -0,0 +1,33 @@ + +/* + * 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 { PresenterInputMethod } from "viewers/common/presenter_input_method"; + +export class PresenterInputMethodClients extends PresenterInputMethod { + protected updateHierarchyTableProperties() { + return {...new ImClientsTableProperties( + this.entry?.obj?.client?.inputMethodManager?.curId, + this.entry?.obj?.client?.editorInfo?.packageName, + )}; + } +} + +class ImClientsTableProperties { + constructor( + public inputMethodId: string | undefined, + public packageName: string | undefined, + ) {} +} diff --git a/tools/winscope-ng/src/viewers/viewer_input_method_clients/viewer_input_method_clients.ts b/tools/winscope-ng/src/viewers/viewer_input_method_clients/viewer_input_method_clients.ts index c38c63930..f733479f4 100644 --- a/tools/winscope-ng/src/viewers/viewer_input_method_clients/viewer_input_method_clients.ts +++ b/tools/winscope-ng/src/viewers/viewer_input_method_clients/viewer_input_method_clients.ts @@ -14,18 +14,23 @@ * limitations under the License. */ import {TraceType} from "common/trace/trace_type"; +import { PresenterInputMethodClients } from "./presenter_input_method_clients"; import { ViewerInputMethod } from "viewers/common/viewer_input_method"; class ViewerInputMethodClients extends ViewerInputMethod { - public override getTitle(): string { + public getTitle(): string { return "Input Method Clients"; } - public override getDependencies(): TraceType[] { + public getDependencies(): TraceType[] { return ViewerInputMethodClients.DEPENDENCIES; } - public static override readonly DEPENDENCIES: TraceType[] = [TraceType.INPUT_METHOD_CLIENTS]; + protected initialisePresenter() { + return new PresenterInputMethodClients(this.imeUiCallback, this.getDependencies()); + } + + public static readonly DEPENDENCIES: TraceType[] = [TraceType.INPUT_METHOD_CLIENTS]; } export {ViewerInputMethodClients}; diff --git a/tools/winscope-ng/src/viewers/viewer_input_method_manager_service/presenter_input_method_manager_service.spec.ts b/tools/winscope-ng/src/viewers/viewer_input_method_manager_service/presenter_input_method_manager_service.spec.ts new file mode 100644 index 000000000..4c52b9166 --- /dev/null +++ b/tools/winscope-ng/src/viewers/viewer_input_method_manager_service/presenter_input_method_manager_service.spec.ts @@ -0,0 +1,41 @@ +/* + * 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 { TraceType } from "common/trace/trace_type"; +import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder"; +import { PresenterInputMethodManagerService } from "./presenter_input_method_manager_service"; +import { executePresenterInputMethodTests } from "viewers/common/presenter_input_method_test_utils"; +import { UnitTestUtils } from "test/unit/utils"; + +describe("PresenterInputMethodManagerService", () => { + async function getEntry() { + return await UnitTestUtils.getInputMethodManagerServiceEntry(); + } + + describe("PresenterInputMethod tests:", () => { + const selectedTree = new HierarchyTreeBuilder() + .setFilteredView(true).setKind("InputMethodManagerService").setId("managerservice") + .setStableId("managerservice").build(); + + executePresenterInputMethodTests( + getEntry, + selectedTree, + "cur", + [13, 8], + PresenterInputMethodManagerService, + TraceType.INPUT_METHOD_MANAGER_SERVICE, + ); + }); +}); diff --git a/tools/winscope-ng/src/viewers/viewer_input_method_manager_service/presenter_input_method_manager_service.ts b/tools/winscope-ng/src/viewers/viewer_input_method_manager_service/presenter_input_method_manager_service.ts new file mode 100644 index 000000000..d37826456 --- /dev/null +++ b/tools/winscope-ng/src/viewers/viewer_input_method_manager_service/presenter_input_method_manager_service.ts @@ -0,0 +1,47 @@ + +/* + * 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 { PresenterInputMethod } from "viewers/common/presenter_input_method"; +import { ImeAdditionalProperties } from "viewers/common/ime_additional_properties"; +import { TraceTreeNode } from "common/trace/trace_tree_node"; +import { ImeUtils } from "viewers/common/ime_utils"; + +export class PresenterInputMethodManagerService extends PresenterInputMethod { + protected updateHierarchyTableProperties() { + return {...new ImManagerServiceTableProperties( + this.entry?.obj?.inputMethodManagerService?.curMethodId, + this.entry?.obj?.inputMethodManagerService?.curFocusedWindowName, + this.entry?.obj?.inputMethodManagerService?.lastImeTargetWindowName, + this.entry?.obj?.inputMethodManagerService?.inputShown ?? false, + )}; + } + + protected override getAdditionalProperties(wmEntry: TraceTreeNode | undefined, sfEntry: TraceTreeNode | undefined) { + return new ImeAdditionalProperties( + wmEntry ? ImeUtils.processWindowManagerTraceEntry(wmEntry) : undefined, + undefined, + ); + } +} + +class ImManagerServiceTableProperties { + constructor( + public inputMethodId: string | undefined, + public curFocusedWindow: string | undefined, + public lastImeTargetWindow: string | undefined, + public inputShown: boolean, + ) {} +} diff --git a/tools/winscope-ng/src/viewers/viewer_input_method_manager_service/viewer_input_method_manager_service.ts b/tools/winscope-ng/src/viewers/viewer_input_method_manager_service/viewer_input_method_manager_service.ts index b42001b79..79bbab444 100644 --- a/tools/winscope-ng/src/viewers/viewer_input_method_manager_service/viewer_input_method_manager_service.ts +++ b/tools/winscope-ng/src/viewers/viewer_input_method_manager_service/viewer_input_method_manager_service.ts @@ -14,18 +14,23 @@ * limitations under the License. */ import {TraceType} from "common/trace/trace_type"; +import { PresenterInputMethodManagerService } from "./presenter_input_method_manager_service"; import { ViewerInputMethod } from "viewers/common/viewer_input_method"; class ViewerInputMethodManagerService extends ViewerInputMethod { - public override getTitle(): string { + public getTitle(): string { return "Input Method Manager Service"; } - public override getDependencies(): TraceType[] { + public getDependencies(): TraceType[] { return ViewerInputMethodManagerService.DEPENDENCIES; } - public static override readonly DEPENDENCIES: TraceType[] = [TraceType.INPUT_METHOD_MANAGER_SERVICE]; + protected initialisePresenter() { + return new PresenterInputMethodManagerService(this.imeUiCallback, this.getDependencies()); + } + + public static readonly DEPENDENCIES: TraceType[] = [TraceType.INPUT_METHOD_MANAGER_SERVICE]; } export {ViewerInputMethodManagerService}; diff --git a/tools/winscope-ng/src/viewers/viewer_input_method_service/presenter_input_method_service.spec.ts b/tools/winscope-ng/src/viewers/viewer_input_method_service/presenter_input_method_service.spec.ts new file mode 100644 index 000000000..0a60d5fa1 --- /dev/null +++ b/tools/winscope-ng/src/viewers/viewer_input_method_service/presenter_input_method_service.spec.ts @@ -0,0 +1,40 @@ +/* + * 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 { TraceType } from "common/trace/trace_type"; +import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder"; +import { PresenterInputMethodService } from "./presenter_input_method_service"; +import { executePresenterInputMethodTests } from "viewers/common/presenter_input_method_test_utils"; +import { UnitTestUtils } from "test/unit/utils"; + +describe("PresenterInputMethodService", () => { + async function getEntry() { + return await UnitTestUtils.getInputMethodServiceEntry(); + } + + describe("PresenterInputMethod tests:", () => { + const selectedTree = new HierarchyTreeBuilder().setKind("InputMethodService") + .setId("service").setFilteredView(true).setStableId("service").build(); + + executePresenterInputMethodTests( + getEntry, + selectedTree, + "visib", + [13, 3], + PresenterInputMethodService, + TraceType.INPUT_METHOD_SERVICE, + ); + }); +}); diff --git a/tools/winscope-ng/src/viewers/viewer_input_method_service/presenter_input_method_service.ts b/tools/winscope-ng/src/viewers/viewer_input_method_service/presenter_input_method_service.ts new file mode 100644 index 000000000..85ffed0bc --- /dev/null +++ b/tools/winscope-ng/src/viewers/viewer_input_method_service/presenter_input_method_service.ts @@ -0,0 +1,35 @@ + +/* + * 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 { PresenterInputMethod } from "viewers/common/presenter_input_method"; + +export class PresenterInputMethodService extends PresenterInputMethod { + protected updateHierarchyTableProperties() { + return {...new ImServiceTableProperties( + this.entry?.obj?.inputMethodService?.windowVisible ?? false, + this.entry?.obj?.inputMethodService?.decorViewVisible ?? false, + this.entry?.obj?.inputMethodService?.inputEditorInfo?.packageName, + )}; + } +} + +class ImServiceTableProperties { + constructor( + public windowVisible: boolean, + public decorViewVisible: boolean, + public packageName: string | undefined + ) {} +} diff --git a/tools/winscope-ng/src/viewers/viewer_input_method_service/viewer_input_method_service.ts b/tools/winscope-ng/src/viewers/viewer_input_method_service/viewer_input_method_service.ts index 221b5be3e..3d5c1ac6a 100644 --- a/tools/winscope-ng/src/viewers/viewer_input_method_service/viewer_input_method_service.ts +++ b/tools/winscope-ng/src/viewers/viewer_input_method_service/viewer_input_method_service.ts @@ -14,18 +14,23 @@ * limitations under the License. */ import {TraceType} from "common/trace/trace_type"; +import { PresenterInputMethodService } from "./presenter_input_method_service"; import { ViewerInputMethod } from "viewers/common/viewer_input_method"; class ViewerInputMethodService extends ViewerInputMethod { - public override getTitle(): string { + public getTitle(): string { return "Input Method Service"; } - public override getDependencies(): TraceType[] { + public getDependencies(): TraceType[] { return ViewerInputMethodService.DEPENDENCIES; } - public static override readonly DEPENDENCIES: TraceType[] = [TraceType.INPUT_METHOD_SERVICE]; + protected initialisePresenter() { + return new PresenterInputMethodService(this.imeUiCallback, this.getDependencies()); + } + + public static readonly DEPENDENCIES: TraceType[] = [TraceType.INPUT_METHOD_SERVICE]; } export {ViewerInputMethodService}; diff --git a/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.ts b/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.ts index e77b1770f..38386b2e9 100644 --- a/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.ts +++ b/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.ts @@ -213,7 +213,7 @@ export class Presenter { private getTreeWithTransformedProperties(selectedTree: HierarchyTreeNode): PropertiesTreeNode { const transformer = new TreeTransformer(selectedTree, this.propertiesFilter) - .showOnlyProtoDump() + .setOnlyProtoDump(true) .setIsShowDefaults(this.propertiesUserOptions["showDefaults"]?.enabled) .setIsShowDiff(this.propertiesUserOptions["showDiff"]?.enabled) .setTransformerOptions({skip: selectedTree.skip}) diff --git a/tools/winscope-ng/src/viewers/viewer_surface_flinger/viewer_surface_flinger.component.ts b/tools/winscope-ng/src/viewers/viewer_surface_flinger/viewer_surface_flinger.component.ts index fca9730bd..0ade7d4e7 100644 --- a/tools/winscope-ng/src/viewers/viewer_surface_flinger/viewer_surface_flinger.component.ts +++ b/tools/winscope-ng/src/viewers/viewer_surface_flinger/viewer_surface_flinger.component.ts @@ -76,10 +76,6 @@ import { PersistentStore } from "common/persistent_store"; vertical-align: middle; } - viewer-surface-flinger { - font-family: Arial, Helvetica, sans-serif; - } - .header-button { background: none; border: none; diff --git a/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.ts b/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.ts index 3a39f1497..a6af00451 100644 --- a/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.ts +++ b/tools/winscope-ng/src/viewers/viewer_window_manager/presenter.ts @@ -215,7 +215,7 @@ export class Presenter { return {}; } const transformer = new TreeTransformer(selectedTree, this.propertiesFilter) - .showOnlyProtoDump() + .setOnlyProtoDump(true) .setIsShowDefaults(this.propertiesUserOptions["showDefaults"]?.enabled) .setIsShowDiff(this.propertiesUserOptions["showDiff"]?.enabled) .setTransformerOptions({skip: selectedTree.skip}) diff --git a/tools/winscope-ng/src/viewers/viewer_window_manager/viewer_window_manager.component.ts b/tools/winscope-ng/src/viewers/viewer_window_manager/viewer_window_manager.component.ts index 941148c4d..3e915dcb8 100644 --- a/tools/winscope-ng/src/viewers/viewer_window_manager/viewer_window_manager.component.ts +++ b/tools/winscope-ng/src/viewers/viewer_window_manager/viewer_window_manager.component.ts @@ -73,10 +73,6 @@ import { PersistentStore } from "common/persistent_store"; vertical-align: middle; } - viewer-window-manager { - font-family: Arial, Helvetica, sans-serif; - } - .header-button { background: none; border: none;